39

ここでAngular noob。質問とサブ質問のツリーを再帰的に表示するディレクティブを作成しています。スコープ内の関数を呼び出すテンプレートのリンクを使用しています。editQuestion()何らかの理由で、メソッドを呼び出しません。

ここにコードとフィドルがありますhttp://jsfiddle.net/madhums/n9KNv/

HTML:

<div ng-controller="FormCtrl">
  <questions value="survey.questions"></questions>
</div>

Javascript:

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

function FormCtrl ($scope) {
  $scope.editQuestion = function (question) {
    alert('abc');
  };
  $scope.survey = {
    // ...
  }
}


app.directive('questions', function($compile) {
  var tpl = '<ol ui-sortable' +
    ' ng-model="value"' +
    ' class="list">' +
    '  <li ng-repeat="question in value | filter:search"' +
    '     <a href="" class="question">' +
    '       {{ question.name }}' +
    '     </a>' +
    '     <span class="muted">({{ question.type }})</span>' +
    '     <a href="" class="danger" ng-click="removeQuestion(question)">remove</a>' +
    '     <a href="" class="blue" ng-click="editQuestion(question)">edit</a>' +
    '     <choices value="question.choices"></choices>' +
    '  </li>' +
    '</ol>';

  return {
    restrict: 'E',
    terminal: true,
    scope: { value: '=' },
    template: tpl,
    link: function(scope, element, attrs) {
        $compile(element.contents())(scope.$new());
    }
  };
});

app.directive('choices', function($compile) {
  var tpl = '<ul class="abc" ng-repeat="choice in value">'+
    '  <li>' +
    '    {{ choice.name }}' +
    '    <span class="muted">' +
    '      ({{ choice.questions.length }} questions)' +
    '    </span>' +
    '' +
    '    <a href=""' +
    '      ng-click="addQuestions(choice.questions)"' +
    '      tooltip="add sub questions">' +
    '      +' +
    '    </a>' +
    '' +
    '    <questions value="choice.questions"></questions>'
    '  </li>' +
    '</ul>';

  return {
    restrict: 'E',
    terminal: true,
    scope: { value: '=' },
    template: tpl,
    link: function(scope, element, attrs) {
        $compile(element.contents())(scope.$new());
    }
  };
});

これを理解するための助けをいただければ幸いです。

4

4 に答える 4

38

範囲の問題があります。を使用してディレクティブで分離スコープを使用したためscope: { value: '=' }、 を持つコントローラーのスコープにアクセスできなくなりましたeditQuestion

editQuestionディレクティブの呼び出し方法を認識できるように、ディレクティブのスコープに渡す必要があります。通常、これは非常に簡単ですが、選択肢に質問を含めることができる無限に再帰的なディレクティブ構造のため、少しトリッキーになります。これが実用的なフィドルです:

http://jsfiddle.net/n9KNv/14/

HTML にeditQuestion次への参照が含まれるようになりました。

<div ng-controller="FormCtrl">
    <questions value="survey.questions" on-edit="editQuestion(question)"></questions>
</div>

そして、あなたの質問ディレクティブはonEdit、そのスコープ内に属性を期待するようになりました:

app.directive('questions', function($compile) {
  var tpl = '<ol ui-sortable' +
    ' ng-model="value"' +
    ' class="list">' +
    '  <li ng-repeat="question in value | filter:search"' +
    '     <a href="" class="question">' +
    '       {{ question.name }}' +
    '     </a>' +
    '     <span class="muted">({{ question.type }})</span>' +
      '     <a href="" class="blue" ng-click="onEdit({question: question})">edit</a>' +
      '     <choices value="question.choices" on-edit="onEdit({question: subQuestion})"></choices>' +
    '  </li>' +
    '</ol>';

  return {
    restrict: 'E',
    terminal: true,
      scope: { value: '=', onEdit: '&' },
    template: tpl,
    link: function(scope, element, attrs) {
        $compile(element.contents())(scope.$new());
    }
  };
});

app.directive('choices', function($compile) {
  var tpl = '<ul class="abc" ng-repeat="choice in value">'+
    '  <li>' +
    '    {{ choice.name }}' +
    '    <span class="muted">' +
    '      ({{ choice.questions.length }} questions)' +
    '    </span>' +
    '' +
      '    <questions value="choice.questions" on-edit="onEdit({subQuestion: question})"></questions>'
    '  </li>' +
    '</ul>';

  return {
    restrict: 'E',
    terminal: true,
      scope: { value: '=', onEdit: '&' },
    template: tpl,
    link: function(scope, element, attrs) {
        $compile(element.contents())(scope.$new());
    }
  };
});

でターゲットを設定する方法に注目してquestionくださいng-click。これは、コールバック関数で引数をターゲットにする方法です。また、ディレクティブにどのようにon-edit渡しているかにも注意してください。これは、が 内ですでに予約されているためです。そのため、この 2 つを区別する必要があります。choicessubQuestionquestionngRepeat

これはおそらく、これまで Angular で学ぶのが最も難しい概念でした。コントローラー、ディレクティブ、およびその他のディレクティブ間でスコープがどのように機能するかを理解したら、Angular の世界はあなたのものです。:)

于 2013-05-10T19:29:18.863 に答える
7

これは範囲の問題です。ディレクティブの ng-click は、現在のスコープの editQuestion および removeQuestion メソッドを呼び出します。これらは、ディレクティブを含むモジュール (つまり、親スコープ) で定義されているため、ディレクティブのスコープには存在しません。

ディレクティブと親の間のバインディングを確立したいので、ディレクティブが ngClick 関数を呼び出すと、ディレクティブをホストしているモジュールで起動します。

ディレクティブ自体でメソッドを定義するか、ディレクティブ定義オブジェクトのスコープ セクションを介してバインディングをセットアップできます。

これは、さまざまなスコープでの ng-click イベントの発生を示すプランカーです (コンソールへの出力)。

http://plnkr.co/edit/9XfXCpU6lhUOqD6nbVuQ?p=preview

于 2013-05-10T19:12:25.613 に答える
2

Langdon の May10'13 の回答は正しいです。デモンストレーションの目的で、Langdon のフィドル コードを簡素化し、148 行の角度から 23 行の角度に減らしました。
また、関数呼び出しメソッドを介してパラメーター値を MouseEvent オブジェクトとして渡し、その値を関数で取得できる機能も追加しました。JSFIDDLE

の後にコードとクレジットが続きます。非常に簡単に理解できるはずです。 http://jsfiddle.net/BeyondLogical/evjzoo30/ --Html--



<div ng-controller="FormCtrl">
    <questions on-edit="editQuestion(ev,question)" ></questions>
</div>

--AngularJS--

var app = angular.module('myApp', []);
function FormCtrl ($scope) {
    $scope.editQuestion = function (ev,question) {
        //ev returns a MouseEvent object
        alert("ev: " + ev);
        //this is how you get the 'data' attribute set in the span tag below
        alert("ev-data: " + ev.target.attributes.data.value); 
    };
}
app.directive('questions', function($compile) {
    var tpl = 
    '<span ng-click="onEdit({ev: $event, myName: question})" data="This sentence would probably be replaced with a mustache brace parameter, example: {{someValue}}, returning a value from the scope." style="cursor:pointer;">Click Me</span>';
    return {
        restrict: 'E',
        terminal: true,
        scope: { onEdit: '&' },
        template: tpl,
        link: function(scope, element, attrs) {
            $compile(element.contents())(scope.$new());
        }
    };
});

Langdonの 功績 -
ディレクティブテンプレート内で ng - clickが機能しないコントローラー関数と Pavan の JSFIDDLE - http://jsfiddle.net/brettdewoody/FAeJq/ (特に Pavan の次のコード行):



alert(obj.target.attributes.data.value);

于 2015-09-14T19:51:51.823 に答える
1

これに来て、あなたのディレクティブで実行されていないコードでそれを行おうとしている人は、オプションreplaceを使用していないことを確認してください。

例えば:

angular.module('app').directive('myDirective', function () {
return {
    template: '<div ng-click="clicked()"></div>',
    scope: {
      options: "="
    },
    replace: true, //<---- Change this to false
    restrict: 'E',
    controller: function ($scope) {

      $scope.clicked = function(){
        console.log("Clicked");
      }
    }
  };
}
于 2016-02-23T03:50:08.230 に答える