🅰️

ここらでDirective Scopeの@=&をまとめておきたいと思う

2021/07/04に公開

@=&でピンと来た方、Directiveを使いこなしていますね!

AngularJSの規模が大きくなると、Viewの再利用性を高めるためDirectiveをたくさん自作することになります。再利用性を高めるということはDirectiveやTemplateの抽象度を高めるということになり、特定の$scopeに依存する書き方は好ましくありません。

そこでDirectiveに独自のScopeを定義します。

Directive Scope

Directiveは初期化時にscopeプロパティを持たせることで、独自のscopeを持たせることができます。

angular.module('myApp')
.directive('dirA', function () {
    return {
        restrict: 'E',
        scope: {arr: '@'} // こんなやつ
    };
})

ここには@=&の符号が使用でき、様々なサイトでその意味、利用法が解説されているのですが、いまいち分からない。

ということで、実例を付けてまとめてみました。

plnkr

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sample</title>
</head>
<body ng-app="myApp">
    <div ng-controller="SampleCtrlA">
        <dir-a my-arr="arr"><span ng-repeat="a in arr">{{a}},</span></dir-a>
    </div>
    <div ng-controller="SampleCtrlB">
        <dir-b my-arr="arr"><span ng-repeat="a in arr">{{a}},</span></dir-b>
    </div>
    <div ng-controller="SampleCtrlC">
        <dir-c my-arr="arr"><span ng-repeat="a in arr">{{a}},</span></dir-c>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-route.js"></script>
    <script>
        angular.module('myApp', ['ngRoute']);

        var link = function (scope, elem, attr) {
            console.log(scope.arr);
            scope.arr = [6, 7, 8, 9, 10];
            console.log(scope.arr);
            console.log(scope);
        };

        angular.module('myApp')
        .directive('dirA', function () {
            return {
                restrict: 'E',
                scope: {arr: '@myArr'},
                link: link
            };
        })
        .directive('dirB', function () {
            return {
                restrict: 'E',
                scope: {arr: '=myArr'},
                link: link
            };
        })
        .directive('dirC', function () {
            return {
                restrict: 'E',
                scope: {arr: '&myArr'},
                link: link
            };
        });

        function Ctrl($scope) {
            $scope.arr = [1, 2, 3, 4, 5];
        }

        angular.module('myApp')
        .controller('SampleCtrlA', ['$scope', Ctrl]);

        angular.module('myApp')
        .controller('SampleCtrlB', ['$scope', Ctrl]);

        angular.module('myApp')
        .controller('SampleCtrlC', ['$scope', Ctrl]);
    </script>
</body>
</html>

console.logに吐いてるので、ログを読めばそのまま動きが分かるはずです。以下の解説はこの動作からみた所感で、公式のリファレンスの引用ではありません。

@

  • ViewのHTML内に書いた文字列がそのまま文字列として渡る。
  • AngularJSの式として評価はされない。
  • 筆者の使い方では、link内の$parse()で扱うために@にすることがある。

=

  • ViewのHTML内に書いた文字列が評価され結果が渡る。
  • 親Scopeとバインドされるので、Directive Scope内の変更で親も変化する。
  • 一番よく使う。

&

  • ViewのHTML内に書いた文字列の評価結果を返すための関数が渡る。
  • 親Scopeとはバインドされない。
  • 多くの解説で「Viewには関数を指定する」と見受けられるが、文字列、数値、配列、関数、なんでもいい。
  • scope.valのように直接参照するとparentGet(scope, locals)という関数が返ってくるだけである。
    • 値はscope.val()として取り出す。
    • これが関数ならscope.val()()として実行する。
  • バインドされず式は評価されるので、用途を理解すると使いやすい。

@=&以降の書き方

よく忘れてエラーになるのが@=&の書き方。

属性名を指定する場合scope: {arr: '=myArr'}というように、キャメルケースで書くことで、HTML中では<directive my-arr="">といったハイフン繋ぎで使えます。

何も書かない場合、そのままScopeのプロパティ名がHTML上での属性名になります。

× {arr: '=my-arr'} <directive my-arr="">
× {arr: '=myArr'}  <directive myArr="">
○ {arr: '=myArr'}  <directive my-arr="">

× {my-arr: '='}   <directive my-arr=""> // そもそも文法として誤り
△ {'my-arr': '='} <directive my-arr=""> // 動くがチェーンできない

○ {myArr: '='}    <directive my-arr="">
○ {myArr: '=arr'} <directive arr="">

あとは自作Directiveを量産するだけ!

Discussion