My project renders a lot of tables with financial data, and one of the requirements is that positive numbers are green and negative numbers are red (along with a couple of other stylizations). I have classes for doing this ("gain" and "loss"), and I know that I can apply them conditionally with ng-class, but the repetitiveness of doing so makes me feel that perhaps there might be a way similar to a filter where I can just apply the check repeatedly, without having to actually spell it out every time.
I could cheat and use a filter to wrap the output in a span with the class, but that would effectively break filter chaining, so I won't be doing that.
A section of the table might look like:
<tr>
<td ng-repeat="month in report" ng-class="{ loss : month.gross < 0, gain: month.gross > 0 }">{{ month.gross | currency }}</td>
</tr>
<tr>
<td ng-repeat="month in report" ng-class="{ loss : month.net < 0, gain: month.net > 0 }">{{ month.net | currency }}</td>
</tr>
<tr>
<td ng-repeat="month in report" ng-class="{ loss : month.profit < 0, gain: month.profit > 0 }">{{ month.profit | currency }}</td>
</tr>
Is there a way to abstract out the ng-class="{ loss: x < 0, gain: x > 0 }" or am I just stuck repeating it? I have similar cases where I'm checking even more than two cases, but this is definitely the more common situation.
Related
Given a set of columns specified by a user. Which will be contained within displayColumns i.e. ['value1', 'value2', 'value3'] i want to iterate over this set of values to provide me with the correct reference to each value in the model.
I don't know what the syntax is for substituting the column name into an expression so that when angular compiles it, it would look like -> {{device.name.value1.value.value}} ... I've tried [] but that obviously didn't work!
<tbody md-body>
<tr md-row ng-repeat="device in $ctrl.devices track by device.mRID">
<td md-cell ng-click="$ctrl.detailedView($event, device)">{{device.aliasName}}</td>
<td md-cell>{{device.mRID}}</td>
<td md-cell ng-repeat="column in $ctrl.displayColumns">{{device.name.[column].value.value}} {{device.name.[column].unit.symbol}}<td>
</tr>
</tbody>
This is called bracket notation:
{{device.name[column].value.value}} {{device.name[column].unit.sybmol}}
Not this:
{{device.name.[column].value.value}} {{device.name.[column].unit.sybmol}}
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
I want do use two different ng-repeat loops in a table to kind of group different obejcts with each other but don't know really how to do it.
My code right now:
...
<tbody>
<tr ng-repeat="person1 in Array1">
<td>{{ person1.address }}</td>
<td>{{ person1.city}}</td>
<td>{{ person1.email}}</td>
</tr>
<tr ng-repeat="person2 in Array2">
<td>{{partner2.address }}</td>
<td>{{partner2.city}}</td>
<td>{{partner2.email}}</td>
</tr>
</tbody>
...
The result/table i'm aiming for:
person1[1].address | person1[1].city | person1[1].email
---------------------------------------------------------------
person2[1].address | person2[1].city | person2[1].email
---------------------------------------------------------------
person1[2].address | person1[2].city | person1[2].email
---------------------------------------------------------------
person2[2].address | person2[2].city | person2[2].email
---------------------------------------------------------------
That is, i'd like to the ng-repeat to out put person1[1] and person2[1] before putting out person1[2].
Is the solution to add an outer array, containing my two current arrays or are there any better solution?
best regards
Assuming you could ensure that your array had no null values and were the same length, you could use this technique:
Create a new array initialized to the length of the two other arrays and iterate on this to get $index.
Put your ng-repeat on the body ( you can have multiple body elements in a table).
You'd get something like this:
var counterArray = new Array(array1.length);
<tbody ng-repeat="item in counterArray">
<tr>
<td>{{ Array1[$index].address }}</td>
<td>{{ Array1[$index].city}}</td>
<td>{{ Array1[$index].email}}</td>
</tr>
<tr >
<td>{{ Array2[$index].address }}</td>
<td>{{ Array2[$index].city}}</td>
<td>{{ Array2[$index].email}}</td>
</tr>
</tbody>
It might be safer to use a getter function on those arrays also:
getData(index,array,value)
Where you can prevent any null errors from occurring.
I wish to show prices in a specific table within my site to 3 decimal places.
Prices will be shown in Pounds, Dollars and Euros.
My currency filter seems to automatically round the price to 2 decimal places.
Also, if the currency is in Euros, Ideally, I would like to auto change the thousands separator to a . and decimal separator to a ,.
Does angularjs have support for this?
The View
<div ng-controller="SpotController">
<table class="header-table-spot-prices">
<thead>
<tr><th>Spot Prices</th><th>Price</th></tr>
</thead>
<tbody>
<tr ng-repeat="spot in spots">
<td>{{ spot.item }}</td>
<!-- This needs to be 3dp -->
<td>{{ spot.price | currency:spot.currency }}</td>
</tr>
</tbody>
</table>
</div>
This is probably irrelevant at this point since the original post was 2 years ago, but angular's "currency" filter takes in a symbol and a fraction size as parameters.
For example:
<td>{{ spot.price | currency:spot.currency : 3 }}</td>
Would output what you are looking for without the caveat of changing the separators based on currency. You could either create your own currency filter that first uses the angular filter, then checks the condition and alters the separators. This plunker illustrates that.
.filter('myCurrency', ['$filter', function($filter){
return function(input, symbol, fractionSize){
input = $filter('currency')(input, symbol, fractionSize);
if(symbol === '\u20AC'){
var tempString = "###";
input = input.replace(",", tempString).replace(".", ",").replace(tempString, ".");
}
return input;
}
}])
You've probably already solved this for your needs, but putting the answer here just in case anyone else is running into a similar issue and comes across this post.
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(){
....
}