Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Two complex problems with our tabs directive
Message
 
 
To
All
General information
Forum:
Javascript
Category:
Other
Title:
Two complex problems with our tabs directive
Miscellaneous
Thread ID:
01627325
Message ID:
01627325
Views:
49
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.
If it's not broken, fix it until it is.


My Blog
Next
Reply
Map
View

Click here to load this message in the networking platform