AngularJS - bind ng-model to a variable which name is stored inside another variable

I'm trying to bind the value of an input field to a variable. I don't know the name of this variable a priori; it is stored in another variable.

This is the html:

<body ng-controller="stageController">
    <form name="myForm" novalidate="">
        <input type="text" name="myText" ng-model="model" />
    </form>
</body>

and this is the controller:

function stageController($scope) {
    $scope.model = 'realModel'; // contains the name of the variable that i would bind to the field 
    $scope.realModel = 'initial value of the field';
}

I made also a fiddle.

This doesn't work because currently the binding is between the input field and the model variable. Instead I would bind the input field to the variable which name is stored inside the $scope.model variable (in this case realModel).

Is it possible? How?

Answers:

Answer

Yes, its possible. I dont understand why you'd want to do it, but I can show you how to. I couldnt start the fiddle, but I copied to a plnkr: http://plnkr.co/edit/o1gFf1lMq4Pg5iVoVyUN?p=preview

You create a directive that transform the original template into a new one using $compile. The new directive:

directive('ngBindModel',function($compile){
    return{
        compile:function(tEl,tAtr){
          tEl[0].removeAttribute('ng-bind-model')
            return function(scope){
              tEl[0].setAttribute('ng-model',scope.$eval(tAtr.ngBindModel))
              $compile(tEl[0])(scope)
                console.info('new compiled element:',tEl[0])
            }
        }
    }
})

Updated html (change from ng-model to ng-bind-model, the new directive)

<input type="text" name="myText" ng-bind-model="model"  />
Answer

A simpler alternative - provided it is possible to change the model a little bit - HTML:

<body ng-controller="stageController">
    <form name="myForm" novalidate="">
        <input type="text" name="myText" ng-model="vars[model]" />
    </form>
</body>

Model:

function stageController($scope) {
    $scope.model = 'realModel'; // contains the name of the variable that i would bind   to the field 
    $scope.vars = {};    // variables container
    $scope.vars.realModel = 'initial value of the field';
}
Answer

I tried to use the previous answer inside ng-repeat and it didn't work. It uses the compile function, which means all the directives used the last passed in value. If you use the link function it seems to work as expected, i.e.

.directive('ngBindModel',function($compile){
      return{
        link:function(scope,element,attr){
          element[0].removeAttribute('ng-bind-model');
          element[0].setAttribute('ng-model',scope.$eval(attr.ngBindModel));
          $compile(element[0])(scope);
        }
      };
    })
Answer

The (currently winning) answer by user2273266 is actually subtly incorrect. While it will work if you only use the directive once, it actually confuses the template element and instance element objects, and will put the last name it finds on ALL elements it renders within a loop, for example.

directive('custBindModel',function($compile){
    return{
        compile:function(tEl){
            tEl[0].removeAttribute('cust-bind-model');
            return function(scope, iEl, iAtr){
                iEl[0].setAttribute('ng-model',scope.$eval(iAtr.custBindModel));
                $compile(iEl[0])(scope);
                console.info('new compiled element:',tEl[0]);
            }
        }
    }
})

This version corrects the problem by separating operations on the template and instance, so the post-link call only modifies the instance and not the template.

Also changed the 'ng' prefix which is reserved.

Answer

I am relatively new to Angularjs. I know what you are asking for is possible in Javascript using window. I am not sure about Angular. I have modified the code to achieve a near possible solution:

 $scope.model = {'var':'realModel','value':'initial value of the field'};

Try the fiddle:

Answer

What you are missing here is the ng-app directive, there is no need to use explicit directives for ng-model.

This works:

<body ng-app="myApp" ng-controller="stageController">
    <form name="myForm" novalidate="">
        <input type="text" name="myText" ng-model="realModel" />
    </form>
<script>
var app = angular.module('myApp', []);
app.controller('stageController', function($scope) {
    $scope.model = 'realModel'; 
    $scope.realModel = 'initial value of the field';
})
</script>
</body>

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.