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;
}
ajaykumar
  • 646
  • 7
  • 17

2 Answers2

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>
sielakos
  • 2,406
  • 11
  • 13
  • 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 – ajaykumar May 27 '16 at 10:27
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

Angelin
  • 648
  • 2
  • 7
  • 19
  • Great Thanks! I could understand now that scope is handled inside the template for custom directives. +1 – ajaykumar May 27 '16 at 10:27