Bruno Casarotti
Bruno Casarotti

Reputation: 643

two-way binding in angular factories

I wrote an Angular factory to store an object that I need to pass to diferent controllers. The factory looks like this:

app.factory('SearchEngineConfigs', function () {
    var configs = {
        isInternational: false,
        TripType: 1,
        journeys: []
    }
    var _setInternational = function(val) {
        configs.isInternational = val;
    }
    var _setTripType = function(val) {
        configs.TripType = val;
    }
    var _setJourneys = function(journeys) {
        configs.journeys = journeys;
    }

    var _getConfigs = function() {
        return configs;
    }
    return {
        setInternatioanl: _setInternational,
        setTripType: _setTripType,
        setJourneys: _setJourneys,
        getConfigs: _getConfigs
    }
});

So I have this factory injected in my controllers. In one of the controllers I'm setting the values of configs' factory like this:

SearchEngineConfigs.setInternatioanl($scope.searchEngine.isInternational);
SearchEngineConfigs.setTripType($scope.searchEngine.TripType);               
SearchEngineConfigs.setJourneys($scope.journeys.slice());

So far so good. What is happening now is that everytime I change let's say the $scope.searchEngine.isInternational without calling the factory method SearchEngineConfigs.setInternatioanl this change still being reflected into the factory and thus, updating this property in another controller that is using that factory at the same time of the first controller. How can I avoid this to happen? I only want to change the value of the object inside the factory when I explicity make a call to the correponding factory method.

Upvotes: 1

Views: 168

Answers (2)

Buh Buh
Buh Buh

Reputation: 7546

You could use angular.copy to avoid allowing any references to your internal state objects for existing outside your factory.
Note that you could have to do this on both the input and output, as either could create a leak.
One way of ensuring this was consistant would be to use a decorator function:

function decorate(func) {
    return function() {
        const argumentsCopy = _.map(arguments, a => angular.copy(a));
        const result = func.apply(factory, argumentsCopy);
        return angular.copy(result);
    };
}

...which in turn is used like this:

var factory = {
    setInternatioanl: decorate(_setInternational),
    setTripType: decorate(_setTripType),
    setJourneys: decorate(_setJourneys),
    getConfigs: decorate(_getConfigs)
}
return factory

Upvotes: 1

tanmay
tanmay

Reputation: 7911

You can either use the new keyword to have different instances of the service.

Something like, var searchEngineConfigs = new SearchEngineConfigs(); and then use it to invoke factory methods.

Or, you can use the angular.copy() while setting the variables in your service to remove the reference which is causing the update in service.

Something like,

var _setInternational = function(val) {
    configs.isInternational = angular.copy(val);
}

Upvotes: 0

Related Questions