Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Two complex problems with our tabs directive
Message
 
General information
Forum:
Javascript
Category:
Other
Miscellaneous
Thread ID:
01627325
Message ID:
01627355
Views:
83
So, I solved part of the problem (the invalid state (and showing invalid tab in red) as well as disabling the add button.

But I do not like the solution at all as I have to access parent's scope and know the details about form's implementation. Here is all my current code and I'd appreciate suggestions of improving it as it's really bad workaround right now.
(function () {

    'use strict';

    var app = angular.module('sysMgrApp')
    .directive('smNavTabs', ['$rootScope', '$location', '$state', '$stateParams', navTabViews])
    .directive('smNavTab', ['$rootScope', '$location', '$state', '$stateParams', navTabView]);

    function navTabViews($rootScope, $location, $state, $stateParams) {
        return {
            restrict: 'E',
            
            transclude: true, // means it has access to the outside scope
            replace: true,
            scope: {},
            
            controller: function ($scope) {
                $rootScope.$state = $state;
                $rootScope.$stateParams = $stateParams;               

                $rootScope.stateChangeAborted = false;

                var urlProtocolAndPath = $location.protocol() + '://' + $location.host() + ($location.port() != NaN ? ':' + $location.port() : '');

                var panes = $scope.panes = [];                

                $scope.lastSelected = 0;
                $scope.$parent.tabsInvalid = false;

                $scope.select = function (uiView) {                    
                 //   window.console && console.log('Selecting ' + uiView.name);
                    // call hook before changing state                                      
                    
                    panes[$scope.lastSelected].invalid = uiView.form.$invalid; // all tabs point to the same form
                                        
                    uiView.onActivating(uiView.name);
                   
                    // use $rootScope to make call to change the state
                    $rootScope.$state.go(uiView.name, uiView.viewSettings.params, uiView.viewSettings.options);                    

                    // set first call from 'addPane' function
                    // to default tab
                    if (panes.length === 0 && uiView.isVisible) {
                        uiView.isActive = true;
                    }                   

                };               

                // called from $stateNotFound, $stateChangeError, $stateChangeAborted
                // and $stateChangeSuccess event listeners
                $rootScope.setNavTabs = function (viewName) {
                    var i = 0;
                 //   window.console && console.log('setNavTabs method is called with viewName = ' + viewName);
                    $scope.$parent.tabsInvalid = false;

                    for (i = 0; i < panes.length; i++) {
                        var pane = panes[i];

                        // set to 'false' all but matching name
                        if (pane.isActive) {
                            $scope.lastSelected = i;                                                        
                        }
                        pane.isActive = false;

                        if ((pane.name == viewName)) {

                            // recall hook if stateChangeAborted = true
                            if ($rootScope.stateChangeAborted == true)
                                pane.onActivating(viewName);

                            pane.isActive = true;
                        }

                        if (pane.invalid)
                        {
                            $scope.$parent.tabsInvalid = true;
                        }
                    }
                }

                //onStateChangeStart
                $rootScope.$on('$stateChangeStart',
                function (event, toState, toParams, fromState, fromParams) {
                    // reset stateChangeAborted flag
                    $rootScope.stateChangeAborted = false;
                })

                //onStateNotFound
                $rootScope.$on('$stateNotFound',
                function (event, unfoundState, fromState, fromParams) {
                    $rootScope.stateChangeAborted = true;
                    $rootScope.setNavTabs(fromState.name);
                })

                //onStateChangeError'
                $rootScope.$on('$stateChangeError',
                function (event, toState, toParams, fromState, fromParams) {
                    $rootScope.stateChangeAborted = true;
                    $rootScope.setNavTabs(fromState.name);
                })

                //onStateChangeAborted
                $rootScope.$on('$stateChangeAborted',
                function (event, toState, toParams, fromState, fromParams) {
                    $rootScope.stateChangeAborted = true;
                    $rootScope.setNavTabs(fromState.name);
                })

                //onStateChangeSuccess
                $rootScope.$on('$stateChangeSuccess',
                function (event, toState, toParams, fromState, fromParams) {
                    $rootScope.stateChangeAborted = false;
                    $rootScope.setNavTabs(toState.name);
                })

                this.addPane = function (pane) {
                   
                    if (panes.length === 0 && pane.isVisible) {
                        panes.push(pane);
                        $scope.lastSelected = 0;
                        $scope.select(pane);
                    }
                    else
                        panes.push(pane);
                };

                
            },
            templateUrl: 'app/templates/smNavTabs'
        };
    };

    function navTabView($rootScope, $state, $stateParams) {
        return {
           
            require: ['^form','^smNavTabs'],
            restrict: 'E',
            transclude: false,
            replace: true,
            scope: {
                name: '@',
                title: '@',
                
                viewSettings: '@?',
                onActivating: '&?',
                isVisible: '=?ngShow'
            },
            link: function (scope, element, attrs, tabsCtrl) {               

                //default settings and functions
                var defaultViewSettings = function () {
                    var params, options;
                    params = {};
                    options = {
                        location: true,
                        inherit: true,
                        relative: $state.$current,
                        notify: true,
                        reload: false
                    };

                    return {
                        params: params,
                        options: options
                    };
                };

                var defaultOnActivating = function () {

                };
                scope.isVisible = scope.isVisible || true;
                scope.viewSettings = scope.viewSettings || defaultViewSettings();
                scope.onActivating = scope.onActivating || defaultOnActivating();
                scope.form = tabsCtrl[0];
                scope.invalid = false;
                scope.isActive = false;
                tabsCtrl[1].addPane(scope);
            },
        };
    };

})()
and the template is
<div class="tabbable">
    <ul class="nav nav-pills nav-stacked">
        <li ng-repeat="pane in panes" ng-class="{active:pane.isActive, 'invalid-tab':pane.invalid}" ng-show="pane.isVisible">
            <a href="" ng-click="select(pane)" >{{pane.title}}</a>
        </li>
    </ul>
    <div class="tab-content" ng-transclude></div>
</div>
our forms have the following markup for the add button:
<button id="btnAdd" class="btn btn-primary" ng-click="new(currentGuest)"
                                    ng-disabled="form.$invalid || disableAction">
                                @Labels.add
                            </button>
the disableAction is actually used when we click on that button (in order to prevent clicking when code didn't complete yet). So, my solution is really a hack.
If it's not broken, fix it until it is.


My Blog
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform