Naomi
Naomi

Reputation: 718

Using ui-views and angularjs ui Tabs and invalid input

I've recently switched markup in few of the forms to use angularJS ui Tabs component. The markups looks like this:

<div class="col-lg-3 col-md-3 panel-container">
                        <tabset vertical="true" type="pills">
                            <tab heading="@Labels.general" select="selectView('general')"  >

                            </tab>

                            <tab heading="@Labels.passes" select="selectView('guestPasses')">

                            </tab>

                            <tab heading="@Labels.history" select="selectView('guestActivity')">

                            </tab>
                            
                            <tab heading="@Labels.userDefined 1"
                                 select="selectView('userDefined1')" >
                            </tab>                     
                            
                            <tab heading="@Labels.userDefined 2"
                                 select="selectView('userDefined2')" >
                            </tab>
                        </tabset>
                    </div>

                    <div class="col-lg-9 col-md-9 panel-container">
                        <div data-ui-view data-autoscroll="false"></div>
                        <div data-ui-view="guestPasses" data-autoscroll="false"></div>
                    </div>

and the controller's code to select a view is the following:

$scope.selectView = function (viewName) {
                if ($scope.isNew) {
                    $state.go('new.' + viewName);
                }
                else {
                    $state.go('edit.' + viewName);
                }
            };

All seems to work well except for this change in behavior comparing with the original implementation - if I make invalid input in one of the controls, switch to another tab, then back, that bad input is gone. The valid input is preserved. I am wondering if it's possible to keep the invalid input this way or not?

Upvotes: 0

Views: 260

Answers (2)

Naomi
Naomi

Reputation: 718

I also want to share my solution in case it will help someone. In my controller I defined the following scope variable object array:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    $scope.tabsViews = [{
                index: 1, name: 'general',
                invalid: false, title: resourceFactory.getResource('Labels', 'general')
            },
            {
                index: 2, name: 'guestPasses', invalid: false,
                title: resourceFactory.getResource('Labels', 'passes')
            },
            {
                index: 3, name: 'guestActivity', invalid: false,
                title: resourceFactory.getResource('Labels', 'history')
            },
            {
                index: 4, name: 'userDefined1', invalid: false,
                title: resourceFactory.getResource('Labels', 'userDefined') + ' 1'
            },
            {
                index: 5, name: 'userDefined2', invalid: false,
                title: resourceFactory.getResource('Labels', 'userDefined') + ' 2'
            }];

and also this method to select a view:

$scope.selectView = function (viewIndex) {
                
                var newView = objectFindByKey($scope.tabsViews, 'index', viewIndex);

                if ($scope.previousIndex != null) {
                    $scope.tabsViews[$scope.previousIndex-1]["invalid"] = $scope.form.$invalid;
                }                
                
                $scope.previousIndex = viewIndex; 
                if (newView) {
                 
                    var viewName = newView["name"];
                    if ($scope.isNew) {
                        $state.go('new.' + viewName);
                    }
                    else {
                        $state.go('edit.' + viewName);
                    }
                }
            };

Then I added the following markup in my HTML:

<div class="col-lg-3 col-md-3 panel-container">
                        <tabset vertical="true" type="pills">
                            <tab ng-repeat="tab in tabsViews" select="selectView(tab.index)"
                                 class=" {{tabsViews[tab.index-1]['invalid'] ? 'invalid-tab': 'valid-tab' }}">
                                <tab-heading>{{tab.title}}</tab-heading>

                            </tab>
                        </tabset>
                    </div>

                    <div class="col-lg-9 col-md-9 panel-container">
                        <div data-ui-view data-autoscroll="false"></div>
                        <div data-ui-view="guestPasses" data-autoscroll="false"></div>
                    </div>

and finally this is what I have for the classes in the site.css:

.widget .invalid-tab * {
    background-color: #F9EAF3;
    /*color: #F9EAF3;*/
    color: #d43f3a;
}

    .widget .invalid-tab:hover * {
        background-color: #E06B6C;
        color: #ffffff;
    }

    .valid-tab {
        border-top: none;
    }

That's all - everything works quite nicely. I am getting the desired behavior with my invalid tabs.

Upvotes: 0

Brad Barber
Brad Barber

Reputation: 2963

Each tab is a separate ui-view with ui-bootstrap and by default invalid values are not applied to the model...so the changes are lost when you navigate to another state/tab. You can override the behavior with ng-model-options with the following

<input type="text" ng-model="model.value" ng-model-options="{allowInvalid:true}" ng-pattern="...">

There's also a similar previous question that provides some options for doing this for globally: How can I override Angular's filtering of invalid form values, forcing Angular to persist the $viewValue to $modelValue?

Upvotes: 1

Related Questions