Maslow
Maslow

Reputation: 1104

AngularJS: What is the best way to bind a directive value to a service value changed via a controller?

I want to create a "Header" service to handle the title, buttons, and color of it.
The main idea is to be able to customize this header with a single line in my controllers like this:

function HomeCtrl($scope, Header) {
    Header.config('Header title', 'red', {'left': 'backBtn', 'right': 'menuBtn'});
}

So I created a service (for now I'm only focussing on the title):

app.service('Header', function() {
    this.config = function(title, color, buttons) {
        this.title = title;
    }
});

...And a directive:

app.directive('header', ['Header', function(Header) {
    return {
        restrict: 'E',
        replace: true,
        template: '<div class="header">{{title}}</div>',
        controller: function($scope, $element, $attrs) {
            $scope.$watch(function() { return Header.title }, function() {
                $scope.title = Header.title;
            });
        }
    };
}]);

So, this actually works but I'm wondering if there are no better way to do it. Especially the $watch on the Header.title property. Doesn't seem really clean to me.

Any idea on how to optimize this ?

Edit: My header is not in my view. So I can't directly change the $scope value from my controller.

Edit2: Here is some of my markup

<div class="app-container">
    <header></header>

    <div class="content" ng-view></div>

    <footer></footer>
</div>

(Not sure this piece of html will help but I don't know which part would actually...)

Thanks.

Upvotes: 2

Views: 368

Answers (2)

koolunix
koolunix

Reputation: 1995

If you are using title in your view, why use scope to hold the object, rather than the service? This way you would not need a directive to update scope.header, as the binding would update it if this object changes

   function HomeCtrl($scope, Header) {
     $scope.header = Header.config('Header title', 'red', {'left': 'backBtn', 'right': 'menuBtn'});
    }

and refer to title as

<h1>{{header.title}}</h1>

Update

Put this in a controller that encapsulates the tags to bind to the header:

$scope.$on("$routeChangeSuccess", function($currentRoute, $previousRoute) {
    //assume you can set this based on your $routeParams
    $scope.header = Header.config($routeParams);
});

Upvotes: 1

mccainz
mccainz

Reputation: 3497

Simple solution may be to just add to rootScope. I always do this with a few truly global variables that every controller will need, mainly user login data etc.

app.run(function($rootScope){
    $rootScope.appData={
            "header" :  {"title" : "foo"}, 
            "user" :{}
    };
});

.. then inject $rootScope into your controllers as warranted.

Upvotes: 0

Related Questions