Summer Developer
Summer Developer

Reputation: 2086

Angular Directive Template Doesn't Bind To Angular Controller Variable

I have a curious case that I can't figure out...

I have a directive on my app like so:

app.directive('cartTotal', function() {
  return {
    template: "<i ui-sref='cart' class='fa fa-shopping-basket'></i><span class='items'>@{{cartQTotal.total}}</span>"
  };
});

When I load the page, this function fires:

if(localStorage.getItem("cart") != null)
    {
        console.log("makeacart");
        var cart = JSON.parse(localStorage.getItem("cart"));
        $scope.cartQTotal.total = 0;
        for(i=0;i<cart.length;i++)
        {
            $scope.cartQTotal.total += cart[i].cartQ;
        }
        $('.fixed-cart').animateCss('bounce');
    }

This works.

But if I modify $scope.cartQTotal outside of this, such as in a function (still in the parent controller but derived from an ng-click()) for example:

$scope.add2Cart = function(name){
var cart =  JSON.parse(localStorage.getItem("cart"));
        for(var zz = 0;zz<cart.length;zz++)
    {
        if(cart[zz].item == name)
        {
            console.log("already in cart");
            $('.fixed-cart').animateCss('bounce');
            return;
        }
    }
        cart.push({item:name,cartQ:1});
        localStorage.setItem("cart", JSON.stringify(cart));
        console.log("makeacartii");
        $scope.cartQTotal.total = 0;
        for(i=0;i<cart.length;i++)
        {
            $scope.cartQTotal.total += cart[i].cartQ;
        }
        console.log($scope.cartQTotal.total);//THE NUMBER I WANT
        $('.fixed-cart').animateCss('bounce');
}

On //The Number I Want line I get the proper number, as in the variable is correct but my directive template doesn't update. I don't understand why not.

Please assist.

Edit (from the docs):

Observing directives, such as double-curly expressions {{expression}}, register listeners using the $watch() method. This type of directive needs to be notified whenever the expression changes so that it can update the view.

So I guess the question is how do I notify the directive properly?

EDIT 2:

Looking at it using the nginspector extension, it appears I have two scopes with cartQTotal rather than one, this remains constant whether or not I have the directive.

I am very confused because I have my controller scope and then a duplicate scope with all the same variables but the cartQTotal changes in one scope and not the other. Why would I have a duplicate but unnamed controller scope?

Upvotes: 0

Views: 302

Answers (3)

Summer Developer
Summer Developer

Reputation: 2086

It was a problem as elucidated here: How do I share $scope data between states in angularjs ui-router?

Basically I didn't realize that my ui-router configuration was creating a seperate instance of my controller. Changing my code as specified in that answer allowed it to work properly, even though I wasn't changing states it still affected the directive's ability to communicate with the proper controller instance.

Upvotes: 1

Saurabh Agrawal
Saurabh Agrawal

Reputation: 7739

This is because your directive and $scope and the controller where data is updating both are different..

So you need to pass your controller data to your directive so that it will get modified. For this purpose you can use $broadcast (but make sure you know about it because in large application its not good practice to use it).

So Try this Controller

 cart.push({item:name,cartQ:1});
        localStorage.setItem("cart", JSON.stringify(cart));
        console.log("makeacartii");
        $scope.cartQTotal.total = 0;
        for(i=0;i<cart.length;i++)
        {
            $scope.cartQTotal.total += cart[i].cartQ;
        }
        console.log($scope.cartQTotal.total);//THE NUMBER I WANT
        $('.fixed-cart').animateCss('bounce');

       $rootScope.$broadcast("cartUpdated",$scope.cartQTotal);

directive

$scope.$on('eventEmitedName', function(event, data) {
    $scope.cartQTotal = data;
  });

Upvotes: 1

Sam Bartlett
Sam Bartlett

Reputation: 78

Data you wish to use within your directive that is manipulated outside of the directive should be passed in using bindings. There's a great short read here that shows you how. Personally, I use method 6 the most.

The gist is - you add to your directive's returned object:

    scope: {
        yourVariable: '=', //use =? for optional variables
    }

And then use it in your directive as such:

<span>{{your-variable}}</span>

And bind to it as such:

<my-directive your-variable="myControllerVariable"></my-directive>

Upvotes: 0

Related Questions