The following conditional return false inside a angular view:
<a ng-class="(parseFloat('-0.56%') < 0) ? 'true' : 'false'">...</a>
I've already added the parseFloat method in $scope.
$scope.parseFloat = parseFloat;
Thanks for any help.
Take a look at this fiddle
You can use option 1 (as you have it) but you need to use class not ng-class
<a class="{{(parseFloat('-0.56%') < 0) ? 'true1' : 'false'}}">Option 1</a>
In order to use ng-class use this:
<a ng-class="{'true': (parseFloat('-0.56%') < 0), 'false': (parseFloat('-0.56%') >= 0)}">Option 2a</a>
<a ng-class="{'true': (parseFloat('0.56%') < 0), 'false': (parseFloat('0.56%') >= 0)}">Option 2b</a>
The difference being is that ng-class takes an object where the key is the class and the value is the boolean evaluation to determine if the class gets added to the element.
Related
How can I do an ng-hide inline expression like this:
ng-hide="userType!=user"
?
what is your userType ?? a string ? and you want to hide if != 'user'
ng-hide="userType!='user'"
please check this answer about ng-hide/ng-show
The ngHide directive would not work on an inline expression. The inline expression is evaluated and then the result is injected in the HTML element containing the expression.
If the inline expression is just plain text, you could try the following:
{{ userType != user ? "" : value }}
or if you do not want an empty string you could also use "null"
{{ userType != user ? null : value }}
I have many tags in HTML with ng-class directive which looks like:
div(class="item-detail-section-line", ng-repeat="group in FieldGroups")
a(href="", ng-click="groupClick(group)",
ng-class="group == currentGroup ? 'item-detail-section-line-selected' : " +
"'item-detail-section-line-unselected'"
I am just wondering if there is any way to write ng-class directive in more compact way? May be move the condition to controller?
Moving the condition to a controller is not a bad idea to clean up your view.
// In your controller
$scope.setDetailLineSelectedClass =
{
'item-detail-section-line-selected': $scope.group == $scope.currentGroup,
'item-detail-section-line-unselected': $scope.group != $scope.currentGroup
}
// In your view
ng-class="setDetailLineSelectedClass"
// Using non-scope variable (created by ng-repeat)
// In your controller
$scope.setDetailLineSelectedClass = function(group){
return {
'item-detail-section-line-selected': group == $scope.currentGroup,
'item-detail-section-line-unselected': group != $scope.currentGroup
}
}
// In your view
ng-class="setDetailLineSelectedClass(group)"
For ng-class there isn't a very much shorter way. You could use the object notation for it:
ng-class="{'item-detail-section-line-selected': group == currentGroup, 'item-detail-section-line-unselected': group != currentGroup}"
In your case it might not be shorter necessarily.
Another approach is to move the logic to an ng-if instead. Although you gain some watchers compared to the initial approach, it would be more readable and manageable than using ng-class as you can use functions using the ng-if:
div(class="item-detail-section-line", ng-repeat="group in FieldGroups")
a(href="", ng-click="groupClick(group)",
ng-if="group == currentGroup"
class="item-detail-section-line-selected"
a(href="", ng-click="groupClick(group)",
ng-if="group != currentGroup"
class="item-detail-section-line-unselected"
I have a list of items, which comes in unsorted, I use orderBy to sort by name alphanumerically.
<li class="ticker-li"
ng-repeat="ticker in tickers | orderBy:'ticker'"
ng-class="{'selected':ticker.selected}">
<div class="ticker"
ng-click="unselectAll(); ticker.selected = !ticker.selected;
selectTicker(ticker);
revealTickerOptions()">
{{ticker.ticker}}
</div>
Now in my controller this is how I'm currently setting the first items selected class:
var vs = $scope;
vs.tickers = data;
vs.tickers[0].selected = true;
^ This worked perfectly until I needed to add the orderBy so that items appear by alpha order:
I found this answer here, however it locks the first item to always have the class.
Modifying my code a bit, I was able to have other buttons gain that class on click, however the $first item still stayed with the class.
ng-class="{'selected':$first || ticker.selected}"
In my controller this is my unselectAll function, which doesn't work with 'selected':$first:
vs.unselectAll = function() {
for (var i = 0; i < vs.tickers.length; i++) {
vs.tickers[i].selected = false;
}
};
How should the code either in the markup or controller need to be updated to fix this issue?
Give this a shot, I'm not sure how it reads the $index on the sort by, but get rid of the $first thing and put this init statement in there.
<li class="ticker-li"
ng-repeat="ticker in tickers | orderBy:'ticker'"
ng-init="$index ? ticker.selected = false : ticker.selected = true"
ng-class="{'selected':ticker.selected}" ng-click="unselectFirst($index)">
I think this is a grey area between a hack or not, you aren't technically aliasing a property in the ng-init, but i think it is a fine line. The other solution would be sort the array in your controller, there is an example in the docs that sort on alphabetic order, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
I try to do this:
<div id="{{mystring.replace(/[\s]/g, \'\')}}"></div>
but its not working. "mystring" is an object on $scope with string like "my string is this" with spaces I want to remove from the view.
Just create a dedicated filter :
angular.module('filters.stringUtils', [])
.filter('removeSpaces', [function() {
return function(string) {
if (!angular.isString(string)) {
return string;
}
return string.replace(/[\s]/g, '');
};
}])
and call it like :
<div id="{{'hi there'| removeSpaces}}"></div>
If you simply need it in one or two places it may be easier to split and join:
$scope.boundString = 'this is a string with spaces'
with that you could do in your template:
<span>my string is: {{ boundString.split(' ').join('') }}</span>
and you would get:
my string is: thisisastringwithoutspaces
another approach that has been mentioned is the regex version ('g' is for global):
<span>my string is: {{ boundString.replace(/ /g, '') }}</span>
I guess the point is that you can do whatever you want to a string within an expression. These examples are bad convention with respect to Angular dirty-checking. In Angular, bound functions (string.replace, string.split) get evaluated differently opposed to a specified value (string, boolean) when bound to a template's expression. The result of a bound function must be evaluated before Angular knows whether or not to update the DOM. This can be costly over a large app. I would suggest using another variable to track the un-spaced value:
$scope.noSpaces = $scope.boundString.replace(/ /g, '');
HTML:
<span>{{ noSpaces }}</span>
This way, when a digest loop is triggered, Angular will check if noSpaces has changed as opposed to evaluating boundString.replace(/ /g, '').
What if you are ng-repeating? Good question.
for (var idx = 0, idx < $scope.boundIterable.length, i++) {
$scope.boundIterable[i].noSpaces = $scope.boundIterable[i].boundString.replace(/ /g, '');
}
HTML:
<ul ng-repeat="iterable in boundIterable">
<li>{{ iterable.noSpaces }}</li>
</ul>
The directive mentioned works pretty well. But if you want to remove spaces for smaller texts, you can use
.split(" ").join("")
This replaces the complete spaces unlike .replace(" ","") which replaces only the first space.
You can replace all spaces by blank by using replace():
.replace(" ","")
How about {{ string.trim() }}?
Source
You can do it by using replace():
{{mystring.replace(" ","")}}
that's it I hope so.
removeSpaces() {
originalText ="hi! here i'm";
removedSpacesText = originalText.split(" ").join("");
}
Here is a code sample I use:
<div ng-class="{alert: ((elements|filter:{hasAlert: true}).length / elements.length) > maxPercentAlerts}">
{{(elements|filter:{hasAlert: true}).length}}
({{Math.floor((elements|filter:{hasAlert: true}).length * 100 / elements.length)}} %)
</div>
As you see, I need to filter my 'elements' array 3 times. I would like to use this kind of following code to increase perfs:
(this is just an example of what I need, not real code)
<div some-ng-prop="alertCount=(elements|filter:{hasAlert: true}).length"
<div ng-class="{alert: (alertCount / elements.length) > maxPercentAlerts}">
{{alertCount}}
({{Math.floor(alertCount * 100 / elements.length)}} %)
</div>
I've tried to handle it with the 'ng-init' attribute: it worked great... But when my model changes, the values are not updated.
Is there a way to do that ?
I've tried to be clear, but please ask for details if you don't understand what I mean.
Here is a plunker: http://plnkr.co/edit/bNjSnee5UwVjp6wHE6RK
I created a directive:
I use $parse rather than $eval for optimizations.
You provide a collection to watch and an expression to run on each change.
It works like ngInit only it updates when the collection is dirty.
I chose general names for attributes, you can change it to what you like.
directive:
app.directive('watchCollection', function($parse){
return {
compile: function(tElm,tAttrs){
if(! tAttrs.assign) return;
var assignFn = $parse(tAttrs.assign)
return function(scope,elm,attrs){
scope.$watchCollection(tAttrs.watchCollection , function(val){
assignFn(scope);
})
}
}
}
})
html:
<div watch-collection="elements"
assign="alertCount=(elements|filter:{hasAlert: true}).length">
Stewie suggested it was a duplicate, I think it's not but it made me try the following code which works great :
<div ng-class="{alert: (alertCount / elements.length) > maxPercentAlerts}">
{{alertCount = (elements|filter:{hasAlert: true}).length}}
({{Math.floor(alertCount * 100 / elements.length)}} %)
</div>