如何将范围值从指令传播到控制器?

时间:2014-03-11 02:47:10

标签: javascript angularjs angularjs-directive angularjs-scope

我有一个复杂的数据结构,需要大量的内联编辑。为了使代码更容易,这个数据结构中的大部分组件都被放入了嵌套指令中。

例如,以下是数据结构的示例:

{
   "pageElements":[
      {
         "id":1721,
         "pageId":861,
         "position":0,
         "type":"Paragraph",
         "text":"<p>Who is the captain of the Enterprise NX-01?</p>"
      },
      {
         "id":1722,
         "pageId":861,
         "position":1,
         "type":"Question",
         "question":{
            "id":1664,
            "type":"ShortAnswer",
            "successMessage":"You really know your captains!",
            "hints":[

            ],
            "answerAllowance":"SINGLE",
            "minimumNumberOfKeywords":1,
            "keywords":[
               {
                  "id":45394,
                  "text":"John Archer",
                  "accuracy":0,
                  "ignoreCase":false
               }
            ]
         }
      },
      {
         "id":2786,
         "pageId":861,
         "position":2,
         "type":"Paragraph",
         "text":"<p>fafadffadfda</p>"
      }
   ]
}

想象一下,这个控制器的主页面遍历pageElements

<ol class="pageElements">
    <li ng-repeat="pageElement in page.pageElements">
        <!-- page-element directive uses $compile 
             to create a specific DOM based on pageElement.type -->
        <div page-element ng-model="pageElement"></div>
    </li>
</ol>

现在,让我们想象一下pageElement指令(或某些子指令)中出现的单个page-element的某些修改。我们如何将这些修改纳入page.pageElements列表?出于某种原因,如果父指令只是对象,我可以将更改传播到父指令,但是一旦父对象包含在列表中,更新就不再传播。

我该如何解决这个问题?问题真的是ng-repeat阻止向上传播吗?

3 个答案:

答案 0 :(得分:1)

在指令和控制器之间共享数据使用SERVICE,它只不过是你在控制器中进行的注入,例如:$ http,$ rootScope,$ scope 类似地,您可以拥有用户定义的服务..将其注入您的控制器和指令并用于交换数据!

第二部分:如何告诉控制器指令中的值已更改?说你的指令有一个变量A,如果你想要在控制器中做一些事情,那么你有两种方式

  1. 使用$ watch
  2. 或使用$ emit方法(最好使用它!它是一种广播,即当A上发生更改时,此$ emit被触发,所有控制器都可以访问此$ emit事件 你可以听它并做你想要触发的事情)

答案 1 :(得分:0)

您只需要正确设置指令范围。看看这段代码

<html>
    <head></head>
    <body>
        <div ng-app="app">
            <div ng-controller="ctrl">
                <div>
                    <h1>I am the parent scope.</h1>
                    {{page}}
                </div>
                <ol class="pageElements">
                    <li ng-repeat="pageElement in page.pageElements">
                        <!-- page-element directive uses $compile 
                             to create elemented based on type -->
                        <div>
                            <h2>I am still the parent scope, only that I watch one element</h2>
                            {{pageElement}}
                        </div>>
                        <div page-element my-page-element="pageElement"></div>
                    </li>
                </ol>
            </div>
        </div>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
        <script>
            angular.module('app', [])
                .controller('ctrl', function($scope) {
                    $scope.page = {"pageElements":[{"id":1721,"pageId":861,"position":0,"type":"Paragraph","text":"<p>Who is the captain of the Enterprise NX-01?</p>"},{"id":1722,"pageId":861,"position":1,"type":"Question","question":{"id":1664,"type":"ShortAnswer","successMessage":"You really know your captains!","hints":[],"answerAllowance":"SINGLE","minimumNumberOfKeywords":1,"keywords":[{"id":45394,"text":"John Archer","accuracy":0,"ignoreCase":false}]}},{"id":2786,"pageId":861,"position":2,"type":"Paragraph","text":"<p>fafadffadfda</p>"}]};
                })
                .directive('pageElement', function() {
                    return {
                        template: '<div><h3>I am the directive scope. You can change the "text" property here to see it propagate.</h3><input ng-model="pageElement.text"><p>{{pageElement.text}}</p><div>{{pageElement}}<div></div>',
                        scope: {
                            pageElement: '=myPageElement'
                        }
                    };
                });
        </script>
    </body>
</html>

工作小提琴: http://jsfiddle.net/9rcu3/

魔术在指令范围内绑定:

scope: {
    pageElement: '=myPageElement'
}

看一下角度开发人员指南,他们有一个关于构建指令的精彩教程:

http://docs.angularjs.org/guide/directive

答案 2 :(得分:0)

好的,我这样解决了。在ngRepeat:

中,显然模型需要包含对象引用
<ol class="pageElements">
    <li ng-repeat="pageElement in page.pageElements">
        <div page-element model="page.pageElements[$index]"></div>
    </li>
</ol>

所以,诀窍是page.pageElements[$index]而不是pageElement

我从以下方面得到了这个解决方案:

Directive isolate scope with ng-repeat scope in AngularJS