1

ユーザーが検索を実行できるようにする UI を作成するディレクティブがあります。ディレクティブは、トランスクルージョンして個々の検索結果のテンプレートになるコンテンツをラップします。このようなもの:

<search>
  <div class="someStyle" ng-click="selectResult(result)">{{result.Name}}</div>
</search>

コントローラーのスコープで ng-click に selectResult 関数を呼び出してもらいたいのですが、result オブジェクトはディレクティブから取得します。ディレクティブで分離されたスコープを使用してこれを達成するにはどうすればよいですか?

4

3 に答える 3

3

ng-transclude を使用する代わりに、トランスクルードされたスコープに結果を配置するために使用できる独自の検索トランスクルード ディレクティブを作成できます。たとえば、検索ディレクティブは、トランスクルードされたコンテンツが必要な ng-repeat と search-transclude ディレクティブを使用して、次のようになります。

.directive("search", function (SearchResults) {
    return {
        restrict: "AE",
        transclude: true,
        scope: {},
        template: '<div ng-repeat="result in results">Search Relevance:' +
        '{{result.relevance}}' +
        //the most important part search-transclude that receives the current
        //result of ng-repeat
        '<div search-transclude result="result"></div></div>',
        link: function (scope, elem, attrs) {
            //get search results
            scope.results = SearchResults.results;
        }
    }
})

次のように検索トランスクルード ディレクティブを作成します。

.directive("searchTransclude", function () {
    return {
        restrict: "A",
        link: function (scope, elem, attrs, ctrl, $transclude) {
            //create a new scope that inherits from the parent of the
            //search directive ($parent.$parent) so that result can be used with other
            //items within that scope (e.g. selectResult)
            var newScope = scope.$parent.$parent.$new();
            //put result from isolate to be available to transcluded content
            newScope.result = scope.$eval(attrs.result);
            $transclude(newScope, function (clone) {
                elem.append(clone);
            });
        }
    }
})

トランスクルードされたコンテンツは、検索ディレクティブが作成されたスコープに存在する場合、selectResult 関数を参照できるようになりました。例はこちら

于 2014-12-03T19:49:52.433 に答える
1

[ディレクティブで] ng-click を使用して、コントローラーのスコープで selectResult 関数を呼び出したいと思います...

  1. 関数 (またはプロパティ) を isolate スコープに渡すには、ディレクティブ タグで属性を使用します。

...しかし、結果オブジェクトをディレクティブ [スコープ] から取得します。

  1. ディレクティブ タグのコンテンツがディレクティブのスコープにアクセスできるようにする場合は、transclude を使用しないでください。指定transclude: trueすると、ディレクティブ タグのコンテンツがディレクティブのスコープにアクセスできないように angular に指示されます。これは、希望するものとは逆です。

#1 を達成するには、ユーザーに次のようにテンプレートを指定させることができます。

  <div ng-controller="MainCtrl">

    <search external-func='selectResult'>
      <div class="someStyle" ng-click="selectResult(result)">{{result.Name}}</div>
    </search>

  </div>

<search>ユーザーはタグに追加の属性を追加する必要があることに注意してください。それでも、その html は、javascript が要素に対してどのような操作を行うかについて、html が開発者にヒントを与えるべきであるという angular の哲学にうまく適合する可能性があります。

次に、isolate スコープを次のように指定します。

      scope: {
        selectResult: '=externalFunc'
      },

#2 を達成transclude: trueするには、ディレクティブで指定しないでください。

var app = angular.module('myApp',[]);

app.controller('MainCtrl', ['$scope', function($scope) {

  $scope.selectResult = function(result) {
    console.log("In MainCtrl: " + result.Name);
  };

}]);

app.controller('DirectiveCtrl', ['$scope', function($scope) {

  $scope.results = [ 
    {Name: "Mr. Result"},
    {Name: "Mrs. Result"}
  ]

}]);

app.directive('search', function() {

  return {
      restrict: 'E',

      scope: {
        selectResult: '=externalFunc'
      },

      template: function(element, attrs) {
      //                    ^       ^
      //                    |       |
      //    directive tag --+       +-- directive tag's attributes

        var inner_div = element.children();
        inner_div.attr('ng-repeat', 'result in results')

        //console.log("Inside template func: " + element.html());

        return element.html();  //Must return a string.  The return value replaces the innerHTML of the directive tag.
      },

      controller: 'DirectiveCtrl'
  }

}]);

ユーザーにテンプレートをより詳細に指定させると、html は javascript が何をするかのより良い記録を提供する可能性があります。

<search external-func='selectResult'>
  <div class="someStyle" 
    ng-click="selectResult(result)"
    ng-repeat="result in results">{{result.Name}}
  </div>
</search>

しかし、ミニマリストの html を主張する場合:

<search>
  <div class="someStyle" ng-click="selectResult(result)">{{result.Name}}</div>
</search>

...次に、(上記のように) ng-repeat 属性を動的に追加できます。また、外部関数を isolate スコープに動的にマップすることもできます。

var app = angular.module('myApp',[]);

app.controller('MainCtrl', ['$scope', function($scope) {

  $scope.selectDog = function(result) {
    console.log("In MainCtrl: you clicked " + result.Name);
  };

  $scope.greet = function(result) {
    console.log('MainCtrl: ' + result.Name);
  };

}]);

app.controller('DirectiveCtrl', ['$scope', function($scope) {

  $scope.results = [ 
    {Name: "Mr. Result"},
    {Name: "Mrs. Result"}
  ]

}]);

app.directive('search', function() {

  return {
    restrict: 'E',

    scope: {
      externalFunc: '&externalFunc'  //Cannot write => externalFunc: '&'
    },                               //because the attribute name is
                                     //'external-func', which means
                                     //the left hand side would have to be external-func.
    template: function(element, attrs) {
      //Retrieve function specified by ng-click:
      var inner_div = element.children();
      var ng_click_val = inner_div.attr('ng-click'); //==>"selectResult(result)"

      //Add the outer_scope<==>inner_scope mapping to the directive tag:
      //element.attr('external', ng_click_val); //=> No worky! Angular does not create the mapping.
      //But this works:
      attrs.$set('externalFunc', ng_click_val) //=> external-func="selectResult(result)"
      //attrs.$set('external-func', ng_click_val); //=> No worky!

      //Change ng-click val to use the correct call format:
      var func_args = ng_click_val.substring(ng_click_val.indexOf('(')); //=> (result)
      func_args =  func_args.replace(/[\(]([^\)]*)[\)]/, "({$1: $1})"); //=> ({result: result})
      inner_div.attr('ng-click', 'externalFunc' + func_args); //=> ng-click="externalFunc({result: result})"

      //Dynamically add an ng-repeat attribute:
      inner_div.attr('ng-repeat', 'result in results')

      console.log("Template: " + element[0].outerHTML);
      return element.html();
    },

    controller: 'DirectiveCtrl'
  }
})

複数の引数を指定して外部関数を呼び出したい場合は、次のようにすることができます。

var app = angular.module('myApp',[]);

app.controller('MainCtrl', ['$scope', function($scope) {

  $scope.selectResult = function(result, index) {
    console.log("In MainCtrl: you clicked " 
                 +  result.Name 
                 + " " 
                 + index);
  };

}]);

app.controller('DirectiveCtrl', ['$scope', function($scope) {

  $scope.results = [ 
    {Name: "Mr. Result"},
    {Name: "Mrs. Result"}
  ]

}]);

app.directive('search', function() {
  return {
    restrict: 'E',

    scope: {
      external: '='
    },

    template: function(element, attrs) {
      //Extract function name specified by ng-click:
      var inner_div = element.children();
      var ng_click_val = inner_div.attr('ng-click'); //=>"selectResult(result, $index)"
      var external_func_name =  ng_click_val.substring(0, ng_click_val.indexOf('(') ); //=> selectResult
      external_func_name = external_func_name.trim();

      //Add the outer_scope<==>inner_scope mapping to the directive tag:
      //element.attr('externalFunc', ng_click_val); => No worky!
      attrs.$set('external', external_func_name);  //=> external="selectResult"

      //Change name of ng-click function to 'external':
      ng_click_val = ng_click_val.replace(/[^(]+/, 'external');
      inner_div.attr('ng-click', ng_click_val);

      //Dynamically add ng-repeat to div:
      inner_div.attr('ng-repeat', 'result in results');

      console.log("Template: " + element[0].outerHTML);
      return element.html();
    },

    controller: 'DirectiveCtrl'
  }
});
于 2014-12-20T05:42:29.703 に答える
1

トランスクルードされたコンテンツは、ディレクティブ要素が存在するスコープ、つまりコントローラ スコープを常に使用します。resultそのため、関数の引数が分離スコープから値を取得するようにしたい場合はselectResult、分離スコープのプロパティとコントローラー スコープのプロパティの間に双方向バインディングを確立する必要がありresultます。分離されたスコープでプロパティを目的の値に設定した後result、コントローラーのスコープresultプロパティは同じ値に更新されます。そのため、トランスクルージョンされたコンテンツはresult、分離されたスコープと同期しているコントローラーを使用しresultます。

resultAttr='result'1)ディレクティブ要素に属性を追加します。

<search resultAttr='result'> <div class="someStyle" ng-click="selectResult(result)">{{result.Name}}</div> </search>

result2)ディレクティブで分離スコープを定義するときに、プロパティの双方向バインディングを確立します。

scope: { result: "=resultAttr" }

3)resultディレクティブで値を設定する

于 2014-12-03T19:15:44.113 に答える