【问题标题】:AngularJS - adding new values to directive's isolated scopeAngularJS - 向指令的隔离范围添加新值
【发布时间】:2014-11-08 17:49:05
【问题描述】:

我有一个独立范围的指令如下:

    application.directive("myDirective",function(){
        return {
            restrict: "A",
            scope: {myDirective:"="},
            link : function(scope) {
                console.log("My directive: ",scope.myDirective) // works fine
                scope.person={name:"John",surname:"Doe"}

                scope.hello=function(){
                    console.log("Hello world!")
                }
            }
        }
    })

对应视图:

<div my-directive='{testValue:3}'>
    Testvalue: {{myDirective}}<br/>
    Hello {{person}}
    <button ng-click="hello()">Say hello</button>
</div>

而且似乎我不能使用范围内声明的任何字段。鉴于“myDirecive”和“person”字段为空白,并且当我按下按钮时未执行范围的“hello”功能。

当我将 scope="true" 传递给指令但在隔离范围内不起作用时,它可以正常工作。

我在这里遗漏了什么,或者没有办法将变量引入指令的隔离范围?

更新

更新的问题介绍了为什么我不想使用静态模板。我想要达到的效果是制作指令,允许上传任何通过rest/json获取表单初始数据的html表单。整个过程相当复杂且特定于应用程序,因此我无法使用任何可用的表单库。我在下面介绍用例的简化版本:

更新后的指令

    application.directive("myForm",function(){
        return {
            restrict: "A",
            scope: {myForm:"="},
            link : function(scope) {
                console.log("Form parameters: ",scope.myForm) // works fine
                scope.formData=... // Get form initial data as JSON from server

                scope.submitForm=function(){
                   // Send scope.formData via REST to the server
                }
            }
        }
    })

我想使用这种形式的情况。当然我想用不同的形式多次使用这个指令。

<form my-form='{postUrl:'/myPostUrl',getFormDataUrl:'/url/to/some/json}'>
    <div>Form user: {{formData.userName}} {{formData.userSurname}}
    <input type="text" ng-model="formData.userAge" />
    <input type="text" ng-model="formData.userEmail" />
    <button ng-click="submitForm()">Submit</button>
</form>

我希望这能解释为什么我不能在这种情况下使用一个静态 html 模板。

也许有人可以解释为什么这适用于 scope="true" 并且在一个孤立的范围内我无法访问任何范围内的变量?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    使用 Angular,指令可以与 template(或 templateUrl)一起使用,也可以与嵌入的内容一起使用。

    如果您使用的是模板,则该模板可以访问隔离范围。因此,如果您将 {{person}} 放入模板中,它将按预期工作。

    如果您使用的是嵌入内容 - 即应用了指令的节点的子内容 - 那么,您不仅需要设置 transclude: true 并指定模板中的位置嵌入的内容去 - 例如&lt;div ng-transclude&gt;&lt;/div&gt; 甚至看到内容,你也不会得到你期望的结果,因为被嵌入的内容可以访问与指令的父级相同的范围变量,而不是指令的隔离范围内可用的变量。

    此外,您应该注意,如果您使用“=”将不可分配的对象传递给指令的隔离范围 - 就像您对 my-directive="{testValue: 3" 所做的那样,那么您无法对其进行任何更改(并且,不幸的是,即使它们是作用域变量,也包括它的属性)。

    所以,要使您的具体案例发挥作用,请执行以下操作:

    application.directive("myDirective",function(){
      return {
        ...
        template: "Testvalue: {{myDirective}}<br/> " + 
                  "Hello {{person}} " + 
                  "<button ng-click="hello()">Say hello</button>";
      };
    });
    

    以及对应的视图:

    其中prop 在视图控制器中设置为:$scope.prop = {testValue: 3};

    【讨论】:

    • the transcluded content is bound to the same scope as the parent of the directive ,实际上它绑定到父级的新子范围,使其成为指令隔离范围的兄弟范围。
    • 是的,这更准确,但我的意思是人们可以访问哪些范围变量,这与问题相关,而不是范围层次结构如何。
    • 只是认为你应该更准确,因为总的来说这是一个很好的答案。将链接添加到文档docs.angularjs.org/guide/…
    • 实际上我希望“myDirective”不要使用模板,它应该是一个简单的指令,在范围上设置的值很少,并且每次可以多次使用不同的内容。因此我不能只指定 HTML 模板。是否还有一种方法可以允许任何 html 包含在我的指令中?
    • @IlanFrumer 我同意。我一靠近大屏幕就会修复
    【解决方案2】:

    您始终可以更改嵌入范围的默认行为(尽管我不推荐这样做):

    application.directive("myDirective",function(){
      return {
        tranclude: true,
        scope: {myDirective:"="},
        link : function(scope, element, attrs, ctrl, $transclude) {
    
          $transclude(scope, function(clone) {
            element.empty();
            element.append(clone);
          });
    
          scope.person={name:"John",surname:"Doe"};
    
          scope.hello=function(){
            console.log("Hello world!");
          };
        }
      };
    });
    

    查看文档:https://docs.angularjs.org/api/ng/service/$compile#transclusion-functions

    另请看ngTranslude源码:https://github.com/angular/angular.js/blob/master/src/ng/directive/ngTransclude.js

    【讨论】:

    • 修正tranclude中的错字...你为什么不推荐这个?
    • 因此,您将使所有子元素与父范围隔离。每次您需要来自外部范围的某些东西时,您都会被困在将其添加到指令范围定义中或使用 $scope.$parent 中,这是一种反模式。一个好的指令不会接管整个模板。
    • 那么你可以设置scope: true,这似乎是OP在阅读了他的cmets之后想要的。如果他发布一个单独的问题并且这就是答案会更好,因为这里的当前问题没有解释目标是什么。
    • 如果我设置 scope=true 是否有办法将配置对象传递给 myForm 模板,如示例中所示?没有范围:{ myform:"="} 我似乎无法将表单配置作为对象...
    • with scope: true 你的指令原型继承了父级的作用域,所以在父级声明的任何内容都对子级可用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-08
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多