Ng-model does not update controller value
Solution 1
Controller as version (recommended)
Here the template
<div ng-app="example" ng-controller="myController as $ctrl">
<input type="text" ng-model="$ctrl.searchText" />
<button ng-click="$ctrl.check()">Check!</button>
{{ $ctrl.searchText }}
</div>
The JS
angular.module('example', [])
.controller('myController', function() {
var vm = this;
vm.check = function () {
console.log(vm.searchText);
};
});
An example: http://codepen.io/Damax/pen/rjawoO
The best will be to use component with Angular 2.x or Angular 1.5 or upper
########Old way (NOT recommended)
This is NOT recommended because a string is a primitive, highly recommended to use an object instead
Try this in your markup
<input type="text" ng-model="searchText" />
<button ng-click="check(searchText)">Check!</button>
{{ searchText }}
and this in your controller
$scope.check = function (searchText) {
console.log(searchText);
}
Solution 2
"If you use ng-model, you have to have a dot in there."
Make your model point to an object.property and you'll be good to go.
Controller
$scope.formData = {};
$scope.check = function () {
console.log($scope.formData.searchText.$modelValue); //works
}
Template
<input ng-model="formData.searchText"/>
<button ng-click="check()">Check!</button>
This happens when child scopes are in play - like child routes or ng-repeats.
The child-scope creates it's own value and a name conflict is born as illustrated here:
See this video clip for more: https://www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s
Solution 3
In Mastering Web Application Development with AngularJS book p.19, it is written that
Avoid direct bindings to scope's properties. Two-way data binding to object's properties (exposed on a scope) is a preferred approach. As a rule of thumb, you should have a dot in an expression provided to the ng-model directive (for example, ng-model="thing.name").
Scopes are just JavaScript objects, and they mimic dom hierarchy. According to JavaScript Prototype Inheritance, scopes properties are separated through scopes. To avoid this, dot notation should use to bind ng-models.
Solution 4
Using this
instead of $scope
works.
function AppCtrl($scope){
$scope.searchText = "";
$scope.check = function () {
console.log("You typed '" + this.searchText + "'"); // used 'this' instead of $scope
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="AppCtrl">
<input ng-model="searchText"/>
<button ng-click="check()">Write console log</button>
</div>
</div>
Edit: At the time writing this answer, I had much more complicated situation than this. After the comments, I tried to reproduce it to understand why it works, but no luck. I think somehow (don't really know why) a new child scope is generated and this
refers to that scope. But if $scope
is used, it actually refers to the parent $scope because of javascript's lexical scope feature.
Would be great if someone having this problem tests this way and inform us.
Solution 5
I had the same problem and it was due to me not declaring the blank object first at the top of my controller:
$scope.model = {}
<input ng-model="model.firstProperty">
Hope this will works for you!
Related videos on Youtube
alchemication
Updated on March 24, 2021Comments
-
alchemication about 3 years
Probably silly question, but I have my html form with simple input and button:
<input type="text" ng-model="searchText" /> <button ng-click="check()">Check!</button> {{ searchText }}
Then in the controller (template and controller are called from routeProvider):
$scope.check = function () { console.log($scope.searchText); }
Why do I see the view updated correctly but undefined in the console when clicking the button?
Thanks!
Update: Seems like I have actually solved that issue (before had to come up with some workarounds) with: Only had to change my property name from
searchText
tosearch.text
, then define empty$scope.search = {};
object in the controller and voila... Have no idea why it's working though ;]-
wroniasty over 11 yearsare you sure you are using this controller in this part of the document? can you post a minimal failing example?
-
alchemication over 11 yearsYes, 100% sure the controller is ok, that issue seems to be familiar to me... Surprisingly it works when I change the property name from
searchText
tosearch.text
, any idea why?? -
Arthur Frankel almost 11 yearsThis is a great question. I ran across the same issue and following the "Update" block solved it for me as well. I'm very curious as well why this solution works - or more importantly why can't I just a $scope.var and have it updated by angular.
-
alchemication almost 11 years@Arthur: It's kinda not obvious but ng-model only creates a sort of speak local variable in your view, there fore if you want to keep it this way you would need to pass it into the check() function, like: check(searchText) and your controller will recognise it then. Hope it helps
-
Arthur Frankel almost 11 yearsThanks, but why does your hash solution work (i.e., hash var vs. regular var)?
-
Dan Bechard over 9 yearsFor the record, it's spelled
voila
, notvuala
,wolla
, etc. -
Willa over 8 yearsI think the answer you are looking for is at stackoverflow.com/a/14049482/1217913
-
Kalamarico almost 7 yearsGreat explanation in that link Willa, thanks!
-
-
alchemication over 11 yearsHmmmm.. thanks for looking into this, I would presume that it should work... why isn't it working for me? And what's more important: Why does it work with objects and doesn't with plain string variables?? Maybe cause I refer my controllers in an in-appropriate way in the routeProvider?? Was trying to avoid globals and have put my controllers as modulename.ctrlName into controllers.js file. Could that cause a headache?
-
ganaraj over 11 yearsI am not really sure why it doesnt work for you. If you could isolate this issue in a fiddle, I guess someone would be able to give you a better answer :)
-
alchemication over 11 yearsOkay, will do, just finishing work now but will do that for sure tomorrow or later in the evening, cheers! There might be a problem with the way I've namespaced my ctrl's, we'll see...
-
alchemication over 11 yearsThanks!! That is perfect (and also solving a lot of issues I had in the past)! +1 ;)
-
cdmckay almost 11 yearsThis only works one-way... what if you want to change the value of
searchText
? -
cdmckay almost 11 yearsThis also doesn't answer the "why?" question.
-
danikoren over 10 yearswhat if i don't want to use any button? i need to submit on enter for instance
-
Damax over 10 yearsSaniko => To submit on enter, you must use form tag and ng-submit on it (docs.angularjs.org/api/ng.directive:ngSubmit)
-
keslert almost 10 yearsThis is the real answer.
-
Catfish almost 10 yearsThis worked for me, but can you elaborate on "this quirk" in javascript?
-
Will Stern almost 10 years@Catfish With prototypal inheritance, whenever you write to the child property, the reference/connection to the parent property ceases to exist. The way Angular Scopes models, if you don't have a dot, then a new property within your child scope is created. This video explains it in more detail: youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m
-
zashu over 9 years@cdmckay - It has to do with the way scopes are inherited via ng-model and the fact that the data is a String (a primitive) and thus not updated by reference. See Will Stern's answer.
-
Don Barry over 9 yearsGracias Boss. This is true! However, it doesnt seem to be a consistent quirk as I encounter the problem only when using with Ionic framework
-
Reza over 9 yearsCould you explain why this happens?
-
Will Stern over 9 years@RezaRahmati When you try to access a property on a child scope, it first checks the child...if not found, it checks the parent for that property and so on. If the child adds the property, it now no longer looks to the parent property, it will always modify the child property of the same name leaving the parent property untouched.
-
user3677331 almost 9 yearsHere it works without a dot. It mostly works without a dot and sometimes only it doesn't. Haven't noticed a pattern, have you?
-
Will Stern almost 9 years@user3677331 It works fine without a dot until you have a child scope that tries to talk to it (like an item within an ng-repeat for example). Say your model name was "phone" Your child scope creates "phone", then you get a scope conflict because child-scope has a "phone" variable and thus can't access "phone" on the parent scope. Whereas if the child scope creates user.phone, it will be added to the parent's user object so both scopes are pointing to the same object
-
fjcero almost 9 yearsFlawless, you're a genius
-
Jakub Kotrs almost 9 yearsThank you, but for me it works without
.$modelValue
. Maybe newer version. -
CodeManiak almost 9 yearsVery helpful. I wasn't sure I would locate an answer to a relatively vague question but this was dead on.
-
Kings over 8 yearsthanks for this reference. I consider this an interesting point related with ng-model.
-
Xun Yang over 8 yearsLooks like the functions attached to
$scope
creates a new scope(i.e. in functioncheck()
,this
refers to a scope that's a child scope of$scope
). Why is it so? Can you give some explanations? -
Rashedul.Rubel about 8 yearswhy should i use 'this' instead of '$scope' in this case? because it worked using $scope in my previous project but this time same thing does not work using $scope. But 'this' has worked. Why is that?
-
devios1 about 8 yearsAngular really should at least warn you if you attempt to bind directly to a scope property for this very reason. It seems this is confusing a lot of people (myself included).
-
Shri about 8 yearsthis works, but if you say
this.searchText = "something else"
or even if$scope.searchText = "something else"
, it doesn't update the view. can you explain this problem? -
Feyyaz about 8 yearsit should. I tried it using the code above, it updated the view.
-
thethakuri about 8 yearsLittle off topic here, but 'data' is a plural term for 'datum'
-
Hasan Tuna Oruç almost 8 yearsperfect solution. thanx.
-
skmasq almost 8 yearsThank you, saved so much time. Works with angular 1.0.8
-
Wand Maker almost 8 yearsThanks, I wasted couple of hours with this issue - luckily I hit this answer.
-
EpicPandaForce almost 8 years@thethakuri and "datum" in hungarian is "date", so I sure wouldn't use that either :P
-
Hardik Bharadava over 7 years@kba I'm having the Same Problem. Angular's ng-model behaviour is if it is changed it will be changed into Controller also. but why this happens, can anyone explain, what is the issue?
-
Damax over 7 years@HP's411 it's because a string is a primitive. When Angular assign the value it change the pointer to the value, so the controller looks at the old value because it have the old pointer to the value.
-
Nico Westerdale about 7 yearsI prefer waffle house to IHOP
-
Dheeraj Avvari about 7 yearsYou are a life saver! Thanks for the Answer @Damax
-
V31 almost 7 yearsthanks for the answer, however y is this working? it should ideally be working on the same scope element right and not the parent?
-
Nico Westerdale over 6 yearsIt's depressing that this rule is not shown in many places on the web. e.g. w3schools.com/angular/angular_model.asp which is incorrect.
-
Jiro Matchonson over 5 yearsThat was a nasty one, tnx much!, I had input ng-model="email" and ng-model="userPassword". First one worked the second one no. After adding dots everything work but I would specify this as an Angular bug.