AngularJS - how to change the value of ngModel in custom directive?
Solution 1
There are different ways of doing it:
-
$setViewValue()
updates the view and the model. Most cases it is enough. - If you want to disconnect view from the model (e.g. model is a number but view is a string with thousands separators) then you could access directly to
$viewValue
and$modelValue
- If you also want to overwrite the content of
ng-model
(e.g. the directive changes the number of decimals, updating also the model), injectngModel: '='
on the scope and setscope.ngModel
e.g.
return {
restrict: 'A',
require: 'ngModel',
scope: {
ngModel: '='
},
link: function (scope, element, attrs, ngModelCtrl) {
function updateView(value) {
ngModelCtrl.$viewValue = value;
ngModelCtrl.$render();
}
function updateModel(value) {
ngModelCtrl.$modelValue = value;
scope.ngModel = value; // overwrites ngModel value
}
...
LINKS:
- 1st option is discussed here
- NgModelController official docs
Solution 2
To work with complex binding expressions you should use the $parse service and the assign
method.
For more information watch this video from ng-conf - it's all about the cool things you can do with the ng-model directive: https://www.youtube.com/watch?v=jVzymluqmg4
app.directive('datepicker', ['$parse',
function($parse) {
return {
require: '?ngModel',
link: function(scope, element, attributes, controller) {
// $parse works out how to get the value.
// This returns a function that returns the result of your ng-model expression.
var modelGetter = $parse(attributes['ngModel']);
console.log(modelGetter(scope));
// This returns a function that lets us set the value of the ng-model binding expression:
var modelSetter = modelGetter.assign;
// This is how you can use it to set the value 'bar' on the given scope.
modelSetter(scope, 'bar');
console.log(modelGetter(scope));
}
};
}
]);
Solution 3
What you tried is actually working: see this Plunker
You don't "see" it in the input because changing the model this way doesn't call controller.$render()
to set the new controller.$viewValue
.
But why don't you simply change the $scope
value (unless you don't know it, but it would be weird):
angular.module('main').directive('datepicker', [function() {
return {
require: '?ngModel',
link: function(scope, element, attributes, controller) {
var model = attributes['ngModel'];
scope[model] = 'bar';
}
};
}]);
And in your html:
<input ng-model="yourVariable" datepicker>
EDIT: (dynamic solution)
angular.module('main').directive('datepicker', [function() {
return {
require: '?ngModel',
link: function(scope, element, attributes, controller) {
// get the value of the `ng-model` attribute
var model = attributes['ngModel'];
// update the scope if model is defined
if (model) {
scope[model] = 'bar';
}
}
};
}]);
Solution 4
Here's the best explanation I've encountered. This helped me big time, and brings together details from a number of the other answers here.
TIP: Be careful to read the whole article rather than skim it, or else you are likely to miss some key bits!
https://www.nadeau.tv/post/using-ngmodelcontroller-with-custom-directives/
Solution 5
This works for a DatePicker
on my site
link: function(scope, elem, attrs, ngModel) {
scope.$apply(function(){
ngModel.$viewValue = value;
}
}
Related videos on Youtube
Sady
Updated on July 09, 2022Comments
-
Sady almost 2 years
Lets take a look to my directive:
angular.module('main').directive('datepicker', [ function() { return { require: '?ngModel', link: function(scope, element, attributes, ngModel) { ngModel.$modelValue = 'abc'; // this does not work // how do I change the value of the model?
So, how do I change the value of the ng-model?
-
glepretre over 10 yearsWhy don't you change the
$scope
value related? For now I've only used$modelValue
to read it. Btw, the fourth attribute of the link function isngModelController
in your case, you should call itcontroller
;) -
Sady over 10 years@glepretre, how can I use scope? model is passing via html like this
<input ng-model="anythingModel">
and I dont know the name of the model to use it with scope. and aboutcontroller
call. Take a look at linkthis, how do they call it. But its wrong too, I think the best name probably will bengModelCtrl
-
vaske almost 9 yearsI tried all solutions from here but neither is supposed to work :(
-
-
Sady over 10 yearsbut what if I change
<input ng-model="yourVariable" datepicker>
to<input ng-model="myVariable" datepicker>
. How directive will react? Note, that I need reusable directive -
glepretre over 10 yearsYour directive is reusable but
ng-model="foo"
must match$scope.foo
to work, that's the point. I edited my answer to provide another solution to make it more dynamic. -
Sady over 10 yearsits still not reusable enough. What if I use complex models as
users[0].educations[1].name
? -
Alex Lapa about 9 yearsIt will not work if your ngModel is bound to smth like "objectOnScope.nestedValue"
-
glepretre about 9 years@AlexLapa Yes I know, it was not required in the question. That's why I did not used
$parse
in my answer but I'm a fair-player, I upvoted Sly_cardinal's one :) -
vaske almost 9 yearsI tried this one but still do not update model on page.
-
dball almost 9 yearsCan you post your html?
-
vaske almost 9 yearsI was desperate and this is my question stackoverflow.com/questions/31122371/…
-
Volte over 8 yearsAhhh! Finally. Thanks "brah"! I missed the
scope ngModel: '='