Actually I'm confused between when to use {{ }} when using angular directives and when to not to use {{ }}
For example:
<div data-ng-init="isHidden=false">
<div data-ng-show="isHidden">
...
</div>
</div>
and
<div data-ng-init="isHidden=false">
<div data-ng-show="{{isHidden}}">
...
</div>
</div>
I'm confused between these syntax ? What are the differences between those? And when to use what? Thanks in advance :)
There is no difference except the "look" u need to use the {{value}} syntax in case you want to write data anywhere in your html body
<div>{{value}}</div>
It's all explained here: Difference between double and single curly brace in angular JS?
For quick answer:
{{}} are Angular expressions and come quite handy when you wish to
write stuff to HTML
Don't use these at a place that is already an expression!
For instance, the directive ngClick treats anything written in between
the quotes as an expression
<div data-ng-init="isHidden=false">
<div data-ng-show="isHidden">
...
</div>
</div>
In This Situation data-ng-show = false , Takes From data-ng-init As Statically,if You Have Given true Then It Returns True .
But Here
<div data-ng-init="isHidden=false">
<div data-ng-show="{{isHidden}}">
...
</div>
{{}} Called As Expressions In Angular One Of The Most Important Concept
It Directly Evaluate If isHidden = true Or False Based On Any Condition Written In Your App.js File .
Example:
<div data-ng-init="isHidden=YourVariable">
<div data-ng-show="{{isHidden}}">
...
</div>
if(YourVariable == true){
Do Somthing
}
else{
Do Something
}
If you are asking when to use {{}} while assigning value to a attribute and when not.
It depends on the binding types of directive. '#' or '='
So here, you have to use:
data-ng-show="{{isHidden}}" if the binding type of directive scope data-ng-show is '#', that mean the data-ng-show will be expecting a string value. So in this case if you keep data-ng-show="isHidden" it will take data-ng-show's value as 'isHidden', but data-ng-show="{{isHidden}}" will take the value of the $scope.isHidden and assign to data-ng-show.
Now if the binding type of directive scope data-ng-show is '=', that means the data-ng-show will be expecting a value from a scope. So data-ng-show="isHidden" itself will take the value of he $scope.isHidden and assign to data-ng-show.
Note: all the default HTML attributes expect a string so you have to use {{}} for default HTML attributes.
There is no as such major difference unless one uses them in the DOM for the value.
When one uses the following:
<div data-ng-show="isHidden">
then, expression is evaluated and on the basis of it respective value, the ng-show either hides or displays the div. But the value of the isHidden cannot be seen, when one inspects the HTML using the browser developer tool.
When one uses the following:
<div data-ng-show="{{isHidden}}">
In this case, the value of the isHidden can be seen from the developer tools, and the rest of the expression does evaluates the same as that of (1).
Related
I'm attempting to use Angular directives to create custom input field types. For example, I have a type called "duration" which draws three separate hours, minutes, and seconds fields. I'm trying to use the directive as an attribute of an input element, and the directive replaces the input element.
For example, in the following code:
<input duration>
Would be rendered as a <div> with several inputs inside of it, and the original input would be out of the picture.
I'm running an ngRepeat loop through several form fields of different types, including duration. I'd like to find a way that only requires me to put one input in the HTML, with the duration attribute applied only if the field is supposed to be of duration type. I tried the following:
<div ng-repeat="field in fields">
<input type='{{field}}' ng-attr-duration="field==='duration'">
</div>
The problem with that code is that every element is rendered as duration because ng-attr-duration gets evaluated to duration='false' when the field is not duration, which triggers my directive.
Is there a way for me to apply the directive conditionally without having to define multiple <input>s to reduce redundancy in my code?
Take a look at what the directive docs say about ng-attr:
When using ngAttr, the allOrNothing flag of $interpolate is used, so if any expression in the interpolated string results in undefined, the attribute is removed and not added to the element.
Note that you need to be using curly braces so Angular will interpolate the expression. And, if your expression has an undefined term in it, the attribute won't be added.
How about something like this:
<div ng-repeat="field in fields">
<input type='{{field}}' ng-attr-duration="{{field==='duration' ? true : undefined}}">
</div>
The true in the ternary expression can be whatever you want, just not undefined.
What i can think of you can use condition if-else of ng-switch
<div ng-repeat="field in fields">
<div ng-switch on="field">
<input ng-switch-when="true" type='{{field}}' ng-attr-duration="field==='duration'">
<input ng-switch-default="true" type='{{field}}'>
</div>
</div>
It will also maintain readability of code.
A few examples:
<img ng-src="{{some.thing}}">
<button ng-class="{active: data.checkThing()}">
<div ng-repeat="thing in things"></div>
As someone learning Angular, this is highly confusing. I never know whether I need { } or {{ }} or neither. Can someone explain what these mean and when to use which?
{{}}:
You use {{}} when you want to evaluate an expression, such as:
$scope variables, e.g:
$scope.myVar = "test";
And in HTML:
<div>{{myVar}}</div> will result in <div>test</div>
Basic calculations, such as: {{ 1 + 1 }}, {{ myVar + " add on" }}
Result of a function on the controller so it can be displayed
Etc..
{}:
Condition, used directives such as ng-class/ng-style. It means the left-hand side will be in effect if the expression on the right-hand side evaluates to true. The following expression means that the button will have the class "active", if data.checkThing() evaluates to true:
<button ng-class="{active: data.checkThing()}">
Neither:
When you want to address objects, like you do in the ng-repeat, you have to iterate on objects, like you do in C#/Javascript/etc..
So because you're working with the objects themselves, you don't need to evaluate anything, and simply address them as they are variables on your scope:
<div ng-repeat="item in items">...</div>
If you are using directives for instance, and you have an isolated scope and want to bind a variable in that scope to an instance, you will use no brackets:
<div myDirective item="myItem"></div>
And in the directive you can have a reference to that item by doing:
angular.module('app').directive('my-directive', function () {
return {
scope: {
item: "=" //references the object that exists in
//attribute `item` on the DOM element the directive is on
}
}
});
Single braces are used for directives accepting an object parameter, which may be more than one value. It is analogous to a JSON object.
For example:
ng-class="{active: true, highlight:true}"
Double braces are used to represent an AngularJS expression.
For example
<div>{{ item.name }}<div> (evaluates to string)
<div>{{ item.name == "Sam" }}<div> (evaluates to boolean)
No braces are used for directives accepting a single value argument.
For example, data binding:
ng-model="people.jim"
{active:data.checkThing()} signifies object creation-----you are constructing and actually passing an object to ng-class directive in the angularjs library.
{{some.thing}} signifies 2-way data binding with the actual ng-model that reflects the changes in model data as and when it occurs.
Hope it helps.If this answers your queries kindly accept this as answer or comment back if not.
This question already has answers here:
AngularJS : Why ng-bind is better than {{}} in angular?
(12 answers)
Closed 1 year ago.
Is there any difference between
{{ }} and ng-bind in angular.
I am quite new to Angular. I started with using {{ }} and then in the documentation i find ng-bind. I think they do the same work but then why an extra directive, if not then please tell the difference.
There is some hint in the official docs: https://docs.angularjs.org/api/ng/directive/ngBind
Typically, you don't use ngBind directly, but instead you use the
double curly markup like {{ expression }} which is similar but less
verbose.
It is preferable to use ngBind instead of {{ expression }} if a
template is momentarily displayed by the browser in its raw state
before Angular compiles it. Since ngBind is an element attribute, it
makes the bindings invisible to the user while the page is loading.
The most obvious difference between them is Flash of Unstyled content while using {{ ... }}.
However, there is a more subtle difference between the two if the object you pass to {{ obj }} and ng-bind="obj" is not a string.
From https://stackoverflow.com/a/19744728/987185 :
Depending on whether you use {{ ... }} or ng-bind syntax, the
.toJSON and the .toString function on your object will be called
to determine its representation.
In addition to the above mentioned answers,
Performance Issues with Interpolation:
As explained in this thread better,
ng-bind is a directive and will place a watcher on the passed variable. So the ng-bind will only apply when the passed value does actually change.
The brackets on the other hand will be dirty checked and refreshed in every $digest, even if it's not necessary.
{{ }} can flash when the page is loading, ng-bind hides the expression properly until it is displayed correctly.
In AngularJs ng-bind directive works as alternative to the interpolation directive {{ }}. By inserting an ng-bind attribute to HTML element we can insert AngularJS data into it.
Here is an example:
<div ng-controller="DemoController" >
<span ng-bind="demoData.doThis()"></span>
</div>
The Key Difference is ng-bind attribute wont show Html content on page loading, where as interpolation Directive show as flash of content without style while page loading.
Another difference is the way ng-bind and interpolation display the data.
ng-bind calls the toString() method, whereas interpolation uses a custom "stringify" function.
Example
<div ng-controller="showClockCtrl">
<p>The current time is {{currentDateTime}}.</p>
<p>The current time is <span ng-bind="currentDateTime"></span>.</p>
</div>
<div ng-controller="showClockCtrl">
<p>MyObject is {{myObject}}</p>
<p>MyObject is <span ng-bind="myObject"></span></p>
</div>
<script>
var showClockCtrl = function ($scope) {
$scope.currentDateTime = new Date();
$scope.myObject = {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3'
}
};
</script>
Output
The current time is "2017-11-18T15:09:59.429Z".
The current time is Sat Nov 18 2017 10:09:59 GMT-0500 (EST).
MyObject is {"key1":"value1","key2":"value2","key3":"value3"}
MyObject is [object Object]
Sometimes when we load our application in the browser , we can notice flashing content for some milliseconds before {{ name }} is resolved and data is loaded.
This happens because the template is loaded before AngularJS had a chance to go in and compile the elements. To resolve this issue, you can use ng-cloak directive.
In the first approach(i.e. {{}}), AngularJS evaluates the expression then replaces it with some value which sometime be left with the flashing double curly brackets but ng-bind saves this time by informing AngularJS to put the contents of the expression within the element itself.
Note:
{{}} sometimes cause performance issue if we have thousand of bindings in our page.In these scenario's, we should go with ng-bind.
Interpolation is only used for a Read-only purpose and you cannot assign a value to inside the mustache bracket to a variable that has been declared inside the Typescript file.
The basic difference between them is that ng-bind should always be used inside the element <> but Interpolation directive can be used inside, outside and between the elements.
Not an answer, but ng-bind is easily exchangable by ng-bind-html, which puts actual html text inside the element instead of pure text.
Since I was wondering for (ok, just) minutes, I add it here as well. My problem was, text-DOM explorer shows the same output.
<div ng-if="question.type =='options'" ng-repeat="option in question.options" >
<ion-radio name="{{$parent.question.id}}"
ng-model="$parent.question.answer"
required ng-value="option.id"
ng-class="{'has-custom-error':submitted && questionForm.{{$parent.question.id}}.$invalid,
'has-custom-success':questionForm.{{$parent.question.id}}.$valid }"
>
{{option.text}}
</ion-radio>
</div>
I have to add has-custom-error on user submitting the form without selecting the option.That is form is not valid but the ng-classis not getting evaluated.
The demo code is over here:http://plnkr.co/edit/FwjoCTYONvi3BoFHNKFK?p=preview
I don't think it is possible to use {{ }} expressions on a ng-class expression. You should be able to use it like this questionForm[$parent.question.id]
Also I never got ng-class working with classes with - between the parts, only CamelCase like hasCustomError. So {hasCustomError: questionForm.$invalid} should work.
Have you considered using the styleClass ng-invalid-required that is already used by angular for your styling? It is usually a lot cleaner, since there is no need for all the ng-class expressions
There is at least one problem with your code. You must not use interpolation {{}} within your ng-class attribute. Here is the correct syntax:
ng-class="{'has-custom-error':submitted && questionForm[$parent.question.id].$invalid, 'has-custom-success':questionForm[$parent.question.id].$valid }"
When you are inside an Angular expression, you don't need the mustache braces. So your code should be:
<div ng-if="question.type =='options'" ng-repeat="option in question.options">
<ion-radio name="{{$parent.question.id}}"
ng-model="$parent.question.answer"
required ng-value="option.id"
ng-class="{'has-custom-error':submitted && questionForm[$parent.question.id].$invalid,
'has-custom-success':questionForm[$parent.question.id].$valid }">
{{option.text}}
</ion-radio>
</div>
The variable form a.b has been replaced by the indexer form a["b"] so that it is evaluated correctly.
You can't use double-mustached expressions ({{ ... }}) inside expressions. The ng-class value is already an expression of type object, so you're supposed to use JavaScript syntax inside this attribute:
ng-class="{'has-custom-error': submitted && questionForm[$parent.question.id].$invalid,
'has-custom-success': questionForm[$parent.question.id].$valid }"
The use of $parent is also unecessary. BTW, you're not using it for your ng-repeat expression:
ng-repeat="option in question.options"
So you should simply use question instead of $parent.question: the scope of the ng-repeat block inherits from its parent scope, and the question is thus available through inheritance.
Note that, playing with your plunkr, it seems like the ion-radio directive that you're using doesn't correctly set the name attribute of the input it generates. This is probably why the CSS classes don't appear.
ng-form is the solution to my problem.But the problem that I am facing is in the name attribute of my ion-radio directive. For radio hence i used angular ng-invalid-required.And for other html tag i used ng-form.$invalid
What is the reasoning behind setting ngIf priority (600) higher than {{ }}(100)? Shouldn't it have a lower priority to allow {{ }} inside ng-if attribute value?
I would like to have a condition inside a $scope variable:
Controller:
app.controller('MainCtrl', function($scope, $http, $parse) {
$scope.hide = "check === 'hidden'";
$scope.parsecond = function (cond) {
return $parse(cond)($scope);
};
});
Template:
<body ng-controller="MainCtrl">
<div ng-if="!{{hide}}">funky ng-if div</div>
<div ng-hide="{{hide}}">ng-hide div</div>
<div ng-if="!parsecond(hide)">ng-if div</div>
<input type="input" ng-model="check" />
</body>
ng-hide works fine since it parses the contents of the hide variable and returns "check === 'hidden'" which then gets evaluated by ng-hide directive.
But ng-if tries to evaluate {{hide}} before interpolate has had a chance to parse the string hence ng-if throws an exception.
The only solution I've found is call a function that basically does the job of the interpolate directive and returns the parsed content.
Plnkr showing the issue: link
EDIT:
After reading documentation I've found better way of doing it without the need of a custom method on the $scope since angularjs has already a method that parses a variable against its current $scope ($eval).
So my solution would be:
<body ng-controller="MainCtrl">
<div ng-if="!$eval(hide)">funky ng-if div</div>
<div ng-hide="{{hide}}">ng-hide div</div>
<div ng-if="!parsecond(hide)">ng-if div</div>
<input type="input" ng-model="check" />
</body>
Updated plnkr: link
Although this still doesn't explain why ngIf has higher priority.
EDIT 2:
Just so people understand that it's not the same:
For example:
Controller:
$scope.value = "hi";
$scope.condition = "value === 'bye'";
HTML:
<div ng-hide="condition"></div> <!--This will be evaluated to true since !!"value ==='bye'" = true. -->
<div ng-hide="{{condition}}"></div> <!--This will be evaluated to false since value !== 'bye' = false -->
<div ng-if="condition"></div> <!--This will be evaluated to true since !!"value === 'bye'" = true. -->
<div ng-if="{{condition}}"></div> <!--This will give an exception since ngIf directive ran before interpolation directive in the $compile step. -->
<div ng-if="$eval(condition)"></div> <!--This will be evaluated to false since value !== 'bye' = false. -->
My conclusion is that it safer to use $parse if you want the directive to evaluate/set a watch in the string rather than in the property on the scope. Although it's true that I could use {{ }} for ng-hide/ng-show or any directive that has a lower priority than 100 but I'm guessing it's not safe since I'm depending in the compiling order and it's not 100% clear that it won't change in future patches.
ng-if expects its value to be an angular expression - under the hood it just makes use of $scope.$watch. Therefore, if you want to condition including content of ng-if on some variable defined on the scope (let say: scope.hide), you put ng-if="hide" in your mark-up. No double curly braces here.
Now back to your question: it is true that ng-if has priority of 600, but $interpolate is angular's service - not a directive. As such $interpolate does not define priority. Where did you get 100 from?
UPDATE
You can always condition including content of ng-if on some function (let say scope.conditionFn) by putting in your mark-up: ng-if="conditionFn()".
UPDATE 2
I updated your PLNKR to make it working. The inconsistencies between ng-if and ng-hide in your plunker had nothing to do with priority of interpolation taking place in $compile.
UPDATE 3
It seems that you are right that order of interpolation plays a role here, but... I really do not see any good reason to interpolate inside of angular's expression. The reason why ng-if has relatively high priority is that it removes/adds transcluded content from/to DOM, whereas ng-hide just shows/hides the transcluded content. I think it is a pure coincidence that one directive seems to work and the other not. But if you do not use unnecessary, superfluous tricks, both do work as intended, what my plunker shows.
To understand why it's doing that, observe the console of this sample here, where the custom directive, similar to ngIf, sits this time at priority 0. The directive is meant to remove the element and, without waiting, to add it back. You'll see however an error which is caused by the attempt to set the attributes back onto what remained due to transclude: elementwhich, in this case and that of the ngIf, is just a marker for where the element has been, in the form of a comment.
To avoid that from happening, ngIf terminates the process early by having a higher priority, terminal:true and by monitoring directly its expression grabbed straight from $tAttrs. Interpolation will execute, but this is done at a later stage, by calling the transclusion function the moment the ngIf expression turns true, on a clone of the original element, now under its control. The new element will show nice and dandy under the comment element.
Here is the same sample but fixed. The error condition is avoided.