ngClass - creating a class name containing angular expression - javascript

I would like to create class names based on an the evaluation of an angular expression, but it seems that angular is removing these expressions from the eventually compiled classes. When iterating over cells, assume the following code:
<td ng-class="{'label{{cell.count}}': !!cell.count}"></td>
My goal is that when cell.count = 1 the resulting class will be "label1", when cell.count = 2, "label2", etc.
In practice, what happens is that angular discards the expression in the eventual class - As long as !!cell.count, I get the class "label" regardless of the count. How can I achieve this?

Try this:
<td ng-class="{'label'+cell.count: !!cell.count}"></td>
If it gets too complicated you can also move the entire object out into a function in the scope.
<td ng-class="getCellClass()"></td>
and then:
$scope.getCellClass = function() { ... }
Your problem is that the {{...}} substitution isn't appropriate here. You have to use an angular expression to create the object, or if you call a method on the scope you can do any javascript you need to create it.

Did you ever try: <td ng-class="'label' + cell.count"></td> - simply not using the curly braces works for me in my project (angular 1.5).

I had the same issue. I managed to solve it like this:
<td ng-class="{['label' + cell.count]: !!cell.count}"></td>

Related

Why the ngStyle directive is declared into the []?

I am an absolute beginner with Angular 2 and I have the following dount related the correct syntax of the ngStyle directive.
I have this example (that works fine):
<p [ngStyle]="{backgroundColor: getColor()}">Server with ID {{ serverID }} is {{ getServerStatus() }}</p>
I know that, in this case, the ngStyle directive is adding something like to:
style="background-color: green;"
at my HTML paragraph.
My doubt is related the correct meaning of this syntax. Why is it:
[ngStyle]="{backgroundColor: getColor()}"
and not
ngStyle="{backgroundColor: getColor()}"
Why is it into the [...]? What it exactly means?
It's called property binding. With the brackets the compiler tries to evaluate the expression. Without it, you are just passing a string.
So with the brackets, you are passing a javascript object:
{
backgroundColor: getColor()
}
Whereby the compiler will call the getColor() method from the component to get the right color.
On the other hand, and going off topic here, but if you want to pass a string while using brackets, you should wrap them in single quotes:
<div [property]="'hiii'"></div>
Angular 2 has 3 types of directives:
Attribute directives.
Structural directives.
Components.
ngStyle is an attribute directive. And all attribute directive to which we need to pass/assign values are written inside square brackets.
The built-in NgStyle directive in the Template Syntax guide, for example, can change several element styles at the same time.

How do I interpolate variable string in pug?

In the following, myVar contains the string "Today, it's the ${date}".
Furthermore, there is an variable with the name date that contains "1st of October". I expect the following pug syntax to replace the literal ${date} with the date variable content.
span!= myVar
Unfortunately, the example results in
<span>Today, it's the ${date}</span>
Expected result:
<span>Today, it's the 1st of October.</span>
Best regards,
Benedikt
Yes, exactly as #omgninjas pointed out, it is called interpolation and preceded by # in Pug.
However you can't always use it (eg. inside a string). Here are some examples:
sensor is a variable passed by the controller to the view.
Normal interpolation. Works as expected:
<div id=#{sensor} style="width:90%;height:250px;"></div>
Inside a string with Template Literals (don't use these with user supplied values!):
img(src=`/images/${sensor}.png`, style="width:20%")
Inside a string used to denote a function call. Note that you cannot use the ` symbol (back tick aka grave accent used in template literals) with function calls because you would have to ecompass the entire function call . This results in a string which is not going to be executed. You need to use string concatenation.
body(onload="initTemp('"+ sensor +"')")
Here is the official documentation for Pug interpolation:
https://pugjs.org/language/interpolation.html
Hope this helps. Corrections and suggestions always welcome!
To render variables directly in a string in a Pug template, you can use the typical ES6 interpolation. Example (assuming pageTitle is in scope, and passed as template context):
- var pageTitle = `Google | ${pageTitle}`;
Pug interpolates with a hash. #{interpolation}

In angular.js, can I filter something before I $eval() it?

I'm using Angular.js for a web app. I have some data I want to $eval(), but the problem is that before I do that, I need to replace a placeholder in the string with the name of the variable I'm using. I wrote a filter to handle that, but I can't figure out how to run the filter before the string is passed to $eval().
Here's an example of what I'd like to happen:
app.js
$scope.newVariable=3;
$scope.test='2+[placeholder]';
index.html
<p>{{$eval(test|replace:'[placeholder]':'newVariable')}}</p>
What I want to happen is for '[placeholder]' to be replaced by 'newVariable' and then for that new string to be passed into $eval(). The way it is written now, the page just crashes when I load it. I've tested the filter separately, so I know that's not the problem. Is there a way to apply this filter before the string is $eval()ed?
Firstly, $eval should be invoked on a scope that you must specify.
Since filters can easily be chained in Angular, you could try creating an additional filter that will perform the evaluation on your replaced expression and then have it displayed.
For example, your filter definition could look like:
.filter('eval', function() {
return function(expr, scope) {
// Note how $eval is called for the passed in scope.
return scope.$eval(expr);
}
})
Then in your HTML:
{{ test | replace:'[placeholder]':'newVariable' | eval:this }}
Note that the this supplied to the eval filter should be the $scope of the controller.

Angular : How does ng-click directory parses the expression without doubly curly brace?

I have a view as follwing,
<li ng-repeat="img in people.images">
<img ng-src="{{img}}" ng-click="setImage(img)">
</li>
Its working. But my doubt here is, the attribute ng-click should have been set the img inside doubly braces to be executed as in ng-src as ng-click="setImage({{img}})". Its shown below,
<li ng-repeat="img in people.images">
<img ng-src="{{img}}" ng-click="setImage({{img}})">
</li>
But the later is not working.
How the expression is parsed here and how does ng-click vary from ng-src?
I really confused here. Any help highly appreciated.
The difference is the following: Some of the directives use expressions, some don't. This is how they "vary" from each other. You may use the angular documentation to see, which directive use expressions and which don't.
Example for ng-click: https://docs.angularjs.org/api/ng/directive/ngClick It uses an expression:
Example for ng-src: https://docs.angularjs.org/api/ng/directive/ngSrc It doesn't use an expression:
ngClick lets you define a JavaScript-like expression, while ngSource lets you define an usual String, where you also may define an expression, inside the double braces. According to the AngularJS documentation, everything inside of the double braces is also an expression: https://docs.angularjs.org/guide/expression.
I think that the "need" to have the difference between "Expression" for "ngClick" and "String" for "ngSrc" come from the original attributes they derive from: onclick and src.
The attribute src is used to reference a resource as String, while using the attribute onclick, you may use javascript. The usual case is to call a function in onclick, i.e. onclick="doSomething();". I assume that angularjs uses these attributes as a base, this is why the workflow is similar. ngClick lets you use usual javascript expressions, while ngSrc lets you use a String and add a {{}} expression if you need to.
The benefit of using ngSrc with a variable, for example ngSrc="http://localhost/{{myRessource}}" is, that it is evaluated only after $scope.myRessource is set, not before. It uses the observer pattern to render the view as soon as the variable is set, as far as I know.
According to your example, the second one which doesn't work:
<li ng-repeat="img in people.images">
<img ng-src="{{img}}" ng-click="setImage({{img}})">
</li>
It doesn't work because of a syntax error. ngClick uses javascript expression, and the syntax of setImage({{img}}) is not correct - you would not use double brackets around variables either in a javascript function.
Further: $interpolate and $parse
Like stated above, some directives, like ngClick use expressions, while other directives like ngSrc use plain Strings combined with {{}}. The difference between the two on angularJs side is the following:
a directive using an expression is evaluated by angularjs using $parse (Read here from heading "Text and attribute bindings")
a directive using a String is evaluated by angularjs using $interpolate (Read here from heading "Context")
Example:
$scope.varOne = "asdasdasd";
var test1 = $interpolate("http://localhost/{{varOne}}");
$scope.displayOne = test1($scope);
At first, we declare a variable varOne. $interpolate returns a function which needs to be called with the scope, we will bind this to the local variable test1. Then we will call test1 using the $scope. As a result, we will have on displayOne the String http://localhost/asdasdasd.
var test2 = $parse("1+5-3");
$scope.displayTwo = test2($scope);
$parse is evaluating javascript expressions, as a test we may use the calculation "1+5-3". After calling test2, the result will be 3.
I prepared a fiddle, so you can see this: http://jsfiddle.net/wSN54/6/
You may also try using brackets in the $parse evaluation (the same that happens in your second example):
$scope.varTwo = 2;
$scope.varThree = 3;
var test2 = $parse("{{varTwo + varThree}}");
$scope.displayTwo = test2($scope);
This must resolve in an error, because the double braces are not used in usual javascript expression:
Check it out fiddle: http://jsfiddle.net/wSN54/8/
As far as I know, if you put img param inside double brackets, when the page is rendered, you will notice that the parameter inside setImage function is a value of img. If you put img without brackets you will have rendered "setImage(img)" and in both case that will work.
Example:
imagine that you have one item in people.images model, and its for example "example.jpg". If you use brackets in setImage function, when the page is rendered you will see the attribute "ng-click=setImage('example.jpg')", in another approach you will have "ng-click=setImage(img)". In first case AngularJS don't need to parse value from your parameter, because you already put 'example.jpg' like a parameter, in another case AngularJS will parse value from img parameter/item before your function is executed.
TLDR; ng-src $interpolate the argument as template where ng-click $parse the expression
Long version
Copied from angular official docs
param=ngSrc, type=template
param=ngRepeat, type=repeat_expression
details refer to https://docs.angularjs.org/api/ng/directive/ngSrc and https://docs.angularjs.org/api/ng/directive/ngRepeat
What is expression - https://docs.angularjs.org/guide/expression
What is template(markup) - https://docs.angularjs.org/api/ng/service/$interpolate

Setting and getting bootstrap radio button inside angular repeat loop

I am trying to set the default button and get the current selected value.
The example without the repeat loop works.
Here is my plnkr:
http://plnkr.co/edit/t9CefA5bhLZs3RASmEUG?p=preview
It is based on this example:
http://plnkr.co/edit/LFj4inY9TLYZs9z7yHCr?p=preview
Thank you!
So, there were 2 things going on in your plunker.
Firstly the btn-radio attribute doesn't need interpolation ({{}}) you can (and should) provide an expression directly. So just write btn-radio="company.id" instead of btn-radio="{{company.id}}".
Secondly, you must know that the ng-repeat directive creates a new scope. This is a very, very common conceptual issue people have with AngularJS so I would encourage you to read https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance
Coming back to you particular problem you can either change you ng-model expression to point to a parent scope (ng-model="$parent.radioModel") or bind to an object property (ng-model="radioModel.id").
Here is a working plunk with the second approach:
http://plnkr.co/edit/uGAxaRlPFK6sD4tRjGXX?p=preview

Categories