How do I compare with a string in ng-class? - angularjs

This line doesn't seem to work for me.
Sort By: Alphabetical
Do I have to escape 'title' in orderProp == 'title' somehow?
in the controller I have
...
$scope.orderProp = 'title';
$scope.setOrder = function(sortBy){
$scope.orderProp = sortBy;
}
...
Thank you
Update: Using v1.3.0-beta.17
Adding ng-class="{active:orderProp=='pagetitle'} to
Alphabetical
throws an error
"Error: [$parse:syntax] http://errors.angularjs.org/1.3.0-beta.17/$parse/syntax?p0=undefined&p1=not%20a%20primary%20expression&p2=null&p3=%7Bactive%3AorderProp%3D%3D&p4=%7Bactive%3AorderProp%3D%3D
Sorry for the way I present the error but I just started angular last week and don't know a better way
Update 2:
error seems to be coming from = == ===. I tried > and no error occured. Is there an alternative syntax to like eq?
Update 3 with solve
I mapped each string to an int pagetile->1 code->2 + data-ng-class="{active:orderPropIdx==1};"
Inside the controller I just do if pagetitle set active:orderPropIdx to 1 and so on
Maybe this is a bug in angular 1.3

As is stated in the comments, your class name should be surrounded by single quotes.
ng-class="{'active': orderProp == 'title'}">
This comparison is case sensitive.

Had the same issue when using ng-class. It refused to dynamically compute the class attribute even though the expression was successfully calculated.
And here is the workaround I've used for the ng-class statement:
Sort By: Alphabetical
instead of ng-class="{active: orderProp == 'title'} I've switched to class="{{orderProp == 'title' ? 'active' : ''}}"

I resolve in this way; 'ClassName':'{{Value}}'=='StringtoCompare', ...
ng-class="{ 'btn-danger' : '{{datasource.difficoltaRicetta}}'=='Difficile', 'btn-warning' :'{{datasource.difficoltaRicetta}}'=='Intermedia', 'btn-success' : '{{datasource.difficoltaRicetta}}'=='Facile'}"

I mapped each string to an int pagetile->1 code->2 + data-ng-class="{active:orderPropIdx==1};" Inside the controller I just do if pagetitle set active:orderPropIdx to 1 and so on
Maybe this is a bug in angular 1.3

This is for people coming to this answer looking for the solution with [ngClass].
<a [ngClass]="{ active: selectedValue === 'foo bar' }"> FooBar </a>
This would result in adding class="active" to the anchor element when the variable selectedValue is given the value "foo bar".

The syntax for ng-class can be quite confusing sometimes. Try this.
ng-class="{true: 'active', false: ''}[orderProp === 'title']"
Include square brackets after the curly braces. Inside the square brackets, you can declare any expression, and declare your results (true/false) and the corresponding classes you want to apply (active). And be sure to use '===' in your expressions, signifying you want orderProp to be exactly equal to what you are comparing it against.

Related

data-ng-src with if condition

I have an image that I display using this:
<img data-ng-src="data:image/jpg;base64,{{selectedReport.reportImage.imageFile.data}}"/>
The above data is fetched from my database.
When the user clicks edit record and selects a new image which is stored in variable imageFile, I want to show this imageFile instead of the record fetched.
How do I use an if condition with data-ng-src?
Individually these work, but i want to apply an if condition where I say, if ImageFile, then
data-ng-src="{{imageFile}}"
else
data-ng-src="data:image/jpg;base64,{{selectedReport.reportImage.imageFile.data}}"
I tried to do like this:
data-ng-src = {{imageFile}} and data-err-src = "data:image/jpg;base64,{{selectedReport.reportImage.imageFile.data}}"/>
But this doesn't work.
I think you should just use a function, declared in your controller to deal with the situation.
In your controller :
$scope.getImage = function (){
return $scope.imageFile || [your_default_image_file];
}
In your HTML, something like :
<img data-ng-src="{{getImage()}}"/>
I hope it helps.
AngularJS views support binary operators
condition && true || false
So your img tag would look like this
<img data-ng-src="{{ imageFile != '' && imageFile || 'your-default-image' }}"/>
Note : You could use any condition to know if imageFile exists or has a value.
Note 2 : the quotes (ie 'your-default-image') are important here. It won't work without quotes.

Strange bug with ng-repeat and filter

I'm using NodeJS, ANgularJS, and MongoDB with mongoose
Here is my model :
var PostSchema = new mongoose.Schema({
nomReseau : String,
corps : String,
etat : String,
section : String
});
I got a function that change the attribute etat:
$scope.passer = function(index){
var post = $scope.posts[index];
post.etat = "enCours";
Posts.update({id: post._id}, post);
$scope.editing[index] = false;
}
I'm using a ng-repeat for show object in my database :
<ul>
<li ng-repeat="post in posts ">
<p>
<a ng-show="!editing[$index]" href="#/{{post._id}}">{{post.corps}}</a>
</p>
<button ng-show="!editing[$index]" ng-click="passer($index)">Passer</button>
</li>
</ul>
I can see all post in my database and when I click on the button this works perfectly the attribute etat change and all is fine.
But when I add a filter in the ng-repeat like this :
<li ng-repeat="post in posts | filter:{ etat:'aTraiter'} ">
The filter works great I have all post with the attribute etat:'aTraiter'
But if I click on my previous button and change the attribute etat nothing change and I try with other functions they all work wihout the filter but when I put it nothing work.
The problem is that $index will change if less data is shown (because you're filtering). you could use directly post variable
ng-click="passer(post)"
and your function should be something like
$scope.passer = function(post){
post.etat = "enCours";
Posts.update({id: post._id}, post);
var index = $scope.posts.findIndex(function(p) { /* comparison to get original index */ }); /* keep in mind findIndex is not supported on IE, you might want to use filter or for loop instead) */
$scope.editing[index] = false;
}
you could handle editing in the post variable directly. So in your passer function you can do this
post.editing = false;
and in your view
ng-show="!post.editing"
this way you won't use $index and you will prevent all issues with being updated by filters
There are bugs in AngularJS v1.4 where in certain situations the ng-repeat breaks. I upgraded to v1.6 and it went away.
Do you have any controllers/services that access $scope.editing? If so, you might be setting the $scope.editing[$index] equal a previous state where it wasn't equal to false. You may also want to consider that you are assuming $scope.editing[$index] is going to be a boolean. if it has any other type such as string or number then it will evaluate to true.
Otherwise none of your results have the attribute etat equal to 'aTraiter' so they aren't showing. Have you verified that any of them actually do have etat equal to 'aTraiter'. You might be changing that value somewhere else. Possibly from the Passer function

Angular TypeError: name.replace is not a function for ng-style

I'm new to angular and keep getting the following error in the console TypeError: name.replace is not a function. I'm not sure what's exactly causing it, but it seems to be caused by the ng-style statement and maybe something to do with the camelCase?
The part I don't understand is why ng-style="isFrontView() || !matches && {'display': 'none'}" throws the error, but ng-style="!isFrontView() || !matches && {'display': 'none'}" doesn't throw the error.
In an attempt to remedy the situation I tried removing the camelCase from the function name and went all lowercase. I also attempted to use !!isFrontView(), but neither seemed to remove the error message.
Do anyone know what is the cause of this error message and a potential fix?
HTML Template:
<div class="system-view">
<div class="controller-container fill" id="systemView1" ng-style="isFrontView() || !matches && {'display': 'none'}">
<canvas id="canvasLayer-shell" data-layername="front" width="617" height="427"></canvas>
<i ng-if="!matches" class="fa fa-repeat toggle-view" ng-click="changeView()" ng-touch="changeView()"></i>
</div>
<div class="controller-container fill" id="systemView2" ng-style="!isFrontView() || !matches && {'display': 'none'}">
<canvas id="canvasLayer-shell" data-layername="back" width="617" height="427"></canvas>
<i ng-if="!matches" class="fa fa-undo toggle-view" ng-click="changeView()" ng-touch="changeView()"></i>
</div>
</div>
Backend Code:
$scope.frontView = true;
$scope.matches = true;
$scope.isFrontView = function() {
return $scope.frontView;
};
$scope.changeView = function() {
$scope.frontView = !$scope.frontView;
};
P.S. Even with the console error everything still functions normally.
Your potential issue is due to the incorrect usage of ng-style. ng-style sets a watcher on the expression and sets the element's style with the help of jquery/jqlite element.css. And Inside element.css css attribute (name) is converted to the standard camel casing (which uses regex string replace). In your specific case the expression evaluated to boolean (true) instead of an object (ng-style does this for each property) and boolean does not have replace property (which is available on a string object) and hence it fails. You can test this by converting your expression to evaluate to a string by using string concatenation.
i.e ng-style="'' + (isFrontView() || !matches && {'display': 'none'})"
Looking at the expression all you need it to hide and show the element, you could well make use of ng-show/ng-hide directives to achieve that.
This can happen if the expression evaluated returns the wrong type.
Expression evaluated:
ng-style="$vm.getStyles()"
must return an object literal:
return { order: -1 };
This is a late answer but I might help others that have the same issue like me.In my case the error is a.replace is not a function and finally I found the reason. It was happening due to ng-style and the expression was data-ng-style="isCompare==true ? {'max-height':'423'} : ***' '*** .... that space between single qoutes caused the error.After removing space the error went away.

Multiple $interpolation symbols in AngularJs

I am rather new to AngularJs, but I have a specific need for a more complex, conditional template using multiple interpolation symbols. I am using the same example as in https://docs.angularjs.org/api/ng/service/$interpolate .
I need something like:
[[ {{greeting}}, {{name}} || Hello, {{name}} || Hello, stranger ]]
This should be interpreted as a multiple conditional template, showing the first fragment if both $scope.greeting and $scope.name are defined, the second one if only $scope.name is defined, and the third one otherwise.
The idea is that within symbols [[ ]] the fragments between a || symbol are interpolated using the standard interpolation symbols with AllOrNothing, proceeding from left to right until the first one succeeds, and making sure that the last one always succeeds.
I know that this can be done with something like
<span ng-if='greeting && name">{{greeting}}{{name}}</span>
<span ng-if='name && !greeting">Hello, {{name}}</span>
<span ng-if='!name">Hello, stranger</span>
but this solution is extremely cumbersome, requires to determine which complex set of boolean expressions makes sure that only one span is shown, and adds spurious spans to the DOM just because you need a place for the ng-if directives.
Thank you for all you can suggest.
You can write your own filter to handle this situation specifically. If you want something a little more reusable, in regards to conditional output, you could make an a kind of ternary filter. Here's one called iif (named as such to prevent eval errors we'd get if we called it just if):
.filter('iif', function() {
// usage: {{ conditionToTest | iif:truevalue:falseValue }}
// example: {{ iAmTrue | iif:'I am true':'I am false' }}
return function(input, trueValue, falseValue) {
return input ? trueValue : falseValue;
};
})
Use it like this in your example:
{{greeting | iif:greeting:'Hello'}}, {{name | iif:name:'stranger'}}
You can certainly specialize it further, if that's too verbose:
.filter('valueOrDefault', function() {
return function(input, defaultValue) {
return input || defaultValue;
};
})
Then your template looks like:
{{ greeting | valueOrDefault:'Hello' }}, {{name | valueOrDefault: 'stranger'}}
And so on.
The interpolator should be able to handle it.
<p>{{ greeting || 'Hello' }}, {{ name || 'Stranger' }}.</p>

How do I debug/dump a value from an ng-bind {{ }} Angular expression?

Is there a good way to dump or inspect the results of an expression? Sometimes when I do
{{some_expression}}
, nothing shows up on the page where the result of that expression should show up. How do I determine if the expression returned a null, an undefined, or an empty string ''?
If it's a normal object, like this, it will show a nice programmer-friendly representation of the object, which is great:
{{ {'a': 1} }}
But if you try to inspect an expression that evaluates to null, undefined, or '', they are all indistinguishable from each other!
{{null}}
{{undefined}}
{{''}}
So how can you tell which one it was??
I tried using JSON.stringify:
{{ JSON.stringify(null) }}
but JSON seems to be unavailable from an Angular expression because it's a method from window and not a property of the scope (see related question about accessing methods from window).
I tried using typeof:
typeof {}: {{ typeof {'a': 1} }}
but it results in an error:
Error: [$parse:syntax] Syntax Error: Token '{' is an unexpected token at column 9 of the expression [ typeof {'a': 1} ] starting at [{'a': 1} ].
So how can I get it to dump the value into the template using something like JSON.stringify (… or console.log)?
Generally speaking, is there a good way to debug Angular expressions other than trial and error? Since Angular expressions are so "forgiving", they don't seem to raise errors; they just silently swallow the errors and return undefined:
In JavaScript, trying to evaluate undefined properties generates
ReferenceError or TypeError. In Angular, expression evaluation is
forgiving to undefined and null.
But without seeing some kind of error message, how do you know what part of the expression Angular had trouble with?
You can add a custom filter for debugging purposes:
app.filter('debug', function() {
return function(input) {
if (input === '') return 'empty string';
return input ? input : ('' + input);
};
});
Usage:
{{ value | debug }}
Demo: http://plnkr.co/edit/U44BCjBhgsFedRkHASlc?p=preview
The recommended way is to use AngularJS's logging service $log. First you need to inject the service into your controller and assign it to a scope variable like so:
app.controller('MyCntrl', function($log){
$scope.$log = $log;
Then in your template, us it like ay other function:
<span>{{$log.log(value}}</span>
If you want to be able to use typeof, it works basically the same way:
$scope.getTypeOf = function(val){ return typeof val; };
<span>{{getTypeOf(val)}}</span>
The built-in JsonPipe might be easier...
{{ object | json }}
See: https://angular.io/api/common/JsonPipe
Based on tasseKATT's and ogc-nick's great answers, I added these two filters. They're written in CoffeeScript but here's the JavaScript equivalent if you prefer. Posting here in case it's helpful to anyone else...
.filter 'debug', ->
(input) ->
if typeof input is 'undefined'
'undefined'
else
JSON.stringify(input)
.filter 'typeof', ->
(input) ->
typeof input
Now I can get some meaningful debugging output from each of the following expressions:
{{null | debug}}
{{undefined | debug}}
{{'' | debug}}
If you're using Chrome, you can try the Batarang extension which allows you to inspect properties on your models. Access it by opening the developer console (CTRL+SHIFT+I), and then you should see a Batarang tab. You'll have to click to enable, and then you should get a listing of all Angular models present on your page. They won't be intuitively named, but you can click through them and deduce which ones are which.
Have you tried putting the console.log() inside the double curlies? That might also work if you just want a quick and lazy method.

Resources