vrghost
vrghost

Reputation: 1212

Creating a ngModel dual binding in a directive

Trying to write a angular model that allows for a two way binding, I.E. where it has a ng-model variable, and if the controller updates it, it updates for the directive, if the directive updates it, it updates for the controller.

I have called the controller scope variable ng-model, and the directive model bindModel. In this case it sends an array of data, but that should not make a difference to how the binding works (I think at least).

So first the mapping, this is how the initial directive looks (link comes later).

return {
    link: link,
    scope: { cvSkills: '=',
        bindModel:'=ngModel'},
    restrict: 'E'

}

My understanding is (and I am uncertain about the exact scope at this moment) the directive will be aware of cvSkills (called cvSkills internally, and used to provide intial data), and bindModel which should pick up whats in ng-model). The call in html is:

<skilltree cv-skills="cvskills" ng-model="CV._skillSet"></skilltree>

So the variables aren't actually (quite) in the directive yet. But there is an awareness of them, so I created two watchers (ignoring the cvskills one for now)

   function link(scope,element, attr){
        //var selected = ["55c8a069cca746f65c9836a3"];
        var selected = [];
        scope.$watch('bindModel', function(bindModel){
            if (bindModel.length >> 0) {
                console.log("Setting " + bindModel[0].skill)
                selected = bindModel;
            }
        })
        scope.$watch('cvSkills', function(cvSkills) {

So once the scope.$watch sees an update to bindModel, it picks it up and stores it to selected (same happens separately with cvSkills). In cvskills I then do updates to selected. So it will add additional data to selected if the user clicks buttons. All works and nothing special. My question is now. How do I then update bindModel (or ngModel) when there are updates to selected so that the controllers scope picks it up. Basically, how do I get the updates to propagate to ng-model="CV._skillSet"

And is this the right way to do it. I.E. make the scope aware, than pick up changes with scope.$watch and manually update the variable, or is the a more "direct" way of doing it?

=================== Fix using ngModel ===================

As per the article, if you add require: "ngModel" you get a fourth option to the function (and skip having a binding between ngModel and bindModel).

return {
    link: link,
    require: 'ngModel',
    scope: { cvSkills: '='},
    restrict: 'E'

}

Once you have done that, ngModel.viewValue will contain the data from ngModel= , in my case I am updating this in the code (which may be a bad idea). then call ngModel.setViewValue. It is probably safeish if you set the variable and then store it straight away (as follows)

function link(scope,element, attr, ngModel){

ngModel.$render =  function()  {
    console.log("ngRender got called " + ngModel.$viewValue );

} ;
....
ngModel.$viewValue.push(newValue);
ngModel.$setViewValue(ngModel.$viewValue)

================= If you don't care about viewValue ================== You can use modelValue instead of viewValue, and any updates to modelValue is propagated straight through. function link(scope,element, attr, ngModel){

ngModel.$render =  function()  {
    console.log("ngRender got called " + ngModel.$modelValue );

} ;
....
ngModel.$modelValue.push(newValue);

Upvotes: 0

Views: 204

Answers (1)

Walfrat
Walfrat

Reputation: 5353

Using the require attribute of the directive you can have the controller API from ngModel directive. So you can update values.

Take a look at this very simple demo here : https://blog.hadrien.eu/2015/01/16/transformation-avec-ngmodel/

For more information here is the documentation : https://docs.angularjs.org/#!/api/ng/type/ngModel.NgModelController

Upvotes: 1

Related Questions