95

分離スコープを使用せずに、ディレクティブ内から親スコープで関数を呼び出す方法を見つけることができないようです。分離スコープを使用する場合、分離で「&」を使用して親スコープの関数にアクセスできることはわかっていますが、必要のないときに分離スコープを使用すると結果が生じます。次の HTML を検討してください。

<button ng-hide="hideButton()" confirm="Are you sure?" confirm-action="doIt()">Do It</button>

この簡単な例では、JavaScript の確認ダイアログを表示し、確認ダイアログで [OK] をクリックした場合にのみ doIt() を呼び出します。これは、分離スコープを使用すると簡単です。ディレクティブは次のようになります。

.directive('confirm', function () {
    return {
        restrict: 'A',
        scope: {
            confirm: '@',
            confirmAction: '&'
        },
        link: function (scope, element, attrs) {
            element.bind('click', function (e) {
                if (confirm(scope.confirm)) {
                    scope.confirmAction();
                }
            });
        }
    };
})

しかし、問題は、私が分離スコープを使用しているため、上記の例の ng-hide は親スコープに対して実行されなくなり、分離スコープで実行されることです (任意のディレクティブで分離スコープを使用すると、その要素のすべてのディレクティブが分離スコープを使用します)。これは、ng-hide が機能しない上記の例の jsFiddleです。(このフィドルでは、入力ボックスに「はい」と入力するとボタンが非表示になることに注意してください。)

別の方法は、分離されたスコープを使用しないことです。これは、このディレクティブのスコープを分離する必要がないため、実際にここで本当に必要なものです。私が抱えている唯一の問題は、分離されたスコープでメソッドを渡さない場合、親スコープでメソッドを呼び出すにはどうすればよいですか?

これは、私が分離スコープを使用しておらず、ng-hide が正常に動作している jsfiddleですが、もちろん、confirmAction() の呼び出しは機能せず、機能させる方法もわかりません。

私が本当に探している答えは、分離されたスコープを使用せずに外側のスコープで関数を呼び出す方法です。この確認ダイアログを別の方法で機能させることには興味がありません。この質問のポイントは、外側のスコープを呼び出す方法を理解し、親スコープに対して他のディレクティブを機能させることができるようにすることです。

または、他のディレクティブが親スコープに対して引き続き機能する場合、分離されたスコープを使用するソリューションについて聞きたいと思いますが、これは可能ではないと思います。

4

4 に答える 4

17

AngularJS で $parse サービスを利用したいと考えています。

あなたの例では:

.directive('confirm', function ($parse) {
    return {
        restrict: 'A',

        // Child scope, not isolated
        scope : true,
        link: function (scope, element, attrs) {
            element.bind('click', function (e) {
                if (confirm(attrs.confirm)) {
                    scope.$apply(function(){

                        // $parse returns a getter function to be 
                        // executed against an object
                        var fn = $parse(attrs.confirmAction);

                        // In our case, we want to execute the statement in 
                        // confirmAction i.e. 'doIt()' against the scope 
                        // which this directive is bound to, because the 
                        // scope is a child scope, not an isolated scope. 
                        // The prototypical inheritance of scopes will mean 
                        // that it will eventually find a 'doIt' function 
                        // bound against a parent's scope.
                        fn(scope, {$event : e});
                    });
                }
            });
        }
    };
});

$parse を使用してプロパティを設定するには落とし穴がありますが、ここまで来たらその橋を渡るようにします。

于 2013-07-11T01:52:01.327 に答える
1

私が抱えている唯一の問題は、分離スコープでメソッドを渡さない場合、親スコープでメソッドを呼び出すにはどうすればよいですか?

これは私が孤立したスコープを使用していないjsfiddleで、ng-hideは正常に機能していますが、もちろん、confirmAction()の呼び出しは機能せず、機能させる方法もわかりません。

最初の小さなポイント: この場合、外側のコントローラーのスコープは、ディレクティブのスコープの親スコープではありません。外側のコントローラーのスコープ、ディレクティブのスコープです。つまり、ディレクティブで使用される変数名は、コントローラのスコープで直接検索されます。

次に、このボタンの場合、書き込みattrs.confirmAction()が機能しません。attrs.confirmAction

<button ... confirm-action="doIt()">Do It</button>

は文字列"doIt()"であり、文字列を呼び出すことはできません"doIt()"()

あなたの質問は本当に次のとおりです。

名前が文字列の場合、関数を呼び出すにはどうすればよいですか?

JavaScript では、ほとんどの場合、次のようにドット表記を使用して関数を呼び出します。

some_obj.greet()

ただし、配列表記も使用できます。

some_obj['greet']

インデックス値が文字列であることに注意してください。したがって、ディレクティブでは、次のように簡単に実行できます。

  link: function (scope, element, attrs) {

    element.bind('click', function (e) {

      if (confirm(attrs.confirm)) {
        var func_str = attrs.confirmAction;
        var func_name = func_str.substring(0, func_str.indexOf('(')); // Or func_str.match(/[^(]+/)[0];
        func_name = func_name.trim();

        console.log(func_name); // => doIt
        scope[func_name]();
      }
    });
  }
于 2014-12-20T10:22:30.460 に答える