编程语言
首页 > 编程语言> > javascript-如何调和Angular的“始终将点与ngModel一起使用”规则与隔离范围?

javascript-如何调和Angular的“始终将点与ngModel一起使用”规则与隔离范围?

作者:互联网

我正在使用Bootstrap开发Angular应用程序.

为了最大程度地减少HTML上的Bootstrap占用空间,我为表单引入了两个指令:

表格控件

module.directive('formControl', function() {
  return {
    restrict : 'E',
    templateUrl : 'form-control.tmpl.html',
    scope: {
      label: '@'
    },
    transclude : true
  };
});

form-control.tmpl.html

<div class="form-group">
  <label class="control-label col-sm-2">
    {{ label }}
  </label>
  <div class="col-sm-10"
       ng-transclude>
  </div>
</div>

对于各种格式输入字段,我也对该指令有一些“扩展”.例如.:

表单输入文本.js

module.directive('formInputText', function() {
  return {
    restrict : 'E',
    templateUrl : 'form-input-text.tmpl.html',
    scope: {
      label: '@',
      value: '=ngModel'
    }
  };
});

form-input-text.tmpl.html

<form-control label="{{label}}">
  <input type="text"
         class="form-control"
         ng-model="value">
</form-control>

app.html

<form-input-text label="Name"
                 ng-model="person.name">
</form-input-text>

在这里我遇到了一个问题.此示例中有多个作用域:

appScope = { person : { name : "John" } };
isolateScope = {
  label: "Name",
  value: "John" // bound two-way with appScope.person.name
};
transcludeScope = {
  __proto__: isolateScope,
  label: "Name", // inherited from isolateScope
  value: "John" // inherited from isolateScope
};

如果我更改输入文本框中的文本,则仅transcludeScope会被修改:

appScope = { person : { name : "John" } };
isolateScope = {
  label: "Name",
  value: "John" // bound two-way with appScope.person.name
};
transcludeScope = {
  __proto__: isolateScope,
  label: "Name", // inherited from isolateScope
  value: "Alice" // overrides value from isolateScope
};

这是因为< input>直接绑定到transcludeScope的属性.直接更改transcludeScope.value,并且父范围isolateScope不受影响.因此,输入中的任何模型更改都不会使其返回到appScope.

我想做的是在appScope.person.name和isolateScope的嵌套属性之间创建双向绑定,例如孤立范围.模型.值.

理想情况下,我想这样声明我的指令:

表单输入文本.js

module.directive('formInputText', function() {
  return {
    restrict : 'E',
    templateUrl : 'form-input-text.tmpl.html',
    scope: {
      model: {
        label: '@',
        value: '=ngModel'
      }
    }
  };
});

这将允许被遮挡的部分绑定到model.value,这将使更改对isolateScope可见,这又会将isolateScope中的更改传播回给appScope.

Angular似乎不直接支持这种用法.

谁能指出我支持此用例的Angular功能,或者如果不提供,请提供解决方法?

编辑:

现在,我的解决方案是将表单控制模板内联到form-input-text模板中.

form-input-text.tmpl.html

<div class="form-group">
  <label class="control-label col-sm-2">
    {{ label }}
  </label>
  <div class="col-sm-10">
    <input type="text"
           class="form-control"
           ng-model="value">
  </div>
</div>

这消除了ng-transclude引入的子范围,但是它也重复了标记,这就是我希望将其重构到一个地方的方法.

解决方法:

关于范围的思考实际上是在错误的轨道上进行的,而且我认为转换与它没有太大关系.要“正确”地执行此操作,应与ngModelController集成.这允许任何以后集成的解析器和格式化程序(可能包含验证逻辑)在适当的时间运行.这有一点复杂,因为您有2个:在应用程序中是父级,在指令模板中是父级,而每个都有2条“管道”要与之集成:

>模型值->查看价值
>查看价值->模型值

然后,将父ngModelController的视图值用作内部ngModelController的模型值.所以整体管道看起来像

>父模型值->父视图值->内部模型值->内在价值
>内部视图值->内部模型值->父视图值->父模型值

去做这个:

>确保您需要:指令定义中的“ ngModel”才能访问父级ngModelController
>从父ngModelController到内部的更改是使用父ngModelController的$render方法及其$viewValue完成的.这样可以确保父$formatters中的所有功能都已运行.
>用户通过internal指令启动的更改是通过在$viewChangeListeners数组中添加一个函数来完成的,该数组在父ngModelController上调用$setViewValue.要从链接函数范围访问此函数,您需要一个命名表单和输入元素.有点烦人的是,该表单仅在其链接功能运行后才在该指令的范围内注册,因此您需要一个观察者来访问它.
>以防万一,请确保formInputText中的模型在对象中. (我不确定这在技术上是否必要)
>然后,您无需将模型放在内部指令的作用域对象中.

放在一起

app.directive('formInputText', function() {
  return {
    restrict : 'E',
    templateUrl : 'form-input-text.tmpl.html',
    scope: {
      label: '@'
    },
    require: 'ngModel',
    link: function(scope, element, attrs, ngModelController) {
      scope.model = {};

      // Propagate changes from parent model to local
      ngModelController.$render = function() {
        scope.model.value = ngModelController.$viewValue;
      };

      // Propagate local user-initiated changes to parent model
      scope.$watch('form', function(form) {
        if (!form) return;
        form.input.$viewChangeListeners.push(function() {
          ngModelController.$setViewValue(form.input.$modelValue);
        });       
      });
    }
  };
});

它的模板看起来像

<form-control label="{{label}}" ng-form name="form">
  <input type="text"
         class="form-control"
         name="input"
         ng-model="model.value">
</form-control>

可以看到它在http://plnkr.co/edit/vLGa6c55Ll4wV46a9HRi?p=preview下工作

标签:angularjs,twitter-bootstrap,angularjs-scope,javascript
来源: https://codeday.me/bug/20191121/2049516.html