最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I bind ngModel through multiple directives with isolate scopes in AngularJs? - Stack Overflow

programmeradmin11浏览0评论

I am trying to bind to a property via ngModel in a layer of directives 3 levels deep. This would be fine, except the middle level contains a ng-if which I believe creates a new scope. The binding is lost at this point.

I have created a jsfiddle to explain the situation: /

Note that it works if the ng-if directive is removed, but I am using ng-if instead of ng-show for performance reasons

Does anyone know how I can get the original ngModel to update from the 'inputDirective' template in the fiddle?

I am trying to bind to a property via ngModel in a layer of directives 3 levels deep. This would be fine, except the middle level contains a ng-if which I believe creates a new scope. The binding is lost at this point.

I have created a jsfiddle to explain the situation: http://jsfiddle/5fmck/2/

Note that it works if the ng-if directive is removed, but I am using ng-if instead of ng-show for performance reasons

Does anyone know how I can get the original ngModel to update from the 'inputDirective' template in the fiddle?

Share Improve this question asked Apr 9, 2014 at 4:52 Erin DrummondErin Drummond 5,5266 gold badges36 silver badges41 bronze badges 1
  • Interesting question. Went to play jsfiddle – Miraage Commented Apr 9, 2014 at 5:04
Add a ment  | 

2 Answers 2

Reset to default 5

Simple :3

Just remember, that child scope is created = use reference to $parent :)

<div ng-if='someCondition'>
    <span>In Wrapper</span>
    <input-directive ng-model='$parent.ngModel'></input-directive>
</div>

http://jsfiddle/5fmck/3/

// upd

As I know you need to use reference to $parent only if ngModel is primitive, not object.

I suspect this is due to the nature of how scopes inherit from each other, and so you should use objects on the scope, and not primitives, and always pass the objects into directives via attributes if it's to be then to be used in another scope. So instead of:

$scope.test = "test";

and

<wrapper-directive ng-model="test" some-condition="true">

use:

$scope.userInput = {
  test: "Test"
}

and

<wrapper-directive user-input="userInput" some-condition="true"> 

Which can be seen at http://jsfiddle/4RBaN/1/ (I've also changed all-but-one of the ngModels to another custom attribute, as if you're not using ngModel specific things, like ngModelController, or integration with ngForm, then I think better to KISS).

The reason is that if you have 2 scopes in a parent/child relationship (via prototypical inheritance), such as the one created by ngIf, if you execute (or if Angular executes):

$parentScope.test = 'test';
$childScope.test = 'My new value';

Then $parentScope.test will still equal 'test'. However, if you use objects:

$parentScope.userInput = {test: 'test'}
$childScope.userInput.test = 'My new value';

Then $parentScope.userInput.test will then equal 'My new value'.

The standard quote from (whom I believe was) the original author of Angular, is "If you haven't got a dot in your model, you're doing it wrong". There are other questions on SO about this, such as If you are not using a .(dot) in your AngularJS models you are doing it wrong?

Edit: If you do want to use ng-model, and always pass a primitive to the directive, and not an object, then there is a way that allows this. You'll need to:

  • Always ensure there is a dot in the model that is passed to ngModel, in every directive. Each directive therefore needs to create a new object on its scope in its controller (or linking function). So the template for your 'middle' directive will be:

    <input-directive ng-model='userInput.test'>
    

    And in its controller:

    $scope.userInput = {
      test: $scope.ngModel   
    }
    

    Where ngModel is bound to the value specified in the directive's attributes:

    "scope" : {
      "ngModel" : "="
    }
    
  • Set up manual watchers in each directive, so that changes to the model from the inner directives get propagated back up the chain:

    $scope.$watch('userInput.test', function(newTest) {
      $scope.ngModel = newTest;    
    });
    

This can be seen at: http://jsfiddle/zT9sD/ . I have to say, it feels a bit plicated, so I'm not quite sure I can remend it. Still, (in my opinion) better than using $parent, as introducing a new scope can quite easily happen as things get more plicated, and then you'll have to use things like $parent.$parent.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论