AngularJS: Show if X > Y and add class - angularjs

I am building my first app. It is an ordering system where a customer can add items to the cart. Everything is working well. However, my client would like a way to alert the customer if they try to add a quantity to the cart that is greater than the current stock.
My client doesn't want to show stock levels, unless the customer adds something greater than the stock available.
I have a table with stock items in each row. I'd like to do three things, if the stock level is greater that available stock, I'd like to change:
• Class on the table row
• Add class disabled to the submit
• Show a div that has the available stock in.
To make matters a little more interesting, customers have to order by packs and not individual items.
Basically, I am trying to get the following code to work:
This is the general markup:
<tr ng-repeat="series_detail in productDetail | filter:filter">
<td>{{series_detail.sku}}</td>
<td>{{series_detail.size}}</td>
<td>{{series_detail.price</td>
<td>{{series_detail.pack}}</td>
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
<td><span class="itemtotal">{{series_detail.price * qty | number:2}}</span></td>
<td class="form-inline" style="text-align:right;">
<input type="submit" class="add_to_cart_submit btn btn-danger btn-small" value="Add">
</td>
</tr>
I want to then show this div
<div ng-show="'{{totalitems}}' > '{{series_detail.stock}}'">Yo, no stock dude</div>
I have tried adding a model, 'totalitems' to a row and then using ngShow to pop it up. However, it seems that 'totalitems' is evaluating to nothing. I've experimented with a few other options, but nothing has worked (ngIF etc.).
Regarding the changing of class, I am guessing, that once I get this sorted, I can transfer the expression to ngClass? I have played with this, and again, nothing has worked so far.

Provided this line goes inside the ng-repeat:
<div ng-show="qty * series_detail.pack > series_detail.stock">Yo, no stock dude</div>
For the class indication, lets say on tr, you could use the same expression as:
<tr ng-class="{outOfStock: (qty * series_detail.pack > series_detail.stock)}" ng-repeat="series_detail in productDetail | filter:filter">
outOfStock is class in your CSS.
BTW,
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
does not set totalitems to whatever {{qty * series_detail.pack | number}} evaluates to.
If you really need totalItems in your model a possible option is to have a method on the series_detail instance
objRef.totalItems = function(qty) {
return qty * this.pack;
}
and use it as:
<div ng-show="series_detail.totalItems(qty) > series_detail.stock">Yo, no stock dude</div>
<td>{{series_detail.totalItems(qty) | number}}</td>

I am not to sure to understand everything but something like this should works ?
<div ng-show="isStockAddedGreaterThanAvailable()">{{series_detail.stock}} Yo, no stock dude </div>
And in your controller
$scope.isStockAddedGreaterThanAvailable = function(){
....
}

Related

ng-repeat not coloring elements properly?

I am stumped on why the fields in my data aren't coloring correctly. I used a simple greater than logic to assign an ng-class of either green, or red. I added debug lines to check that inside the function the values are correct, and the bool is correct, but on the main page items are 'randomly' colored incorrectly. Help?
I tried several different things on the values, like parseInt() etc with the same results. As Is, no matter what I put inside the function it displays different colors than expected
<table>
<th><input class="search" type="text" ng-model="searchKey" placeholder="Character" ng-change="setClickedRow(-1)"></th>
<th ng-click="setSort('pval1')">
<div ng-app="KIdash" ng-controller="controller">
Total Matches: {{TotalMatchesFunc()}}
</div>
</th>
<th ng-click="setSort('pval2')">Wins</th>
<th ng-click="setSort('pval3')">Losses</th>
<tbody ng-repeat="ps in PlayerStats | orderBy: sortKey | filter:searchKey">
<tr ng-class="{'main-row-selected': $index == selectedRow,'main-row': $index != selectedRow}" ng-click="setClickedRow($index)">
<td>{{ps.name}}</td>
<td>{{ps.pval1}}</td>
<!-- *** THIS IS THE PART THAT ISNT WORKING CORRECTLY *** -->
<td ng-class="{'green': GreaterWins({{$index}}),'red': !GreaterWins({{$index}})}">{{ps.pval2}}</td>
<td>{{ps.pval3}}</td>
</tr>
<!-- *** COULD THIS SECOND FUNCTION CALL BE POLLUTING MY RESULTS? *** -->
<tr ng-class="{'extra-row-green': GreaterWins({{$index}}),'extra-row-red': !GreaterWins({{$index}})}" ng-show="selectedRow == $index">
<td>Detail: {{ps.detail_p1}}</td>
<td>Detail: {{ps.detail_p2}}</td>
<td>Detail: {{ps.detail_p3}}</td>
<td>Detail: {{ps.detail_p4}}</td>
</tr>
</tbody>
</table>
$scope.GreaterWins = function(z) {
console.log( "bool "
+ Boolean($scope.PlayerStats[z].pval2 > $scope.PlayerStats[z].pval3)
+ " "
+ $scope.PlayerStats[z].pval2 + "vs" + $scope.PlayerStats[z].pval3);
return Boolean($scope.PlayerStats[z].pval2 > $scope.PlayerStats[z].pval3));
};
Two things which i feel is creating issue.
Instead of passing index in function you should pass variable ps as ngRepeat create isolated scope. so some time there is issue.
variable selectedRow should be object as primitive variables has issue in inheritance and two data binding.
try both things your code should work.
I can't really repeat the issue using JSbin, here is the example I made in JSbin.
https://jsbin.com/jadiputoha/edit?html,js,console,output

assigning id to new added object in ngrepeat

i am using Xeditable Angular,
Working fine.
The issue is when i added a new data as a new row to table. and i made a ajax call to server, server saved it, and returned new id, i want to assign this id to the new added model. how i do that.
When i added a new item, it added instantly to model by xeditable, its fine, but its id field is null, i want to change the null to the return value from server. how select the item of last edited by its track by id
<tr ng-cloak ng-repeat="school in results = (content.data | filter: content.search | orderBy:sortType:sortReverse | offset: (content.currentPage-1) * content.pageSize | limitTo: content.pageSize) track by school.id">
<td><input type="checkbox" ng-model="content.deleteList[school.id]" ng-checked="content.head"></td><td>{{school.id}}</td> .......................................
Only part of desplayed
What you can do is update the id when you get a reply form the server :
$scope.addData = function(user) {
yourFactory.addData(user).then(function(result) {
user.id = result.data.id;
});
}
I may be able to help you better if you provide more code

Filter ng-repeat more times

I'm creating an application to manage restaurant orders.
I create the menu from $http so I've this list:
<div class="row vertical" style="background-image: url(/gest/images/etichette/ANTIPASTI.png);border-color: #0CF">
<div class="card piatti col s2" ng-repeat="anti in antis | filter:{tipo:'ANTIPASTI'}">
<div class="card-content"> <span class="card-title truncate red darken-3">{{anti.piatto}}</span> </div>
<div class="card-action"> {{n}}</div>
</div>
</div>
The div with class "row vertical" contain one time starters, then pasta, then beef ecc.
So I use ng-repeat each time, and filter by tipo.
My question is: is there any way to make ng-repeat only one time to show all menu (orderer before by starters, then pasta, beef ecc)?
I have this data (is a restaurant menu):
piatto: name of the the dish
tipo: category of the dish (like pasta, beef, fish, starters ecc)
I would show with only one repeat all the dishes ordered so:
starters, pasta, beef, fish, dessert etc.
And I would create each time a new row
From what I understand you already have all your date on the antis and you just want to filter it by type or do you want to OrderIt by a certain type?
This fiddle for example would order by name, but you can also provide an array with functions to retrieve each type in the way that you like, you can read about it here.
But basically you'd do
anti in antis | orderBy:'+tipo'
or
anti in antis | orderBy: [ function(){}, function(){} ]
EDIT:
As #yarons mentioned you can also chain strings to filter even further. I've updated the Fiddle so now the filter would be anti in antis | orderBy:['+tipo', '+piato']" which indicates that first the tipo would be alphabetically ordered ascending (+ indication) and after that the piato would also be alphabetically ascending.
If you'd want to define a different order than the alphabetical one I think you can use a sort of ENUM for the tipo as in:
var tipoENUM = {};
tipoENUM['ANIPASTI'] = 0;
tipoENUM['PASTA'] = 1;
tipoENUM['PIZZA'] = 2;
tipoENUM['BEEF'] = 3;
tipoENUM['DESERT'] = 4;
So that way you'd avoid using the string for the order, see following fiddle for the example.
EDIT 2:
Ok, so if you receive the data via the HTTP request it's better if you create a order function to help you, check this updated fiddle, like so:
// The enum would be defined as before but:
$scope.orderTipo = function (dish) {
return tipoENUM[dish.tipo];
}
On the HTMl you'll do:
ng-repeat="anti in antis | orderBy:[orderTipo, '+piato']"
Ok your example is perfect but I would repeat each time the "tipo" and then the relative "piato" in a list....something like this:
ANTIPASTI
- bruschetta
- suppli
- fritto
PRIMI
- caqrbonara
- amatriciana
etc.
Is it possible?

How do I do reference data in AngularJS?

Is it possible in AngularJS, while in a nested ng-repeat, to access data from a third table?
Here's an example... let's say I want to create a table which lists actors and actresses in the first row, and then the first column would list movies. In the cells where actor and movie intersect, we might display a rating for how well that actor performed in that film. However, since only a few actors may appear in each film, more often than not those intersecting cells would be blank. If we have roughly 120 actors and 600 films, then we're talking about 72,000 possible intersections, although our dataset may only actually have about 5000 entries.
I'm using three JSON files to do this; actors.json, movies.json, and ratings.json. The first two files contain lists of the actors or movies, and extended data for each; ie: year, genre, director, or age, nationality, etc. The last file; ratings.json, contains simply the ID of the movie, the name of the actor (our data doesn't contain IDs for the actors), and the rating.
Setting up my table, in the first row I ng-repeat through the actors file to display my header row, with the names and information about each actor. I skip the first cell, as it's the top of my header column.
Next, I ng-repeat through my movies data, opening a new row for each, and then within each row, I ng-repeat through my actors data again to create the ratings td's themselves.
All of this is working, but this is where I go off the rails. I cannot figure out an efficient way to grab the ratings data easily. I did figure out HOW to make it work, by basically looping through the entire ratings table, and filtering for a match, but I know that can't be the right way to do it.
Here's some sample code:
<table>
<tr>
<td></td>
<td ng-repeat="movie in movies>
<p>{{movie.name}}</p>
<p>{{movie.year}}</p>
</td>
</tr>
<tr ng-repeat="actor in actors>
<td>{{actor.name}}</td>
<td ng-repeat="movie in movies">
<span ng-repeat="rating in ratings | filter: { id: movie.id } : true | filter: { actor: actor.name } : true">
{{rating.rating}}
</span>
</td>
</tr>
</table>
As you can imagine, this method is really (REALLY) slow.
If this were php or something, I'd just grab the data from an array (ie: $rating[$movie_id][$actor_name]), simple as pie, but for the life of me I can't figure out how to do this with AngularJS, not at all. I just want to reference the proper bit of ratings data directly.
As requested, here's a sample of ratings.json.
[
{
actor: "Brad Pitt",
id: "13",
rating: "3"
},
{
actor: "Jennifer Anniston",
id: "8",
rating: "7"
},
...
]
Thanks,
m.
You would need to pre-process your ratings.json array into a nested hash.
var ratings = {};
for (var i=0; i < ratingsArray.length; i++){
var ratingEntry = ratingsArray[i];
var id = ratingEntry.Id, actor = ratingEntry.actor;
rating[id] = rating[id] || {};
rating[id][actor] = ratingEntry.rating;
}
Then you could just do exactly what you would expect had it been PHP:
<tr ng-repeat="actor in actors>
<td>{{actor.name}}</td>
<td ng-repeat="movie_id in movies">
{{rating[movie_id][actor]}}
</td>
</tr>

Pagination using PageObject Watir Webdriver [duplicate]

Using page-object and watir-webdriver how can I click a link in a table, based on the row text as below:
The table contains 3 rows which have names in the first column, and a corresponding Details link in columns to the right:
DASHBOARD .... Details
EXAMPLE .... Details
and so on.
<div class="basicGridHeader">
<table class="basicGridTable">ALL THE DETAILS:
....soon
</table>
</div>
<div class="basicGridWrapper">
<table class="basicGridTable">
<tbody id="bicFac9" class="ide043">
<tr id="id056">
<td class="bicRowFac10">
<span>
<label class="bicDeco5">
<b>DASHBOARD:</b> ---> Based on this text
</label>
</span>
</td>
<td class="bicRowFac11">
....some element
</td>
<td class="bicRowFac12">
<span>
<a class="bicFacDet5">Details</a> ---> I should able click this link
</span>
</td>
</tr>
</tbody>
</table>
</div>
You could locate a cell that contains the specified text, go to the parent row and then find the details link in that row.
Assuming that there might be other detail links you would want to click, I would define a view_details method that accepts the text of the row you want to locate:
class MyPage
include PageObject
table(:grid){ div_element(:class => 'basicGridWrapper')
.table_element(:class => 'basicGridTable') }
def view_details(label)
grid_element.cell_element(:text => /#{label}/)
.parent
.link_element(:text => 'Details')
.click
end
end
You can then click the link with:
page.view_details('DASHBOARD')
Table elements include the Enumerable module, and I find it very useful in cases like these. http://ruby-doc.org/core-2.0.0/Enumerable.html. You could use the find method to locate and return the row that matches the criteria you are looking for. For example:
class MyPage
include PageObject
table(:grid_table, :class => 'basicGridTable')
def click_link_by_row_text(text_value)
matched_row = locate_row_by_text(text_value)
matched_row.link_element.click
#if you want to make sure you click on the link under the 3rd column you can also do this...
#matched_row[2].link_element.click
end
def locate_row_by_text(text_value)
#find the row that matches the text you are looking for
matched_row = grid_table_element.find { |row| row.text.include? text_value }
fail "Could not locate the row with value #{text_value}" if matched_row.nil?
matched_row
end
end
Here, locate_row_by_text will look for the row that includes the text you are looking for, and will throw an exception if it doesnt find it. Then, once you find the row, you can drill down to the link, and click on it as shown in the click_link_by_row_text method.
Just for posterity, I would like to give an updated answer. It is now possible to traverse through a table using table_element[row_index][column_index].
A little bit more verbose:
row_index could also be the text in a row to be matched - in your case - table_element['DASHBOARD']
Then find the corresponding cell/td element using either the index(zero based) or the header of that column
table_element['DASHBOARD'][2] - Selecting the third element in the
selected row.
Since you do not have a header row (<th> element) you can filter the cell element using the link's class attribute. Something like this
table_element['DASHBOARD'].link_element(:class => 'bicRowFac10').click
So the code would look something like this:
class MyPage
include PageObject
def click_link_by_row_text(text_value)
table_element[text_value].link_element(:class => 'bicRowFac10').click
end
end
Let me know if you need more explanation. Happy to help :)

Resources