Two-way Data Binding Broken


#1

Hello all! I have put hours googling on this but I just cannot understand what is going on. I need help. Thanks for reading:

I have a simple profile form that gets prepopulated when the view loads, the interesting part:

 Name: <input type='text' ng-model="profileedit_name">
 <button ng-click="doSaveProfileEdit()" >Save</button>

Now, the input boxes get prepopulated when the view loads, like this:

var responsePromise = $http({
  method: 'POST',
  url: 'ajax/get_profile.php',
  data: "userid=" + 0,
  headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});

responsePromise.success(function(data, status, headers, config) {
  $scope.profileedit_name = data['name'];
});   

This code sucessfully fetches the data (json array with name + more things) and puts it in the input/textareas.

I then manually edit (I click+type) on the NAME input field and change “Bob” to “Anastasia”

Then, using the button at the top this code runs:

$scope.doSaveProfileEdit = function() {
  alert($scope.profileedit_name);
}

In turn, that code is suposed to send the values to the server, but it sends the OLD “Bob” data which is no where to be seen in the view! The alert also shows “Bob”. If I manually edit the value just before the alert with:

$scope.profileedit_name = 'foo';

Then the alert goes “foo” as one would expect.

This is not working on desktop Firefox browser, stock safari on iPhone5 and stock browser on SamsunGalaxy S3 mini.

What is happening? Any help is very MUCH appreciated.

Ionic is 1.0.0-beta.4


#2

Try

 <input type='text' ng-model="profileedit_name">
 <button ng-click="doSaveProfileEdit(profileedit_name)" >Save</button>

with

$scope.doSaveProfileEdit = function(newName) {
  alert(newName);
}

#3

That worked! Thanks a million, that is exactly what I needed!

I have of course passed several variables not just one, so it may not look too clean but it works and you have saved me hours of head bashing a brick wall.

Thank you!


#4

There is a better way to deal with this. The main problem is that your are not using “dot notation”. Basically, when you get the data from the server and make this assignment $scope.profileedit_name = data['name'];, you are storing what’s known as a primitive. It’s a simple value. When AngularJS binds to that primitive, it uses “prototype inheritance”. In JavaScript, simple values are essentially just copies. There is no binding.

In order to create REAL binding, you need to be providing the model with REAL objects or arrays. In JavaScript, real objects or arrays get linked to. So, any changes are based up the chain.

Here’s how to handle this:


$scope.data = {};  // Create an object.
var responsePromise = $http({
  method: 'POST',
  url: 'ajax/get_profile.php',
  data: "userid=" + 0,
  headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});

responsePromise.success(function(data, status, headers, config) {
  $scope.data.profileedit_name = data['name']; // Put the received data in the object.
});
 Name: <input type='text' ng-model="data.profileedit_name">
 <button ng-click="doSaveProfileEdit()" >Save</button>

Now, because you used the data object in your model and in the HTML, it will be properly bound. When you trigger doSaveProfileEdit method, it will show you the proper value.

$scope.doSaveProfileEdit = function() {
  alert($scope.data.profileedit_name);
}

Here is the best source for really understanding this topic : https://github.com/angular/angular.js/wiki/Understanding-Scopes