简体   繁体   中英

Changing data returned from service changes data in service too

When I store data returned from a service in my controller and then edit it, it also changes the data in the service.

JSFiddle Demo

 /* The backend connection part and the actual markdown editor JS have been removed because it would just make the code huge and is irrelevant to the problem */    

var myApp = angular.module('myApp', []);

// In my app, this service caches blog post data from my server on the client side and returns single posts from it
myApp.factory('PostService', function ($log, $filter, $http) {
    var data;

    // Just an example for data pulled from server
    data = [{
        id: 99999,
        text: "Hello"
    }];

    // Function for returning a post out of the data array loaded from the server
    var getData = function (id) {
        if (id !== undefined) {
            var arr = $filter('filter')(data, {
                id: id
            });
            if (arr.length === 0) {
                $log.error('PostService:: getData(' + id + '):: Post Not Found');
                return 'not_found';
            } else {
                $log.debug('PostService:: getData(' + id + '):: Post returned');
                return arr[0];
            }
        } else {
            return data;
        }
    };
    return {
        getData: getData            
    };
});

function ctrl($log, $scope, PostService) {
    var edit = this;

    // Sample post id
    edit.editingId = 99999;

    // "Copy" (apparrently more "bind") the blog post data to edit.data
    edit.data = PostService.getData(edit.editingId);

}

This is used for a markdown editor. I wanted to load the data from the service into the controller, then edit it, and give the service the new version on pressing a "Save" button. If the aforementioned behaviour is correct in the sense of Angular's databinding, what is a better solution to achieve what I want?

Update

Based on PSL 's comment and Thibaud Sowa's answer I changed the getData() function to return a copy using angular.copy() . However, it seems not to be possible to copy one object out of an array (like angular.copy(arr[0]) ), as it will still return the whole array. See the updated JSFiddle .

Update 2

Well, I was dumb. I corrected it in the fiddle . Thank you for your answers.

This is because you are returning an object. In javascript when you do that it's like if you are passing a pointer.

You should use angular.copy to copy the object field by field, like this:

        return angular.copy(data);

See the doc here https://docs.angularjs.org/api/ng/function/angular.copy

Response to your update

Well, I edited your fiddle, to show you that you can copy an item of an array. Actually it's seems that every thing works like you want... (Or I didn't understand your need!)

The updated fiddle:

https://jsfiddle.net/thibaudsowa/aybLwa2L/3/

There is a very simple solution to your problem:

If you dont want to change the data you get from the service make a copy

There are plenty of threads on SO discussing the fastes or most elegant way to deep copy a Javascript object. A simple and rather fast solution is using json parse and stringify like this:

var copyOfA = JSON.parse(JSON.stringify(a));

Apply this to the data you get from your service and you are good to go :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM