JohnDizzle
JohnDizzle

Reputation: 1338

Controller change data of another controller on click

I want to pass some data from one controller to a second one via an onClick-Event. I tried to use a service between the two controllers but it seems that the controller who receives the data from the service doesn't recognize the onClick-Event of the first controller which leads to static/non changing data.


OnClick function (Controller 1)

$scope.select = function(index){            
    vm.currentActive = index;
    sessionService.setState(index);         
};

Exchange service

app.service('sessionService', function() {


    var state = null;

    var setState = function(changestate){
        state = changestate;
    };

    var getState = function(){
        return state;
    };

    return {

        setState: function(changestate){
            setState(changestate);
        },
        getState: function(){
            return state;
        }
    };
});

Receiving Controller (Controller 2)

app.controller('ContentController', function ($scope, sessionService)
{       
    var vm = this;
    vm.currentActive = sessionService.getState();
});

In the end I want that the state of Controller 2 changes whenever the OnClick-Event is triggered in controller 1. Is this way with the service the best or what do recommend to change the data in controller 2 after a click ?

Upvotes: 0

Views: 114

Answers (3)

sfletche
sfletche

Reputation: 49714

The reason your Receiving Controller is not getting the updated value is because the state property is copied into vm.state at the point of the directive definition object's initialization.

vm.currentActive = sessionService.getState();

Here, getState is only called once, so it won't matter if that state value is later updated...

One Solution

One option would be to call getState from the controller's view (which will get re-called (i.e. the value will be updated) with every digest cycle)...note this strategy has performance implications...

Another Solution

Another option is to leverage the trickle down effect of referenced objects (or as Miško explains in this Angular Best Practices video, "...if you don't have a dot, you're doing it wrong..."

You could utilize this strategy by using an object to store the state in your Exchange Service...

app.service('sessionService', function() {

  var data = {};

  var setState = function(changestate){
    data.state = changestate;
  };

  var getState = function(){
    return data.state;
  };

  return {
    setState: setState,
    data: data
  };
});

Receiving Controller

app.controller('ContentController', function ($scope, sessionService) {       
  var vm = this;
  vm.data = sessionService.data;
});

Then whenever data.state is updated in sessionService, vm.data.state will (by virtue of referenced data) contain the updated data as well.

In other words, vm.data.state will always contain the most up to date value of sessionService.data.state because they both refer to the same object.

Upvotes: 0

kicken
kicken

Reputation: 2167

One option for watching the state of a service is to use $scope.$watch with a function that returns the value to be watched for changes.

$scope.$watch(function(){ return sessionService.getState(); }, function(newValue, oldValue){
    //Do something
});

If the value in the service is changed, the watch will pick up the change on the next digest cycle. With this method there's no need to have your service or other controller try and signal that the value has changed.

If your service's getter method does not depend on this, you can simplify the watcher by just passing the getter method as the watch function rather than using a wrapper function.

$scope.$watch(sessionService.getState, function(newValue, oldValue){
    //Do something
});

Upvotes: 1

jcubic
jcubic

Reputation: 66490

You can add onChange event to service:

app.service('sessionService', function() {

    var state = null;
    var callbacks = [];

    var setState = function(changestate) {
        callbacks.forEach(function(callback) {
            callback(state, changestate);
        });
        state = changestate;
    };

    var getState = function() {
        return state;
    };

    return {
        setState: function(changestate) {
            setState(changestate);
        },
        getState: function() {
            return state;
        },
        onChange: function(fn) {
            if (typeof fn == 'function') {
                callbacks.push(fn);
            }
        }
    };
});

Upvotes: 0

Related Questions