AngularJS template binding to object - angularjs

As we all know AngularJS uses the simplest form of $watch when we bind to variable in template like this {{ $ctrl.obj }}.
It should compare value of $ctrl.obj by reference, but if I mutate $ctrl.obj the change is reflected in view. The reference doesn't changed, so why?

When we use brackets ({{}}) angular does not use any watch (ers) for detecting changes on the expression placed inside them. Instead this expression is dirty checked and refreshed in every $digest cycle, even if it is not necessary.
See this post: AngularJS : Why ng-bind is better than {{}} in angular?

Related

Angular ng-init assignment inside of a template

I need to initialize an object in my view and assign a reference to it.
Can I achieve this by using ng-init? Is it an assignment by value or reference?
<ANY ng-init="objA = objB"> ... </ANY>
Any help will be appreciated!
Move assignment to controller init() method.
ng-init is directive that have a very lot of side effects and hardly to trace it down. For example: when you use ng-init in directive template for creating/editing item and you assign some model value in it - you will achieve problem with editing that actually should use already existing value.
As well side effect of it is executing few times when you add ng-if.
Usage ng-init in templates are your own risk.
Right way: controller data should be defined at start of module - in any case any view started in order: $state -> resolve() -> controller -> template -> directive. It's not a good idea to fool yourself with not existing data until it will be created by magic.
In case of repeaters when you have for example empty {} and you need to display it like possibility to fill yet empty input, as I mentioned - you need to run function on init that can define empty or extend existing model by passing actual model.

Angular to use ng-bind or {{}}?

Ok so I have read in several places that using ng-bind is better for performance.
But looking at these jsperfs makes me a bit confused :)
https://jsperf.com/angular-bind-vs-brackets
http://jsperf.com/ng-bind-vs-brackets/14
So what is the best way when it comes to performance?
{{::value}}
or
<div ng-bind="value"></div>
You should use ng-bind. Its a directive that puts a watcher on that variable so it only updates when the variable changes, while {{}} will dirty-check and refreshes the variable in every digest cycle.
See this answer
Also :: is called "bindonce" and will only set the variable once and wont update afterwards.
e: The jsperf tests binding from variable to html (I think), while the linked answer focuses on the behaviour afterwards. If you got 100 curly braces and you update one model, every {{}} gets updated. While ng-bind only updates if the variable itself changes, because it creates a watcher for that variable.
When it comes to one-time-binding, then you should also use the colon in ng-bind as well.
So use ng-bind="::value"
for filter or expressions you have to use brackets: ng-bind="::(value | number:2)"
use ng-bind is better . If javascript files is not loaded , {{ }} will show on the page .

Angular - listening to binding changes in directive executed by controller

I'm attempting to watch a custom directive attribute value inside the directive. This value is a variable binding from a controller. The variable is a boolean and is updated via an action in the controller.
I can see that I'm updating this value in the controller action correctly through console.logs but I cannot seem to get the directive to watch for changes to this value. As I said, this value is the value of a custom directive: auto-focus="{{isFocused}}"
I've created a simple plunker to show my problem, any help would be great.
Angular - listening to binding changes in directive executed by controller
http://plnkr.co/edit/QwwFCQPN7L7nwuthH0CJ?p=preview
In order to watch for changes in an attribute that has an interpolation you'll need to use $attrib.$observe instead of $scope.$watch. This is described in the angularjs documentation: http://docs.angularjs.org/api/ng/service/$compile#Attributes
Also, you're comparing focusVal to true, but you're passing it as a string through the attribute. Here's an updated plunker: http://plnkr.co/edit/e8ZaBM?p=preview
In the focus-on directive, you have:
focus-on="{{isFocused}}"
This makes your directive actually watch what isFocus contains - which is "false"
Change it to:
focus-on="ifFocused"
Then your code works fine.

Two way databinding not working on directive

I have a directive and I want to change the ng-model value given with this directive...
I'm setting scope: {ngModel: '='} and I'm changing the ngModel value (on click event) inside my directive but I can't see changes on my external/original object.
This plunker shows the problem...
There are a few things wrong here, all of them common mistakes.
Event handlers registered through jQuery using $(...).on(...) will be executed outside of angular context, so angular will not know when things have updated. To address this, you must wrap the contents in a scope.$apply call like so
$('#aaa').on('click', function() {
_scope.$apply(function(){
_scope.ngModel = 'Other Value';
updateTemplate();
});
});
This will update the binding to the input with ng-model. In fact you can avoid having to do this by using the ng-click directive.
With angular, you do not need to update templates like this yourself using .html(...). Binding is one of the major features of the framework. Instead of having the update function, you can use interpolation by putting an expression inside of {{ ... }} and your DOM will be updated when your model is. For example when defining the directive you can use
template: '<div id="aaa">{{ngModel}}</div>'
to set your template and {{ngModel}} will show the current value of ngModel.
ngModel is not just any attribute, it is a powerful directive. If you need your own directive to be able to declare the current model valid or invalid, or to interact with forms then you should use this through the require property on your controller (see here).
If you don't need those features then you should be calling your attribute something different to avoid conflict.
I have updated the plunker to include these points.

Directive ng-show alternatives

I have a control that should display breadcrumb navigation. It needs data (route & title) to display the navigation correctly. Data is taken from scope and used inside a directive.
What causes my problems is that I use a localization directive in the control that should translate the title. And this localization directive is called even when expression in ng-show is evaluated to false. Then the translation in localization directive ends with exception because it tries to translate incorrect string (see 'localize' directive in http://jsfiddle.net/F97wn/7/).
That seems quite weird. I would expect that if something sets whether the inner content should be visible or hidden, then it is evaluated first and then the inner content..
Ok, then I found that ng-show only sets some css attribute, so it's quite useless for me.
The question is: How should I solve the problem - what to use instead of the ng-show?
An example is at http://jsfiddle.net/F97wn/7/
You could use ngSwitch instead with the on part set to "toshow()" and the inner ng-switch-when="true" part to have your custom directive inside that area. This will then not execute the custom directive if the value of toshow is not true.
If the directive is throwing an exception, more information should probably be passed to the directive, in one of the following ways, so that the directive can decide if it has the required information to do what it needs to do:
attribute data -- e.g., localize="..." show-me="..."
something defined on the scope associated with ctrl -- e.g., $scope.showMe. The directive scope will have access to this property as scope.showMe, based on the way you currently have the directive defined.
or inject a service (that has the data) into the directive -- e.g., directive('localize', function(myShowMeService) { ... }
You might also want to look into <ng-if>. The ngIf directive removes and recreates a portion of the DOM tree (HTML) conditionally based on "falsy" and "truthy" values evaluated within an expression. It might be more intuitive than <ng-show> for your needs.
However, it is currently only available in the unstable version of AngularJS. If you can use that version of AngularJS you can find more information about it here.

Resources