stallingOne
stallingOne

Reputation: 4006

Update a service value from a parent controller

I've been searching for hours how to update a service value from a nested controller.
My child controller needs to update a value in a service. And that value needs to be shown in the parent controller.

I've made a jsfiddle to make it more clear and easy to help http://jsfiddle.net/jtsmduxw/3/

<body ng-app="MyApp">
    <div ng-controller="parentCtrl">
        <p>{{username}}</p>
        <div ng-controller="childCtrl">
            <p>{{username}}</p>
        </div>
    </div>
</body>

-

var app = angular.module("MyApp", []);

app.service('authenticationSrv', function () {
    var user = 'anonymous';
    return {
        getUser: function () {
            return user;
        },
        setUser: function (value) {
            user = value;
        }
    };
});

app.controller("parentCtrl", function ($scope, authenticationSrv) {
    $scope.username = authenticationSrv.getUser();
});

app.controller("childCtrl", function ($scope, authenticationSrv) {
    authenticationSrv.setUser('my name'); // I need this function to also update the scope of the parent
    $scope.username = authenticationSrv.getUser();
});

(I've read and tried Update parent scope variable, but I could not make it work with the service.)

Thanks!

Upvotes: 4

Views: 84

Answers (4)

rtribaldos
rtribaldos

Reputation: 1277

Make user in the Service an object instead of a primitive (string). Then use {{user.name}} in your view.

Notice that I did some minor changes to authenticationSrv.setUser() and renamed it to authenticationSrv.setUserName().

See my working fiddle: https://jsfiddle.net/rbwk3rqb/

var app = angular.module("MyApp", []);

angular.module("MyApp")
.service('authenticationSrv', function () {
    var user = {name: 'anonymous'};
    return {
        getUser: function () {
            return user;
        },
        setUserName: function (value) {
            user.name = value;
        }
    };
});

angular.module("MyApp")
.controller("parentCtrl", function ($scope, authenticationSrv) {
    $scope.user = authenticationSrv.getUser();
});

angular.module("MyApp")
.controller("childCtrl", function ($scope, authenticationSrv) {
    authenticationSrv.setUserName('my name');
    $scope.user = authenticationSrv.getUser();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="MyApp">
    <div ng-controller="parentCtrl">
        <p>{{user.name}}</p>
        <div ng-controller="childCtrl">
            <p>{{user.name}}</p>
        </div>
    </div>
</body>

Upvotes: 1

Dayan
Dayan

Reputation: 8031

Make use of an object literal instead of the variable username.

Parent

app.controller("parentCtrl", function ($scope, authenticationSrv) {
    $scope.parentObject = {};
    $scope.parentObject.username = authenticationSrv.getUser();
});

Child

app.controller("childCtrl", function ($scope, authenticationSrv) {
    authenticationSrv.setUser('my name'); 
    $scope.parentObject.username = authenticationSrv.getUser();
});

Working Example

var app = angular.module("MyApp", []);


app.service('authenticationSrv', function () {
    var user = 'anonymous';
    return {
        getUser: function () {
            return user;
        },
        setUser: function (value) {
            user = value;
        }
    };
});

app.controller("parentCtrl", function ($scope, authenticationSrv) {
    $scope.parentObject = {};
    $scope.parentObject.username = authenticationSrv.getUser();
});

app.controller("childCtrl", function ($scope, authenticationSrv) {
    authenticationSrv.setUser('my name'); 
    $scope.parentObject.username = authenticationSrv.getUser();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="MyApp">
    <div ng-controller="parentCtrl">
        <p>{{parentObject.username}}</p>
        <div ng-controller="childCtrl">
            <p>{{parentObject.username}}</p>
        </div>
    </div>
</body>

Upvotes: 2

Tj Gienger
Tj Gienger

Reputation: 1405

The idea is to create and object to update and not just a primitive:

$scope.user = {};
$scope.user.name = authenticateSrv.getUser();

and in the child scope you just set it:

$scope.user.name = authenticateSrv.setUser('my name');

here is a Fiddle

Upvotes: 1

doldt
doldt

Reputation: 4506

As user is a primitive value in the service, when you put the value from the service to your controller's scope with this line:

$scope.username = authenticationSrv.getUser();

the value of user is copied into $scope.username. So just because later on you overwrite the value of user in the service, nothing is changing in your "parent" $scope.

There are several ways to get around this, the easiest is probably to create a user object in your service - if you store the reference to this object in your scopes, it will reflect the changes made to it from other controllers. (Objects in javascript are passed by reference value, so all controllers will be affecting the same object, not copies of the values.) For the actual implementation, I'd guide you back to the same link you posted - when you tried implementing that, what was the problem with it? Show us the code you tried.

Alternatively, you can also implement the observer pattern using this service (this is considerably more work), or use events on the scope hierarchy to notify the controllers of the change of user (this is a questionable practice).

Upvotes: 1

Related Questions