Angular JS Magazine

marți, 7 octombrie 2014

Custom Directive - One-Way Binding for an Isolated Scope

In Custom Directive - Creating Simplest Isolated Scope you saw how to create a simple isolated scope for each instance of a custom directive. That blocks the scopes of the instances of directive to inherit objects and properties from the controller scope. Since we don't inherit any data values from the controller scope, we have a totally useless isolated scope. But, Angluar allows us to define the interractions between controller scope and the directive as bellow - this violates the isolation layer in a controlled manner:

Note:One-way bindings on isolated scopes are always evaluated as strings and the custom directive doesn't have access to the data value in the controller scope. Arrays are accesed via two-way bindings, even if they don't need access to the data value in the controller scope.

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script src="../angular/angular.min.js"></script>
    <style type="text/css">
    </style>
    <script type="text/ng-template" id="playerTemplate">
        <div class="panel-body">
            <p>Players:
                {{playerslocal}}
            </p>
            <p>Court: {{courtlocal}}</p>
            <p>Injury: {{injurylocal}}</p>
        </div>
    </script>
    <script>
        angular.module("appModule", [])
                .controller("appCtrl", function ($scope) {
                    $scope.injury = "No";
                    $scope.court = {name: "Philippe Chatrier"};
                    $scope.players = [
                        { name: 'Nadal, Rafael (ESP)', rank: 1, age: '28', prizemoney: 66149345 },
                        { name: 'Djokovic, Novak (SRB)', rank: 2, age: '27', prizemoney: 70704129 },
                        { name: 'Federer, Roger (SUI)', rank: 3, age: '33', prizemoney: 84827704 },
                        { name: 'Wawrinka, Stan (SUI)', rank: 4, age: '29', prizemoney: 13155060 },
                        { name: 'Ferrer, David (ESP)', rank: 5, age: '32', prizemoney: 24034072 },
                        { name: 'Tsonga, Jo-Wilfried (FRA)', rank: 11, age: '29', prizemoney: 1708240 },
                        { name: 'Simon, Gilles (FRA)', rank: 26, age: '29', prizemoney: 760469 },
                        { name: 'Lopez, Feliciano (ESP)', rank: 20, age: '33', prizemoney: 1100579 },
                        { name: 'Benneteau, Julien (FRA)', rank: 28, age: '32', prizemoney: 617688 },
                        { name: 'Verdasco, Fernando (ESP)', rank: 33, age: '30', prizemoney: 689219 },
                        { name: 'Mayer, Leonardo (ARG)', rank: 25, age: '27', prizemoney: 946294 }
                    ];
                })
                .directive("nextMatch", function () {
                    return {
                        template: function () {
                            return angular.element(
                                    document.querySelector("#playerTemplate")).html();
                        },
                        scope: {
                            injurylocal: "@injuryattr",
                            courtlocal: "@courtattr",
                            playerslocal: "@playersattr"
                        }
                    }
                });
    </script>
</head>
<body>
<div ng-app="appModule" ng-controller="appCtrl">
    Next match on Roland Garros:
    <table>
        <tr>
            <td>
                <div next-match injuryattr="{{injury}}" 
                        courtattr="{{court.name}}" playersattr="{{players}}"></div>
            </td>
            <td>
                <div next-match injuryattr="{{injury}}" 
                        courtattr="{{court.name}}" playersattr="{{players}}"></div>
            </td>
        </tr>
    </table>
</div>
</body>
</html>

So, this is a one-way binding for an isolated scope based on three steps:
  • in the scope definition object, set up a one-way binding between the attributes and the properties in the directive scope
                scope: {
                            injurylocal: "@injuryattr",
                            courtlocal: "@courtattr",
                            playerslocal: "@playersattr"
                            }

  • define the attributes on the elements to which we apply the custom directive
                <div next-match injuryattr="{{injury}}"
                        courtattr="{{court.name}}" playersattr="{{players}}"></div>
  • specify the values for the local properties in the directive scope   
                <p>Players:
                      {{playerslocal}}
                </p>
                <p>Court: {{courtlocal}}</p>
                <p>Injury: {{injurylocal}}</p>