AngularJS : Directive not able to access isolate scope objects

15,879

Solution 1

The problem is: at that time angular does not update its bindings yet.

You should not access your variables like this, try to use angular js binding mechanism to bind it to view (by using $watch for example). Binding to parent scope variables means you're passive, just listen for changes and update other variables or your view. That's how we should work with angular.

If you still need to access it. You could try a workaround using $timeout

$scope.setDefaults = function() {
    $timeout(function () {
        alert(JSON.stringify($scope.appSubs)); //Coming as undefined  
    },0);          
};

DEMO

It's better to use $watch

 angular.module('ctrl', []).controller('TempCtrl', function ($scope, $location, $rootScope) {
         $scope.appSubscriptions = "Subscriptions";
         $scope.appObj = "Objs";
         $scope.showAppEditWindow = function () {
             //Binding the directive isolate scope objects with parent scope objects
             $scope.asAppObj = $scope.appObj;
             $scope.asAppSubs = $scope.appSubscriptions;

         };
     });

     angular.module('ctrl').directive('tempDirective', function () {
         return {
             restrict: 'E',
             replace: true,
             scope: {
                 appObj: '=asAppObj',
                 appSubs: '=asAppSubs'
             },
             link: function (scope, element, attrs) {

             },
             controller: function ($scope, $timeout) {
                 $scope.$watch("appSubs",function(newValue,OldValue,scope){
                     if (newValue){ 
                         alert(JSON.stringify(newValue)); 
                     }
                 });
             },
             template: "<div>{{appSubs}}</div>"
         };
     });

DEMO

By using $watch, you don't need to broadcast your event in this case.

Solution 2

Most likely the isolated scope variable is not available when the directive's controller first instantiates but probably its available when you need it for a following event such as: within a function bound to an ng-click

its just a race condition and the object doesn't arrive exactly when directive's controller loads

Share:
15,879
Akhilesh Aggarwal
Author by

Akhilesh Aggarwal

Updated on June 14, 2022

Comments

  • Akhilesh Aggarwal
    Akhilesh Aggarwal almost 2 years

    I am trying to put some default values in my directive with Isolate scope. Basically, I need to do some DOM manipulations using the scope object when my directive is bound. Below is my code:

    Controller:

    angular.module('ctrl').controller('TempCtrl', function($scope, $location, $window, $timeout, RestService, CommonSerivce) {
    
    $scope.showAppEditWindow = function() {
        //Binding the directive isolate scope objects with parent scope objects
        $scope.asAppObj = $scope.appObj;
        $scope.asAppSubs = $scope.appSubscriptions;
    
        //Making Initial Settings
        CommonSerivce.broadcastFunction('doDirectiveBroadcast', "");
    };
    

    Service:

    angular.module('Services').factory('CommonSerivce', function ($rootScope) {
    return {       
        broadcastFunction: function(listener, args) {
            $rootScope.$broadcast(listener, args);
        }
    };
    

    Directive:

    angular.module('directives').directive('tempDirective', function() {
    return {
        restrict : 'E',
        scope:{
            appObj:'=asAppObj',
            appSubs: '=asAppSubs'
        },
        link : function(scope, element, attrs) {},
        controller : function ($scope,Services,CommonSerivce) {         
            //Broadcast Listener 
            $scope.$on('doDirectiveBroadcast', function (event, args) {
                $scope.setDefaults();
            });
    
            $scope.setDefaults = function() {
                //Setting Default Value
                alert(JSON.stringify($scope.appSubs)); //Coming as undefined            
            };
        },
        templateUrl:"../template.html"
        };
    });
    

    Custom Directive element:

    <temp-directive as-app-obj="asAppObj" as-app-subs="asAppSubs" />
    

    Now, the issue is that while trying to access the isolate scope in the default method inside directive, I aam getting an undefined value whereas the data is coming and is getting bound to the DOM. How can I access the isolate scope in the broadcast listener and modify the directive template HTML? Is there another wasy for handling this?

  • Khanh TO
    Khanh TO over 10 years
    @Akhilesh Aggarwal: You should use $watch for this. Check out a similar problem at stackoverflow.com/questions/19142409/…
  • Akhilesh Aggarwal
    Akhilesh Aggarwal over 10 years
    @Khank To: This is even better :). Any particular reason why the 'watch' definition should be added inside 'link'. I tested and it works under 'controller' also.
  • Khanh TO
    Khanh TO over 10 years
    @Akhilesh Aggarwal: In your case, I think you should use $watch inside controller. As controller should contain your logic and link function should only care about making a dynamic connection between model and view
  • Seth Flowers
    Seth Flowers almost 10 years
    @KhanhTO: According to the angular docs for directives: "Best Practice: use controller when you want to expose an API to other directives. Otherwise use link."