1

I'm trying to create a service to store the state of whether a tutorial is active or not, so that I can share that information amongst different controllers. I'm also creating a scope for the service, so that I can watch when the value changes. Is there a way to expose the scope created in the service to the controller?

I've tried it with 1) exposing the scope variable and 2) using a function, but it seems like there would be another way. Is there?

HTML

<div ng-app="App">
    <h2>As variable</h2>
    <div ng-controller="tutorialController">
        <button ng-click="toggleActive()">Toggle</button>
        <div ng-show="tutorial.scope.isActive">Tutorial</div>
        <div ng-bind="tutIsActive"></div>
    </div>

    <hr/>

    <div ng-controller="tutorialController2">
        <h2>As function</h2>
        <button ng-click="toggleActive()">Toggle</button>
        <div ng-show="tutorial.isActive()">Tutorial</div>
        <div ng-bind="tutIsActive"></div>
    </div>
</div>

JS

var App = angular.module('App', [])

// 1: As variable

    .factory("Tutorial", ["$rootScope", function($rootScope) {
        var scope = $rootScope.$new();
        scope.isActive = true;

        scope.$watch('isActive', function() {
            console.log("1: isActive changed: " + scope.isActive);
        });

        return {
            scope: scope  
        };
    }])
    .controller('tutorialController', ["$scope", "Tutorial", function($scope, Tutorial) {
        $scope.tutorial = Tutorial;
        $scope.tutIsActive = $scope.tutorial.scope.isActive;

        $scope.toggleActive = function() {
            console.log("1: toggleActive");
            $scope.tutorial.scope.isActive = !$scope.tutorial.scope.isActive;
            $scope.tutIsActive = $scope.tutorial.scope.isActive;
        };
    }])

// 2: As function

    .factory("Tutorial2", ["$rootScope", function($rootScope) {
        var scope = $rootScope.$new();
        scope.isActive = true;

        scope.$watch('isActive', function() {
            console.log("2: isActive changed: " + scope.isActive);
        });

        return {
            isActive: function() {
                return scope.isActive;
            },
            toggle: function() {
                scope.isActive = !scope.isActive;   
            }
        };
    }])
    .controller('tutorialController2', ["$scope", "Tutorial2", function($scope, Tutorial) {
        $scope.tutorial = Tutorial;
        $scope.tutIsActive = $scope.tutorial.isActive();

        $scope.toggleActive = function() {
            console.log("2: toggleActive");
            $scope.tutorial.toggle();
            $scope.tutIsActive = $scope.tutorial.isActive();
        };
    }]);

JS fiddle

It seems 2 is not best practice, as it is using a function within an expression, but 1 seems like it's exposing too much? Or maybe I should be using a controller instead?

1 Answer 1

2

You don't need to expose a scope. Just attach the injected tutorial to your controller scope where you need it:

var App = angular.module('App', [])

App.factory("Tutorial", function() {
    return {
        isActive: true,
        toggleActive: function() {
            this.isActive = !this.isActive;
        }
    };
});

App.controller('tutorialController', function($scope, Tutorial) {
    $scope.tutorial = Tutorial;

    $scope.toggleActive = function() {
        $scope.tutorial.toggleActive();
    };
});

Fiddle

Sign up to request clarification or add additional context in comments.

7 Comments

Pretty much what satchmorun said. The only thing I would add is to perhaps not expose the state variable to the client and create a getter function instead.
The reason I had the scope was so I could use scope.$watch. Would I be able to still use that or something equivalent to check when it changes?
If you are controlling the state of 'isActive' via the exposed function 'toggleActive', then just put your watcher code there. If isActive is private then that's the only way it can get changed.
@BoxerBucks - so there's no way for any type of service to have scope exposed inside of it? None of these methods (fact, srvc & prvdr) can have scope inside, and than being used by these methods?
@neoswf You can inject $rootScope and use that, but unless you are implementing specific functionality (like broadcasting or .on from a service for some reason) I wouldn't do that.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.