angular when to use curly brackets - javascript

In angular sometimes i have seen curly brackets but some times not.i search a lot but i couldn't find correct question
with curly bracket
ng-src="{{imageSrc}}
without curly bracket
ng-hide="imageSrc"
what i'm asking is why we cannot write ng-hide as
ng-hide="{{imageSrc}} // doesn't work anyway
why there is 2 different syntax for src and hide?

It simply depends on the way the directive you are using is "declared".
If the directive has the following declaration:
scope:{
ngHide: '='
}
then, you don't have to use double mustaches because the directive expects an object
If the directive is declared like the following :
scope:{
ngMin:'#'
}
then, it expects a value. If your value comes from a javascript variable, then you have to use curly braces to interpolate the string contained into your variable.
EDIT :
It has been a long time since I read angular source code.
I haven't found any source code to prove my point :
ngController which expects a string is declared like the following
var ngControllerDirective = [function() {
return {
restrict: 'A',
scope: true,
controller: '#',
priority: 500
};
}];
https://github.com/angular/angular.js/blob/master/src/ng/directive/ngController.js#L3
ngMaxLength
var maxlengthDirective = function() {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
var maxlength = -1;
attr.$observe('maxlength', function(value) {
var intVal = toInt(value);
maxlength = isNaN(intVal) ? -1 : intVal;
ctrl.$validate();
});
ctrl.$validators.maxlength = function(modelValue, viewValue) {
return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
};
}
};
};
https://github.com/angular/angular.js/blob/master/src/ng/directive/validators.js#L186

Beacuse they mean two different things.
When you use this:
<span data-ng-bind="test">
This means that angular will go to the scope and get value from there with test as key. So value will be $scope.test. But attribte value will be "test"
When you use
ng-src="{{imageSrc}}
then value will be evaluated and placed to the attribute. So value willbe $scope.imageSrc and attribute value will be $scope.imageSrc.
But. Not all tags can wait for evaluation. They think that value {{}} is correct and will not be changed. This cause to bad request. To fix this problem ng-src was created.

You can't write because both have different meaning see this link
,It's all about expression and template argument.
https://docs.angularjs.org/api/ng/directive/ngSrc
ng-src=template
You can find it in argument
https://docs.angularjs.org/api/ng/directive/ngHide
ng-hide=expression
You can also find it in argument

Related

AngularJS ([$parse:syntax] Syntax Error: Token ':' is an unexpected token at) when value is URL

I have created a directive as below:
angular.module('mymodule')
.directive('httpsimg', function () {
return {
restrict: 'E', //E = element, A = attribute, C = class, M = comment
//# reads the attribute value, = provides two-way binding, & works with functions
scope: {
style: '#',
width: '=',
height: '=',
'src': '='
},
template: '<img src="{{src}}" width="{{width}}" height="{{height}}" style="{{style}}" />',
link: function ($scope, element, attrs) {
var srcparts = $scope.src.replace('http','https');
$scope.src=srcparts;
} //DOM manipulation
}
});
then I use that in my Html code as below:
<httpsimg src="http://www.mytest.com/imgdir/logo.png" width="50" />
if inside my directive change src to one way binding(#) as below:
scope: {
style: '#',
width: '=',
height: '=',
'src': '#'
}
it works fine, I mean I can get value and there is no error. But if I change # to = to have two way binding I see the error
Also I found out that the issue is because of Url so if I change the url to a simple world without dot and slash it works fine.
= two way binding is to bind expressions, e.g. variables:
<httpsimg src="foo">
Where foo is a scope variable. https://… is most certainly not a scope variable, and is invalid syntax for a variable or expression. If you use = binding, you need to supply a literal value as expression literal:
<httpsimg src="'http://www.mytest.com/imgdir/logo.png'">
^ ^
Just as you would write a string literal in Javascript. Perhaps to illustrate it even better:
<httpsimg src="'http://' + 'www.mytest.com/imgdir/logo.png'">
Since you're not binding a variable expression, there's no point in using two way binding. If you just want to pass a literal value, that's exactly what # is for.

AngularJS - When should we avoid using {{}}? [duplicate]

In angular sometimes i have seen curly brackets but some times not.i search a lot but i couldn't find correct question
with curly bracket
ng-src="{{imageSrc}}
without curly bracket
ng-hide="imageSrc"
what i'm asking is why we cannot write ng-hide as
ng-hide="{{imageSrc}} // doesn't work anyway
why there is 2 different syntax for src and hide?
It simply depends on the way the directive you are using is "declared".
If the directive has the following declaration:
scope:{
ngHide: '='
}
then, you don't have to use double mustaches because the directive expects an object
If the directive is declared like the following :
scope:{
ngMin:'#'
}
then, it expects a value. If your value comes from a javascript variable, then you have to use curly braces to interpolate the string contained into your variable.
EDIT :
It has been a long time since I read angular source code.
I haven't found any source code to prove my point :
ngController which expects a string is declared like the following
var ngControllerDirective = [function() {
return {
restrict: 'A',
scope: true,
controller: '#',
priority: 500
};
}];
https://github.com/angular/angular.js/blob/master/src/ng/directive/ngController.js#L3
ngMaxLength
var maxlengthDirective = function() {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
var maxlength = -1;
attr.$observe('maxlength', function(value) {
var intVal = toInt(value);
maxlength = isNaN(intVal) ? -1 : intVal;
ctrl.$validate();
});
ctrl.$validators.maxlength = function(modelValue, viewValue) {
return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
};
}
};
};
https://github.com/angular/angular.js/blob/master/src/ng/directive/validators.js#L186
Beacuse they mean two different things.
When you use this:
<span data-ng-bind="test">
This means that angular will go to the scope and get value from there with test as key. So value will be $scope.test. But attribte value will be "test"
When you use
ng-src="{{imageSrc}}
then value will be evaluated and placed to the attribute. So value willbe $scope.imageSrc and attribute value will be $scope.imageSrc.
But. Not all tags can wait for evaluation. They think that value {{}} is correct and will not be changed. This cause to bad request. To fix this problem ng-src was created.
You can't write because both have different meaning see this link
,It's all about expression and template argument.
https://docs.angularjs.org/api/ng/directive/ngSrc
ng-src=template
You can find it in argument
https://docs.angularjs.org/api/ng/directive/ngHide
ng-hide=expression
You can also find it in argument

Evaluating expression with $parse in directive inside an ng-repeat in Angular 1.4.5

I'm trying to use $parse the expression of an attribute of a directive within an ng-repeat.
Here's a simple HTML:
<body ng-app="hello" ng-controller="control">
<div ng-repeat="a in array" my-dir="a.one == 1"></div>
</body>
and the Angular directive:
angular.module('hello', [])
.controller('control', function($scope){
$scope.array = [{
one: 1,
two: 2
},
{
one: 3,
two: 4
}];
})
.directive('myDir', function($parse){
return {
restrict: 'A',
link: function(scope, elem, attrs){
var hash = $parse(attrs.myDiv);
// I would like a way of evaluating this expression
// without having to use things like my-dir="array[$index].item == 1"
// just like one would do with other angular directives.
console.log(hash(scope)); // This is undefined, because a.one can not be found in scope.
},
};
});
The issue with doing this is that $parse is using scope to look for the a.one property and obviously that doesn't exist.
I could do my-dir="array[$index].one == 1" but it's not intuitive for the users of the directive (they will have to consider the scope in which they're calling the directive).
There is typo - myDiv instead myDir.
http://plnkr.co/edit/rwoUXjxmvmdTp3OIE4Yo?p=preview

Passing format string to a directive and interpolating it

I want to pass a format string to a directive and make the directive interpolate it with an object. The problem is that if I use curly brackets Angular tries to interpolate the string before the directive is even created. If I escape the curly brackets, Angular isn't showing the values of the object (the string isn't interpolated correctly).
How can I pass a format string to a directive?
This is my demo code template:
<div test-directive item-text="{{ x }} - {{ y }}"></div>
Angular app/directive:
var app = angular.module('plunker', ["test-directive"]);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
var dir = angular.module('test-directive', []);
dir.directive("testDirective", ['$interpolate', function($interpolate) {
return {
template: "<div>{{ text }}</div>",
link: function ($scope, element, attrs) {
var obj = {
x: 6,
y: 9
};
$scope.text = $interpolate(attrs.itemText)( obj );
}
}
}]);
Demo: http://plnkr.co/edit/vUVVuLVBptEmUcv3y7o4?p=preview
Edit:
Applying #Lucas's annswer to my original problem isn't solving the issue. For some reason the attr gets wiped, even if I'm not erasing it anywhere.
Please check the line 301: http://plnkr.co/edit/6bjW35D3W1dTGQz9kNSn?p=preview
Note that itemLabel isn't changed anywhere.
The way to do it is to change it as
$scope.text = $interpolate(element.attr(attrs.$attr.itemText))( obj );
http://plnkr.co/edit/ctPalH7Szqqnpit5t0On?p=preview
Not sure what the actual usecase is, but from your example, you don't seem to need interpolation (so you shouldn't use it and avoid the overhead).
What you (seem to) need, is to evaluate a expression in some context (e.g. obj).
One way of doing it, is to use Scope's $eval() method; e.g.:
<div test-directive item-text="x+' - '+y" ...
...
link: function postLink(scope, elem, attrs) {
var obj = {x: 6, y: 9};
scope.text = scope.$eval(attrs.itemText, obl);
}
Updated Plnkr
EDIT: Admitedly, this beats the purpose of simplicity, so here is another approach using a helper service that replaces the start-/end-symbols and interpolates: Demo

Angular directive: return object from collection

I try to implement a custom directive that list all available plans and allow user to choose one.
When plan is selected, the parent scope must be updated with selected object (it is linked with two way binding)
It should behave exactly the same as angular ng-options does, but I have hard time fighting the Javascript object replacement.
What I have right now works (with some clutter removed):
In HTML:
<choose-plan ng-model='plan' plans='plans' choose-plan-title='Premium plans' />
In Controller:
$scope.plan = {}
Plans.get (resource) ->
$scope.plans = resource.plans
return
It does not work with $scope.plan = undefined obviously, but I look for the solution that does.
In JS (Coffeescript) directive:
angular.module('tv-dashboard').directive 'choosePlan', [
'lodash'
(lodash) ->
'use strict'
restrict: 'E'
scope:
plan: '=ngModel'
plan_collection: '=plans'
title: '#choosePlanTitle'
link: (scope, element, attrs) ->
# HACK two way binding does not replace the value. Investigate
scope.choosePlan = (available_plan) ->
# scope.plan = available_plan # Does NOT update the parent scope binded ng-model
angular.copy available_plan, scope.plan
return
scope.isSelected = (available_plan) ->
return unless available_plan?
available_plan.id == scope.plan.id
presentPlans = (collection) ->
angular.copy(collection).map (resource_plan) ->
price_parts = resource_plan.interval_price.split '.'
resource_plan['integer_price'] = price_parts[0]
resource_plan['decimal_price'] = price_parts[1]
resource_plan
chooseDefaultPlan = (collection) ->
scope.choosePlan lodash.last collection
unWatchCollection = scope.$watch 'plan_collection', (collection) ->
return unless collection? && collection.length > 0
scope.plans = presentPlans collection
chooseDefaultPlan scope.plans
unWatchCollection()
return
return
templateUrl: 'form/choose_plan.html'
]
But if you take a look on the isSelected function, you notice that i have to compare objects using the id field. Comparison by == (=== in JS) does not return true.
Is there a way I can replace the parent scope plan without dancing around with angular.copy available_plan, scope.plan and forced to use the id field comparison?
You should use require: 'ngModel' to inject the model attached to the element or its parent element on which the directive is bound to. Here is a demo.
One way to solve this is to share an object and write into its properties
$scope.plan = {
// value: set in directive
}
scope.choosePlan = (available_plan) ->
scope.plan.value = available_plan
return
scope.isSelected = (available_plan) ->
return unless available_plan?
available_plan == scope.plan.value
Your code as jsfiddle: http://jsfiddle.net/ht6tmhfu/1/
Fixed code as jsfiddle: http://jsfiddle.net/ht6tmhfu/3/

Categories

Resources