4

I have a directive that will use ng-model to expose its value.

The question is that this directive have internal components that will also mess the scope, so I need to isolate its scope, but still preserve ng-model bind to outside world.

How would I achieve this?

This is the directive:

angular.module('app', []).directive('myDirective', function() {
  return {
    restrict: 'E',
    require: 'ngModel',
    link: function(scope, element, attr, ngModel) {
      // do stuff using ngModel controller
    },
    replace: true,
    template: '<div><input ng-model="userInput" /></div>'
  };
});
<my-directive ng-model="prop"></my-directive>

As you can see, the directive must expose prop as its value, but should not expose userInput in the parent scope, defined in <input ng-model="userInput"/>.

How would I be able to make only prop available in the parent scope?

Tom
  • 26,212
  • 21
  • 100
  • 111
Caio Cunha
  • 23,326
  • 6
  • 78
  • 74
  • What do you want to do with `prop` inside the directive? Will it become be part of a field element? Also, the `ngModel` you show -- is that intended for `prop` or `userInput`? – Mark Rajcok Mar 12 '13 at 17:49
  • I need two `ng-model`s. The one from input will be the user input. My directive controller will `$watch` for changes in it, complement and update `prop` using `ngModelController.$setViewValue()`. I know I could listen to input events and avoid the internal `ng-model`, but in future, I'll have more elements sharing the same internal scope properties. So I'd like to have an isolated scope where internal elements can play, but still would like to have `ng-model="prop"` bound to parent scope. I'll also use validity feature from external `ng-model`. – Caio Cunha Mar 12 '13 at 17:59

1 Answers1

3

Normally, ngModelController is meant to be used with directives that do not create a new scope. The only way I've found to get it to work with an isolate scope is to use the same name in the isolate scope:

scope: { prop: '=ngModel' }  // must use 'prop' here!

For more discussion on this, see my SO answer: https://stackoverflow.com/a/14792601/215945

You can also have the directive create a new scope using scope: true. If you do this, then prop would need to be an object property, not a primitive: e.g., ng-model='someObj.prop'. For more on this approach, see the first fiddle of this https://stackoverflow.com/a/13060961/215945

This would still allow you to create your own (new) properties on the new directive child scope, without affecting the parent scope. Well, you need to be aware of how scope prototypal inheritance works somewhat -- objects defined on the parent scope will be visible and changeable in the directive child scope. Primitives defined on the parent scope will be visible, but if you try to change the value of a parent primitive you'll end up creating a child property that hides/shadows the parent property of the same name. (Lots more info about prototypal inheritance can be found here.)

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • I know about the bidirectional-binding trick you suggest, but I can't force user to use always the same property. Another approach I tried (and works) is to remove `ng-model` from external element and defining it in the template, `` --> `scope: {internalBind: '=some'}` --> `template:
    ...
    `. It's just that I'd like to let the user explicitly use `ng-model`, so he knows he can count with this element as a control in a `form`, for example.
    – Caio Cunha Mar 12 '13 at 19:31
  • @CaioToOn, just curious, you didn't like the `scope: true` alternative? (That's what I would use here.) That should give you want you want, as long as an object property is used (which is what the Angular team recommends -- i.e., they recommend not using primitives for ng-model: [Misko](http://youtu.be/ZhfUv0spHCY?t=30m).) – Mark Rajcok Mar 12 '13 at 19:41
  • Thanks for insisting. It's just that setting the value to `undefined` when there is an invalid value would suit better my design. I liked the idea of isolating the scope, anyway. I'm just starting wondering if what I wish is anti-pattern, or at least anti-natural, or if this is a common necessity: to be able to choose which properties remain linked with parent by its attribute name, without needing to define property name. – Caio Cunha Mar 12 '13 at 19:58