0

I am creating a tabs directive which allows the user to add a tab.
Everything is working fine but the tab-entry directive is not reading the scope selected value in the node element which is used to set the active class.

Even if I change the scope selected to true in the tabs directive link > > > function, it does not reflect the change and active class is not set.

Directives

 _app_dashboard.directive('tabs' , function(){
            return {    
                    restrict  : 'EA',

                    controller : function($scope){

                        $scope.tabEntries = this.tabEntries  = [];

                        $scope.select = function($event , item){

                                    //unselect All                                          
                                    this.tabEntries.forEach(function(tabentry , index){
                                    tabentry.selected = false;
                                    if(tabentry.heading == item){
                                        tabentry.selected = true;
                                    }
                                })                              
                            }
                    },

                    template : '<div class = "tab-container"><ul><li ng-repeat = "tabentry in tabEntries"><a href=""  ng-click="select($event , tabentry.heading)">{{tabentry.heading}}</a></li></ul><div ng-transclude></div></div>',  

                    transclude : true,
                    replace : false 
                }
        });
        _app_dashboard.directive('tabEntry' , function(){
            return {    
                        restrict : "EA",
                        require : "^tabs",
                        scope : {
                            heading : "@",
                        },

                        template : '<div ng-transclude></div>',
                        transclude : true,

                        link : function(scope , ele , attr , ctrl , transcludeFn){
                            scope.tabCtrlScope = ctrl;
                            scope.selected = true;

                            scope.tabCtrlScope.tabEntries.push(scope);


                        }
                }
        });

HTML

<tabs >
    <tab-entry  heading = 'Tab1'  ng-class = "{'active' : selected}">
        <div>The is the content of tab 1</div>
    </tab-entry>
    <tab-entry  heading = 'Tab2'  ng-class = "{'active' : selected}">
        <div>This is the content of tab 2</div>
    </tab-entry>

</tabs>

CSS

tab-entry {
    display : none;
}
tab-entry.active {
    display : block;
}

2 Answers 2

1

You need to set property selected: '=' on scope declaration in your directive declaration to achieve two-way binding.

var _app_dashboard = angular.module('app', []);

_app_dashboard.directive('tabs' , function(){
            return {    
                    restrict  : 'EA',

                    controller : function($scope){

                        $scope.tabEntries = this.tabEntries  = [];

                        $scope.select = function($event , item){

                                    //unselect All                                          
                                    this.tabEntries.forEach(function(tabentry , index){
                                    tabentry.selected = false;
                                    if(tabentry.heading == item){
                                        tabentry.selected = true;
                                    }
                                })                              
                            }
                    },

                    template : '<div class = "tab-container"><ul><li ng-repeat = "tabentry in tabEntries"><a href=""  ng-click="select($event , tabentry.heading)">{{tabentry.heading}}</a></li></ul><div ng-transclude></div></div>',  

                    transclude : true,
                    replace : false 
                }
        });
        _app_dashboard.directive('tabEntry' , function(){
            return {    
                        restrict : "EA",
                        require : "^tabs",
                        scope : {
                            heading : "@",
                            selected: '='
                        },

                        template : '<div ng-transclude></div>',
                        transclude : true,

                        link : function(scope , ele , attr , ctrl , transcludeFn){
                            scope.tabCtrlScope = ctrl;
                            scope.selected = true;

                            scope.tabCtrlScope.tabEntries.push(scope);


                        }
                }
        });
tab-entry {
    display : none;
}
tab-entry.active {
    display : block;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<tabs >
    <tab-entry  heading = 'Tab1' selected="selected1"  ng-class = "{'active' : selected1}">
        <div>The is the content of tab 1</div>
    </tab-entry>
    <tab-entry  heading = 'Tab2' selected="selected2"   ng-class = "{'active' : selected2}">
        <div>This is the content of tab 2</div>
    </tab-entry>

</tabs>
</div>

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

1 Comment

Thanks. This is another way round solving this. I can conclude that in custom directives we can fetch an attribute with a two way binding and use the same variable in other attributes in the same custom directive rather than simply putting the new scope object created in link function. +1
1

You can set the selected property internally so you don't have to expose it in the main template:

_app_dashboard.directive('tabEntry' , function(){
  return {    
    restrict : "EA",
    require : "^tabs",
    scope : {
      heading : "@"
    },
    template : '<div ng-class="{ active: selected }" ng-transclude></div>',
    transclude : true,
    link : function(scope , ele , attr , ctrl , transcludeFn){
      scope.tabCtrlScope = ctrl;
      scope.selected = true;
      scope.tabCtrlScope.tabEntries.push(scope);
    }
  }
});

CSS:

tab-entry > div {
  display : none;
}
tab-entry > .active {
  display : block;
}

Check out this working plunker

1 Comment

Great Thanks! I could understand now that scope is handled inside the template for custom directives. +1

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.