Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restangular caches attributes #811

Closed
daveroberts opened this issue Aug 1, 2014 · 17 comments
Closed

Restangular caches attributes #811

daveroberts opened this issue Aug 1, 2014 · 17 comments
Labels

Comments

@daveroberts
Copy link

I have a save function where I want to change / add properties before save:

$scope.save = function(person){
  person.name = "Overwriting property name";
  person.hobby_ids = [1,2,3];
  person.save();
};

Neither the new name, nor the hobby_ids is placed into the PUT request for the person. At the start of the save function, person did have a name, but not hobby_ids. The old name was placed into the PUT request.

@bvaughn
Copy link
Contributor

bvaughn commented Aug 2, 2014

This is incorrect. Nowhere in the Restangular source is $watch used or referenced, so no async updating/caching is being done.

I also tried this myself just now (via the JS console) and confirmed that attributes modified immediately before a call to save (aka PUT) is made are passed through.

Maybe if you included a little more context we could spot the problem?

@daveroberts
Copy link
Author

I created a very small application that simulates the problem here: https://github.com/daveroberts/restangular_test

The instructions to run the code are in the README file, but here are the highlights. The application is a simple user edit form. The form lets you change the person's name:

<div ng-controller="person_edit_controller">
  <h1>Edit {{person.name}}</h1>
  <form>
    <div>Name: <input type="text" ng-model="person.name" /></div>
    <button ng-click="save(person)">Save</button>
  </form>
</div>

The user is retrieved with the following json:

{"id":1,"name":"Jon"}

After clicking save, the person's name is changed to "Hard coded", and hobby_ids are set onto the person:

var app = angular.module('myapp', ['restangular']);
app.controller('person_edit_controller', function($scope, Restangular){
  $scope.person = Restangular.one('people', 1).get().$object;
  $scope.save = function(person){
    person.name = "Hard coded";
    person.hobby_ids = [1,2,3];
    person.save();
  };
});

Restangule submits a PUT request to /people/1 as expected, but the parameters that are sent an incorrect:

Processing by PeopleController#update as HTML
  Parameters: {"id"=>"1", "name"=>"Jon", "person"=>{"id"=>"1", "name"=>"Jon"}}

The expected result is that the person's name is sent as "Hard coded", and hobby_ids are included.

@bvaughn
Copy link
Contributor

bvaughn commented Aug 4, 2014

Ah, you're right! Looks like it's related to issue #55 but specific to $object.

You can work around this bug in the meanwhile by changing your controller code to:

Restangular.one('people', 1).get().then(function(data) {
  $scope.person = data;
});
``1

@daveroberts
Copy link
Author

Thank you, that work around seems to work. For now we will avoid using $object, and look forward to a bug fix in a future release.

One more question: The params which are sent to the server are in this format:
Parameters: {"id"=>"1", "name"=>"Hard coded", "hobby_ids"=>[1, 2, 3], "person"=>{"id"=>"1", "name"=>"Hard coded"}}

As you can see, the parameters are sent twice, and the hobby_ids are only sent at the "root" level. Is it possible to adjust how the parameters are sent so that they are not sent twice? Is it possible to adjust what the root element should be (or if there should be one at all?)

@bvaughn
Copy link
Contributor

bvaughn commented Aug 6, 2014

Sorry mate. Been a long day at work.

Pretty sure this confusion is just arising from Rails' logging. Watching Chrome's Network tab I see the following request data going out to http://localhost:4321/people/1:

{
  "id":1,
  "name":"Jon!!!!",
  "hobby_ids":[1,2,3]
}

The Rails log shows the following:

Parameters: {"id"=>"1", "name"=>"Jon!!!!", "hobby_ids"=>[1, 2, 3], "person"=>{"id"=>"1", "name"=>"Jon!!!!"}}

So the person is the updated model, ignoring parameters (like hobby_ids) that don't map to columns in the DB.

@mgonto
Copy link
Owner

mgonto commented Aug 7, 2014

@bvaughn thanks for the help :).

@daveroberts can you move the sample to a JSFiddle or plunkr so that it's easier to debug please?

It does seem a bug indeed with $object usage. If you can create the sample on JSFiddle, I'll try it out.

For the API, you can use http://node-backend-todo.herokuapp.com/api/todos which supports all CRUD operations on TODOs :).

@mgonto mgonto added bug labels Aug 7, 2014
@daveroberts
Copy link
Author

JS Fiddle: http://jsfiddle.net/daveroberts/xur4dqsp/

See the screenshot below of the error in action. It shows the chrome debugger's network tab for the put request to the server. As stated above, I expect the application to send the hard coded name and the hobby_ids array. Instead, the original, cached values of the todo are sent.

restangular_error

@mgonto mgonto added this to the 1.5.0 milestone Aug 17, 2014
@Climax777
Copy link

I'm suffering from the same problem also. $object doesn't work as expected. This is kind of a blocker for me. I cant believe it hasn't come up more often.

@daveroberts
Copy link
Author

@Climax777 : There's a workaround. Use the promise instead.

Not working: $scope.thing = Restangular.one('things', 7).get().$object;

Working:

Restangular.one('things', 7).get().then(function(t){
$scope.thing = t;
});

@ShaunSpringer
Copy link

Adding to this thread. We are having issues ONLY on top level objects. For instance:
device = {
name: 'Device Name',
settings: {
power: false,
value: '00FF00'
}

Anytime device.settings.power or device.settings.value changes, a save works fine, but if device.name changes, it seems to only send the original data.

It is in fact fixed with the workaround mentioned above.

@TzipporahWitty
Copy link

Still an issue for me - workaround by Restangular.copy on element before saving, but I'd much appreciate a real fix.

@muenchdo
Copy link

In combination with #697 (Cloning sets fromServer to true) this is a real issue. I can't save my newly created objects because when doing the Restangular.copy workaround, Restangular performs a PUT request which is rejected by my server. Does anyone know of another workaround? A real fix would also be greatly appreciated.

@philippeluickx
Copy link

I can confirm that by using $object, you can not simply do a put(). It will send the old object. When using the .then(success, failure) approach, everything works fine.

@akomm
Copy link

akomm commented Nov 18, 2015

I'm not sure if that is the same issue. I'm using angular.copy. The copy is modified properly - at least checking via console.log before saving - but the request payload contains old data.

@ConcurrentHashMap ConcurrentHashMap removed this from the 1.5.0 milestone Feb 19, 2016
@hartz89
Copy link

hartz89 commented Mar 31, 2016

@akomm there's a section in the docs about using angular.copy():
https://github.com/mgonto/restangular#copying-elements

Before modifying an object, we sometimes want to copy it and then modify the copied object. We can't use angular.copy for this because it'll not change the this binded in the functions we add to the object. In this cases, you must use Restangular.copy(fromElement).

@daviesgeek
Copy link
Collaborator

I updated the fiddle (it was using Underscore instead of Lodash).

I can also confirm the bug after playing around with the fiddle. If I have some time, I'll see if I can track down the problem.

http://jsfiddle.net/daviesgeek/qo6wd3Lh/

@daviesgeek
Copy link
Collaborator

Closing as a duplicate of #579. Tracking changes there…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests