Reputation: 718
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
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
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