I am brand new to AngularJS and while doing the Codecademy course I got stuck. I was trying to repeat a directive using the following syntax.
<div class="card" ng-repeat="app in apps">
<app-info info="{{ app }}"></app-info>
</div>
I played around a bit and figured out I needed to remove the curly braces.
<div class="card" ng-repeat="app in apps">
<app-info info="app"></app-info>
</div>
But if I was not using a directive I think I would access the information like this. AngularJS documentation.
<div class="card" ng-repeat="app in apps">
{{ app }}
</div>
Could someone explain why I do not need the curly braces to help me better understand AungularJS. Thanks!
Usage of interpolation symbols {{ }}depend upon the implementation of the directive.
Some directives like ng-click='expression' or ng-if='expression' take an expression without the double curlies.
Whereas some other directives such as ng-src='{{expression}}' accept interpolation symbol.
It all depends upon how the directive is setup.
The basic usage of interpolation is to execute the expression and replace the content with the return value of expression (a string value).
As you learn more about the directives, you will learn how parameters are passed to directives using #,=,&. These parameters could be a simple string value (in which case an interpolation can be used), or an object, or a function.
In that particular case, using {{data}} you are evaluating the value of that variable, but when you do info="app" in other directive which contains a scope variable called info , what you are doing is binding the info scope variable of our app-info directive to the controllers (or parent directive) app scope variable.
Related
I'm reviewing this tutorial which uses a tooltip directive like this:
CASE A: No surrounding []
<p tooltip="Tooltip from text">Tooltip from text</p>
CASE B: Surrounding []
<p [tooltip]="template">Tooltip from TemplateRef</p>
I just want to make sure I understand this correctly.
If we use the tooltip directive without brackets, then the text string gets passed to the directive (Tooltip from text").
When we surround the tooltip with brackets, then the template property, which should be available on the component view (The view using the directive), gets passed in?
If we use the tooltip directive without brackets, then the text string gets passed to the directive
Yes Exactly.
For the second case, [tooltip]="template"
[prop] is for object binding to properties (#Input() of an Angular component or directive or a property of a DOM element) of the angular Component.
Taken from the Angular documentation:
Angular Expressions
Angular expressions are JavaScript-like code snippets that are mainly
placed in interpolation bindings such as
<span title="{{ attrBinding }}">{{ textBinding }}</span>
but also used directly in directive
attributes such as ng-click="functionExpression()".
For example, these are valid expressions in Angular:
1+2 a+b user.name items[index]
However I'm a little confused as to when to use the double braces syntax {{}} and when not to. The documentation seems to suggest that you don't need them when using expressions within the directive attributes (see the ng-click example above).
Although the following code which works offers anecdotal evidence to the contrary:
<ul id="Menu">
<li ng-repeat="appModule in applicationModules"
id="{{appModule.Name}}"
ng-class="{ 'selected' : selectedAppModule == '{{appModule.Name}}' }"
ng-click="menuClicked(appModule.Name)">
{{appModule.Display}}
</li>
</ul>
Note how in the ng-class directive the double braces are used and inside the ng-click directive they are not.
How do you know when to use them and when not to?
It depends on the directive attribute in question and the type of binding it uses. Further more it depends on what you intend in the given situation.
From your example:
ng-repeat="appModule in applicationModules"
No need for the braces as this expression is evaluated by angular inside the ng-repeat directive.
id="{{appModule.Name}}"
Here we need braces as we want the id to be equal to the value of the expression.
ng-class="{ 'selected' : selectedAppModule == '{{appModule.Name}}' }"
I'm pretty sure this can be written as:
ng-class="{ 'selected' : selectedAppModule == appModule.Name }"
And you get the same behaviour.
ng-click="menuClicked(appModule.Name)"
In this example we need the ng-click to be bound to the method named menuClicked.
Generally we use {{}} when we want to evaluate the expression and when dealing with attributes we don't always need to use {{}} as they are in many cases evaluated behind the scenes.
Simple Tip A rule of thumb for when {{}} is needed is by thinking of it as a wrapper for a .ToString()-method. Does converting the expression to a string make sense, then so does using {{}}. (Any counter examples are very welcome)
Check the documentation. Avoid using using interpolation {{ }} when
the documentation says that the directive takes an expression, . In the case of ng-src, the documentaion explicitly says use {{ }}. If the attribute is not an AngularJS directive, use interpolation.
Erroneous
ng-class="{ 'selected' : selectedAppModule == '{{appModule.Name}}' }"
The above example is an example of mixing interpolation and Angular epressions.
Instead use:
ng-class="{ 'selected' : selectedAppModule == appModule.Name }"
From the Docs:
Why mixing interpolation and expressions is bad practice:
It increases the complexity of the markup
There is no guarantee that it works for every directive, because interpolation itself is a directive. If another directive accesses attribute data before interpolation has run, it will get the raw interpolation markup and not data.
It impacts performance, as interpolation adds another watcher to the scope.
Since this is not recommended usage, we do not test for this, and changes to AngularJS core may break your code.
— AngularJS Developer Guide - mixing interpolation and expressions
Update
Don't use interpolation with:
ng-selected, see AngularJS ng-selected Directive API Reference
ng-disabled, see AngularJS ng-disabled Directive API Reference
ng-required
ng-if
ng-show
ng-hide
ng-open
ng-value
ng-repeat
ng-options
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.
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
http://plnkr.co/edit/kL2uLPQu2vHHKIvRuLPp?p=preview
After a click on the button, from the controller i call the service who compiles the html and inject it in the body.
The html is compiled (see "Hello World" from $scope.name) against the $scope of the controller, but ngClick doesn't work.
Why?
How i can compile against the scope of the single phone (inside the ng-repeat?)?
I know that it's better to have a directive in this case, but i need to understand how it works because i need it for a dialog (see How can I get AngularJS binds working with a fancybox dialog?)
The two problems I see here both appear to stem from a misunderstanding of expressions and scope in angular.
When you use expressions in directives or bindings, such as in these two examples
<p>{{ phone.name }}</p>
<a ng-click="alert('angular')">Link</a>
they cannot access the JavaScript scope. Any identifiers used in these are coming from the angular scope, i.e. $scope. So
{{ phone.name }}
will display
$scope.phone.name
and
ng-click="alert('angular')"
will be trying to call
$scope.alert('angular')
Looking at your plunker, you are trying to use both phone and alert without assigning them to the scope. You can create a function to perform your alert by assigning it to your controller scope, but phone will be more difficult as it needs to be different every time.
You can either create a brand new scope for this and assign phone as I have done here, or you can pass the scope from inside your ng-repeat and compile your new element in this scope as I have done here.
The name alert is not defined on the $scope with which the template is compiled. If you do include an alert function, then ng-click does work:
$scope.alert = function (msg) { window.alert(msg); };
Demo
However, as you have yourself pointed out, this work is better suited for a directive than a service.