21

作成中のソート列ヘッダーを表示する簡単なディレクティブを<table>作成しました。

ngGrid.directive("sortColumn", function() {
    return {
        restrict: "E",
        replace: true,
        transclude: true,
        scope: {
            sortby: "@",
            onsort: "="
        },
        template: "<span><a href='#' ng-click='sort()' ng-transclude></a></span>",
        link: function(scope, element, attrs) {
            scope.sort = function () {

                // I want to call CONTROLLER.onSort here, but how do I access the controller scope?...
                scope.controllerOnSort(scope.sortby);
            };
        }
    };
});

作成されるいくつかのテーブル ヘッダーの例を次に示します。

<table id="mainGrid" ng-controller="GridCtrl>
<thead>
    <tr>
        <th><sort-column sortby="Name">Name</sort-column></th>
        <th><sort-column sortby="DateCreated">Date Created</sort-column></th>
        <th>Hi</th>
    </tr>
</thead>

したがって、並べ替え列がクリックされたときに、グリッドコントローラーで onControllerSort 関数を起動したいのですが、行き詰まっています! これまでのところ、これを行うことができた唯一の方法は<sort-column>、「onSort」の属性を追加し、ディレクティブでそれらを参照することです。

<sort-column onSort="controllerOnSort" sortby="Name">Name</sort-column>

しかし、私は常に controllerOnSort を呼び出したいので、それはあまり良いことではありません。HTML に不要なマークアップを必要とせずに、ディレクティブ内でこれを行うにはどうすればよいですか? それが役立つ場合、ディレクティブとコントローラーの両方が同じモジュール内で定義されます。

4

5 に答える 5

24

2 つ目のディレクティブをラッパーとして作成します。

ngGrid.directive("columnwrapper", function() {
  return {
    restrict: "E",
    scope: {
      onsort: '='
    }
  };
});

次に、関数を参照して、外側のディレクティブで 1 回呼び出すことができます。

<columnwrapper onsort="controllerOnSort">
  <sort-column sortby="Name">Name</sort-column>
  <sort-column sortby="DateCreated">Date Created</sort-column>
</columnwrapper>

「sortColumn」ディレクティブでは、次の呼び出しにより、その参照された関数を呼び出すことができます

scope.$parent.onsort();

実際の例については、このフィドルを参照してください: http://jsfiddle.net/wZrjQ/1/

もちろん、ハードコードされた依存関係を気にしない場合は、1 つのディレクティブを使用して、親スコープ (問題のコントローラー) で関数を呼び出すこともできます。

scope.$parent.controllerOnSort():

これを示す別のフィドルがあります: http://jsfiddle.net/wZrjQ/2

このソリューションは、他の回答 ( https://stackoverflow.com/a/19385937/2572897 )のソリューションと同じ効果があります (ハードカップリングに関しては同じ批判があります) が、少なくともそのソリューションよりもいくらか簡単です。 . とにかく強く結合する場合、コントローラーを参照する意味はないと思います。コントローラーは常に $scope.$parent で使用できる可能性が高いためです (ただし、スコープを設定する他の要素に注意してください)。

しかし、私は最初の解決策に行きます。少しマークアップを追加しますが、問題を解決し、きれいな分離を維持します。また、2 番目のディレクティブを直接ラッパーとして使用すると、 $scope.$parent が外部ディレクティブと一致することを確認できます。

于 2013-10-15T18:16:05.793 に答える
20

& ローカル スコープ プロパティを使用すると、ディレクティブのコンシューマーは、ディレクティブが呼び出すことができる関数を渡すことができます。

& スコープ プロパティの図

詳細はこちらをご覧ください。

これは、ディレクティブ コードからコールバック関数に引数を渡す方法を示す、同様の質問に対する回答です。

于 2014-07-24T10:44:12.220 に答える
8

ディレクティブでは、requireを使用しngControllerてリンク関数を次のように変更します。

ngGrid.directive("sortColumn", function() {
    return {
        ...
        require: "ngController",
        ...
        link: function(scope, element, attrs, ngCtrl) {
            ...
        }
    };
});

あなたが得るのngCtrlはあなたのコントローラーですGridCtrl。ただし、その範囲はわかりません。次の行で何かをする必要があります。

xxxx.controller("GridCtrl", function($scope, ...) {
    // add stuff to scope as usual
    $scope.xxxx = yyyy;

    // Define controller public API
    // NOTE: USING this NOT $scope
    this.controllerOnSort = function(...) { ... };
});

次のようにリンク関数から呼び出します。

ngCtrl.controllerOnSort(...);

この require は最初の parent を取得することに注意してくださいngControllerGridCtrlとディレクティブの間に別のコントローラーが指定されている場合は、そのコントローラーが取得されます。

原理を示すフィドル (ng-controllerメソッドで親にアクセスするディレクティブ): http://jsfiddle.net/NAfm5/1/


人々は、このソリューションが望ましくない密結合を導入する可能性があることを恐れています。これが本当に懸念事項である場合は、次のように対処できます。

コントローラーとサイドバイサイドになるディレクティブを作成し、それを呼び出しましょうmaster:

<table id="mainGrid" ng-controller="GridCtrl" master="controllerOnSort()">

このディレクティブは、コントローラーの目的のメソッドを参照します (つまり、デカップリング)。

子ディレクティブ(sort-columnあなたの場合)にはmasterディレクティブが必要です:

require: "^master"

サービスを使用して$parse、指定されたメソッドをマスター コントローラーのメンバー メソッドから呼び出すことができます。この原則を実装する更新されたフィドルを参照してください: http://jsfiddle.net/NAfm5/3/

于 2013-10-15T16:06:20.910 に答える
1

私をクレイジーと呼んでください、しかし、それをいじるよりも、そのための組み込みメソッドを介して要素からコントローラーを取得する方が簡単なようですrequire:

var mod = angular.module('something', []).directive('myDir', 
  function () {
    return {
      link: function (scope, element) {
        console.log(element.controller('myDir'));
      },
      controller: function () {
        this.works = function () {};
      },
      scope: {}
    }
  }
);

http://plnkr.co/edit/gY4rP0?p=preview

于 2015-12-01T13:17:52.620 に答える