AngularJS : directives and scope

I have a simple question that I think has a pretty simple solution, but somehow I am missing it.

I'm setting up a simple directive for my app. I'm leaving the scope property set to the default, "false", because I want it to share the scope of my controller.

The problem is, I can't seem to access that scope.

In my linking function, I can do:

console.dir(scope)

and I can see the property that I am after ('pages') in the scope object.

If I try to do:

console.dir(scope.pages) 

however, it comes back as undefined.

What am I missing?

Thanks in advance.

MyDirectives.directive("mdPagination", function(){
    return {
        templateURL: "/templates/pagination.html",
        replace: true,
        restrict: 'A',
        scope: false, //default
        link: function(scope, element, attrs){ 
            console.log('in linking function');
            console.dir(scope);
            console.dir(element);
            console.dir(attrs);
            console.dir(scope.pages);
        }
    }
});

The template:

<nav class="pagination" md-Pagination></nav>

The controller:

App.controller('MachinesListCtrl', function ($scope, $routeParams, $location, MachineServices, CustomerServices) {

    var page = ($routeParams.page ? $routeParams.page : 1);

    //if we are getting all machines based on their customer id.
    if($routeParams.customerID){
        MachineServices.getByCustomerId($routeParams.customerID).then(function (data) {
            _.each(data.results, function (machine, index, list) {
                CustomerServices.get(machine.customer_id).then(function(data){
                    machine.CustomerData = data.results;
                });
            });

            $scope.Machines = data.results;
            $scope.pages = data.pages;
        });
    }
    //otherwise we just want the regular list of machines.
    else{
        MachineServices.query(page).then(function (data) {
            _.each(data.results, function (machine, index, list) {
                CustomerServices.get(machine.customer_id).then(function(data){
                    machine.CustomerData = data.results;
                });
            });

            $scope.Machines = data.results;
            $scope.pages = data.pages;
        });
    }
});

Answers:

Answer

The problem in your code is: MachineServices.getByCustomerId and MachineServices.query are asynchronous. When you call these functions, data from the server does not arrive yet and these lines

  $scope.Machines = data.results;
  $scope.pages = data.pages;

are not called yet.

Scope in your link function is bound to the parent's scope. But when the link function is called, the parent's scope.pages is still undefined (due to asyn)

When we work with angular data-binding, we should be passive, just listen for changes and react accordingly(use $watch, for example), because our code does not know and should not know when the bound property has value or has its value updated. Let angular notify us the changes

Answer

It looks like you are using angular $resource for your MachineServices, right? That creates an empty object or array for your results that you can bind to immediately that it later fills with results when the call completes asynchronously. When link is called by angular it will not be populated with data yet.

First add logging to your query and getByCustomerId calls to make sure they are getting the values and setting the properties on the scope correctly. Add {{pages|json}} somewhere in your template to see the JSON of pages as it is changed. If you see that then you can watch that property in your directive if you need to do something special when it changes:

MyDirectives.directive("mdPagination", function(){
    return {
        templateURL: "/templates/pagination.html",
        replace: true,
        restrict: 'A',
        scope: false, //default
        link: function(scope, element, attrs){ 
            console.log('in linking function');
            console.dir(scope);
            console.dir(element);
            console.dir(attrs);
            console.dir(scope.pages);

            // watch pages for changes
            scope.$watch('pages', function(value) {
                console.log("pages now has this value:");
                console.dir(scope.pages);
            });
        }
    }
});
Answer

Try Injecting scope into your directive.

MyDirectives.directive("mdPagination", function($scope){...
Answer

Here is the code working with Ng 1.2:

http://jsfiddle.net/roadprophet/PfEaz/

MyDirectives.directive("mdPagination", function(){
    console.log('BLAH');
    return {
        template: "<h1>BLAH!</h1>",
        replace: true,
        restrict: 'A',
        scope: false, //default
        link: function(scope, element, attrs){ 
            console.log('in linking function');
            console.dir(scope);
            console.dir(element);
            console.dir(attrs);
            console.dir(scope['pages']);
        }
    }
});

Notice I am injecting $scope into the controller.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.