Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between & vs @ and = in angularJS

@ allows a value defined on the directive attribute to be passed to the directive's isolate scope. The value could be a simple string value (myattr="hello") or it could be an AngularJS interpolated string with embedded expressions (myattr="my_{{helloText}}"). Think of it as "one-way" communication from the parent scope into the child directive. John Lindquist has a series of short screencasts explaining each of these. Screencast on @ is here: https://egghead.io/lessons/angularjs-isolate-scope-attribute-binding

& allows the directive's isolate scope to pass values into the parent scope for evaluation in the expression defined in the attribute. Note that the directive attribute is implicitly an expression and does not use double curly brace expression syntax. This one is tougher to explain in text. Screencast on & is here: https://egghead.io/lessons/angularjs-isolate-scope-expression-binding

= sets up a two-way binding expression between the directive's isolate scope and the parent scope. Changes in the child scope are propagated to the parent and vice-versa. Think of = as a combination of @ and &. Screencast on = is here: https://egghead.io/lessons/angularjs-isolate-scope-two-way-binding

And finally here is a screencast that shows all three used together in a single view: https://egghead.io/lessons/angularjs-isolate-scope-review


I would like to explain the concepts from the perspective of JavaScript prototype inheritance. Hopefully help to understand.

There are three options to define the scope of a directive:

  1. scope: false: Angular default. The directive's scope is exactly the one of its parent scope (parentScope).
  2. scope: true: Angular creates a scope for this directive. The scope prototypically inherits from parentScope.
  3. scope: {...}: isolated scope is explained below.

Specifying scope: {...} defines an isolatedScope. An isolatedScope does not inherit properties from parentScope, although isolatedScope.$parent === parentScope. It is defined through:

app.directive("myDirective", function() {
    return {
        scope: {
            ... // defining scope means that 'no inheritance from parent'.
        },
    }
})

isolatedScope does not have direct access to parentScope. But sometimes the directive needs to communicate with the parentScope. They communicate through @, = and &. The topic about using symbols @, = and & are talking about scenarios using isolatedScope.

It is usually used for some common components shared by different pages, like Modals. An isolated scope prevents polluting the global scope and is easy to share among pages.

Here is a basic directive: http://jsfiddle.net/7t984sf9/5/. An image to illustrate is:

enter image description here

@: one-way binding

@ simply passes the property from parentScope to isolatedScope. It is called one-way binding, which means you cannot modify the value of parentScope properties. If you are familiar with JavaScript inheritance, you can understand these two scenarios easily:

  • If the binding property is a primitive type, like interpolatedProp in the example: you can modify interpolatedProp, but parentProp1 would not be changed. However, if you change the value of parentProp1, interpolatedProp will be overwritten with the new value (when angular $digest).

  • If the binding property is some object, like parentObj: since the one passed to isolatedScope is a reference, modifying the value will trigger this error:

    TypeError: Cannot assign to read only property 'x' of {"x":1,"y":2}

=: two-way binding

= is called two-way binding, which means any modification in childScope will also update the value in parentScope, and vice versa. This rule works for both primitives and objects. If you change the binding type of parentObj to be =, you will find that you can modify the value of parentObj.x. A typical example is ngModel.

&: function binding

& allows the directive to call some parentScope function and pass in some value from the directive. For example, check JSFiddle: & in directive scope.

Define a clickable template in the directive like:

<div ng-click="vm.onCheck({valueFromDirective: vm.value + ' is from the directive'})">

And use the directive like:

<div my-checkbox value="vm.myValue" on-check="vm.myFunction(valueFromDirective)"></div>

The variable valueFromDirective is passed from the directive to the parent controller through {valueFromDirective: ....

Reference: Understanding Scopes


Not my fiddle, but http://jsfiddle.net/maxisam/QrCXh/ shows the difference. The key piece is:

           scope:{
            /* NOTE: Normally I would set my attributes and bindings
            to be the same name but I wanted to delineate between 
            parent and isolated scope. */                
            isolatedAttributeFoo:'@attributeFoo',
            isolatedBindingFoo:'=bindingFoo',
            isolatedExpressionFoo:'&'
        }        

@: one-way binding

=: two-way binding

&: function binding