Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular directives: mixing attribute data and ngModel

I've had luck building directives that share scope, and ones that isolate scope, but I'm having trouble figuring out the correct way to do both.

<input type="text" ng-model="search" append-me terms="myTerms">

I'm trying to take an input like the one above, and staple a UL that ng-repeats over a list of attributes after it. I have two problems.

1) How do I correctly interface the shared ng-model scope?

2) What am I doing incorrectly with this compile function?

http://jsfiddle.net/vEQ6W/1/

like image 231
Eric_WVGG Avatar asked Nov 21 '13 21:11

Eric_WVGG


People also ask

Is NgModel structural directive?

Essentially, you are applying [ngModel] with an input, then automatically modifying a value based on its output. As such, NgModel is definitely an attribute directive.

What is [( NgModel )] used for?

The ng-model directive binds the value of HTML controls (input, select, text-area) to application data. It is a part of the FormsModule. This directive is used by itself or as part of a larger form. It accepts a domain model as an optional Input.

What is [( NgModel )] Angular?

Angular NgModel is an inbuilt directive that creates a FormControl instance from the domain model and binds it to a form control element. The ngmodel directive binds the value of HTML controls (input, select, textarea) to application data.

What is the difference between @component and @directive in Angular?

Component is used to break up the application into smaller components. But Directive is used to design re-usable components, which is more behavior-oriented. That is why components are widely used in later versions of Angular to make things easy and build a total component-based model.


1 Answers

Mixing isolated scope with ngModel is a documented issue, see the Isolated Scope Pitfall section in the documentation:

Isolated Scope Pitfall Note that if you have a directive with an isolated scope, you cannot require ngModel since the model value will be looked up on the isolated scope rather than the outer scope. When the directive updates the model value, calling ngModel.$setViewValue() the property on the outer scope will not be updated. However you can get around this by using $parent.

Using this knowledge and some freaky scope experiments I've come with two options that does what you want to do:

(1) See this fiddle It makes use of the $parent method as described above.

<div ng-controller="MyCtrl">
  <div>
    <input ng-form type="text" ng-model="$parent.search" append-me terms="myTerms">
  </div>
  {{search}}
</div>

myApp.directive('appendMe', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope: {terms: '='},
        link: function(scope, element, attributes) { // linking function
            console.log(scope.terms);
            var template = '<p>test</p>' + 
                '<ul><li ng-repeat="term in terms">{{term}}</li></ul>' +
                '<p>hm…</p>'
            element.after($compile(template)(scope));
        }
    }
}]);

(2) See this fiddle It does not use $parent, instead it uses the isolated scope to publish the search model as configured via ngModel.

<div ng-controller="MyCtrl">
    <div>
        <input ng-form type="text" ng-model="search" append-me terms="myTerms">
    </div>
    {{search}}
</div>

myApp.directive('appendMe', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope: {terms: '=', search: '=ngModel'},
        link: function(scope, element, attributes) { // linking function
            console.log(scope.terms);
            var template = '<p>test</p>' + 
                '<ul><li ng-repeat="term in terms">{{term}}</li></ul>' +
                '<p>hm…</p>'
            element.after($compile(template)(scope));
        }
    }
}]);

Both options seem to work just fine.

like image 61
Beyers Avatar answered Nov 03 '22 12:11

Beyers