Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Two complex problems with our tabs directive
Message
From
11/11/2015 04:15:02
 
General information
Forum:
Javascript
Category:
Other
Miscellaneous
Thread ID:
01627325
Message ID:
01627326
Views:
34
>Hi everybody,
>
>My colleague created these directives:
>
>
>(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,
>            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.select = function (uiView) {
>
>                    // call hook before changing state
>                    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 != false) {
>                        uiView.isActive = true;
>                    }
>                };
>
>                // called from $stateNotFound, $stateChangeError, $stateChangeAborted
>                // and $stateChangeSuccess event listeners
>                $rootScope.setNavTabs = function (viewName) {
>                    var i = 0;
>
>                    for (i = 0; i < panes.length; i++) {
>                        var pane = panes[i];
>
>                        // set to 'false' all but matching name
>                        pane.isActive = false;
>                        if ((pane.name == viewName)) {
>
>                            // recall hook if stateChangeAborted = true
>                            if ($rootScope.stateChangeAborted == true)
>                                pane.onActivating(viewName);
>
>                            pane.isActive = 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) {
>                        $scope.select(pane);
>                    }
>                    panes.push(pane);
>                };
>            },
>            templateUrl: 'app/templates/smNavTabs'
>        };
>    };
>
>    function navTabView($rootScope, $state, $stateParams) {
>        return {
>            require: '^smNavTabs',
>            restrict: 'E',
>            transclude: false,
>            replace: true,
>            scope: {
>                name: '@',
>                title: '@',
>                viewSettings: '@?',
>                onActivating: '&?',
>                isVisible: '=?'
>            },
>            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();
>
>                tabsCtrl.addPane(scope);
>            },
>        };
>    };
>
>})()
>
>with the template
>
>
><div class="tabbable">
>    <ul class="nav nav-pills nav-stacked">
>        <li ng-repeat="pane in panes" ng-class="{active:pane.isActive}" ng-show="pane.isVisible">
>            <a href="" ng-click="select(pane)" >{{pane.title}}</a>
>        </li>
>    </ul>
>    <div class="tab-content" ng-transclude></div>
></div>
>
>There are, unfortunately, two problems which I don't know how to solve.
>
>1. The invalid tab needs to show in red. This is how it is done in "static" case:
>
>
>ng-class="{true: 'invalid-tab', false: ''}[form.UserDefinedFields.$invalid]">
>
>More importantly, the invalid tab is not propagating to the whole form and I don't know how to make it work. Say, the first page will show several required columns in red, the Add (Save) button will be disabled. Switching to different tab activates that Add / Save button as the invalid state is not carried over.
>
>2. Similar problem seems to exist with the dirty state which is not propagating to the form. Making control dirty on some tab, then trying to navigate to a different row in the index list doesn't trigger 'Cancel changes' question. I had custom solution but I removed it as I want something generic.
>
>I think both problems can be somehow solved (e.g. saving the current form's state before switching over and restoring), but I don't see a way to access the form from the tab.
>
>Thanks in advance.

Not easy to see the problem amongst so much code without a runnable example. But it seems to me that this isn't really a 'Tab' control. You just have a set of buttons that inject the relevant view into the same area using $state.go. This means that when you go to any 'Tab' the view state of the existing view is lost.

It would be better if each tab had its own content which is shown or hidden depending on whether it is 'active'
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform