Roee Gavirel
Roee Gavirel

Reputation: 19445

Angular render view after parameter changed in service

High level
I header view and a main view in my angular application. I want the header to have a "back" button that is show/hidden based on the page I'm on.

What I did
app.js (snippet)

app.factory('globalServices', function() {
    return {
        showBack : false,
        back: function() {
            window.history.back();
        }
    };
});

header.html (snippet)

<a class="button-prev" ng-click="back()" ng-show="showBackButton">
    Back
</a>

headerCtrl.js (snippet)

$scope.showBackButton = globalServices.showBack;
$scope.back = function() {
    globalServices.back();
};

subPageCtrl.js (snippet)

globalServices.showBack = true;

Problem
The button viability isn't refreshed after the value is changed. I only see the value changed after I move one more page.

Is there a way to fix it?

I'm also open for a different approach.

Edit
Trying to call $scope.$apply(); also failed with error $digest already in progress because I'm changing this value as part of the constructor of subPageCtrl.

Upvotes: 0

Views: 232

Answers (2)

Wayne Ellery
Wayne Ellery

Reputation: 7958

This is because when booleans are passed, they are assigned by value (they are a by value type) so when you are doing $scope.showBackButton = globalServices.showBack; it is assigning the value of $scope.showBackButton to the value of globalServices.showBack so if you change the value of globalServices.showBack it won't change the value of $scope.showBackButton.

To fix this you should used an object which is assigned by reference:

app.factory('globalServices', function() {
    return {
        showButtonDetails: {
            showBack : false
        },
        back: function() {
            window.history.back();
        }
    };
});

<a class="button-prev" ng-click="back()" ng-show="showButtonDetails.showBack">
    Back
</a>

$scope.showButtonDetails = globalServices.showButtonDetails;
$scope.back = function() {
    globalServices.back();
};

globalServices.showButtonDetails.showBack = true;

Upvotes: 1

Joe Enzminger
Joe Enzminger

Reputation: 11190

$scope.showBackButton = globalServices.showBack;

only set's showBackButton to globalServices.showBack once (during controller initialization). Future changes to globalServices.showBack aren't propagated to the $scope.showBackButton, which is the value that your UI is bound to.

You have two options:

1)

$scope.$watch('globalServices.showBack', function(){
    $scope.showBackButton = globalServices.showBack;
}

This option will watch globalServices.showBack for changes, and then set $scope.showBackButton to match on any change.

or

2)

$scope.globalServices = globalServices;

<a class="button-prev" ng-click="globalServices.back()" ng-show="globalServices.showBackButton">
    Back
</a>

This option exposes globalServices directly to your UI. This is how I would do it.

Upvotes: 1

Related Questions