0

I am trying to focus the first tab which contains invalid field on a form submit. I did manage to focus on the first input field but it doesn't work if the field is in another tab and I have no idea how to make it works.

Here is my html file:

<uib-tabset justified="true"> 
  <uib-tab heading="{{ 'PERSONAL_INFORMATION' | translate }}">
    inputs...
  </uib-tab> 
  <uib-tab heading="{{ 'BANK_ACCOUNTS' | translate }}">
    inputs...
  </uib-tab> 
  <uib-tab heading="{{ 'CONNECTIVITY' | translate }}">
     inputs...
  </uib-tab>
</uib-tabset>

The directive that focus on the first invalid input:

app.directive('focus', function() {
    return {
        restrict : 'A',
        link : function(scope, elem) {
            // set up event handler on the form element
            elem.on('submit', function() {

                // find the first invalid element
                var firstInvalid = elem[0].querySelector('.ng-invalid');

                // if we find one, set focus
                if (firstInvalid) {
                    firstInvalid.focus();
                }
            });
        }
    };
});

I would appreciate any help.

Fabien Roussel
  • 225
  • 1
  • 4
  • 10
  • Possible duplicate of [Set focus to first invalid form element in AngularJS](http://stackoverflow.com/questions/19849174/set-focus-to-first-invalid-form-element-in-angularjs) – Fridjon Gudjohnsen Nov 01 '15 at 22:07

2 Answers2

0

If I'm understanding your question correctly, you want to focus on the first tab that contains the invalid element. To do that, give each tab an ngForm directive.

This will force the parent form controller to validate each of the tabs as an independent form (although they will continue to belong to the parent controller). As such, each will be treated like the a form, which will also be given an ng-invalid class. Assuming your tabs are focusable, it should work.

<form name="myForm" test>
    <uib-tabset justified="true"> 
      <uib-tab heading="{{ 'PERSONAL_INFORMATION' | translate }}" ng-form="form1">
          inputs...
      </uib-tab> 
      <uib-tab heading="{{ 'BANK_ACCOUNTS' | translate }}" ng-form="form2">
          inputs...
      </uib-tab> 
      <uib-tab heading="{{ 'CONNECTIVITY' | translate }}" ng-form="form3">
          inputs...
      </uib-tab>
    </uib-tabset>
</form>

You can see an (admittedly rudimentary) example on this plunk.

Caleb Williams
  • 1,035
  • 5
  • 12
  • I don't think this works for `` because the form elements are not descendants of the tab element. – Nik Dow Jan 24 '16 at 05:19
0

after you identify the first invalid element with

var firstInvalid = elem[0].querySelector('.ng-invalid'); you can find the controller of the tab it belongs to with:

var tab = angular.element(firstInvalid).parents('div.tab-pane').scope().tab

and you can call that controller's select function:

tab.select()

That will select the tab containing the firstInvalid element, which I think is what you mean by "focus the tab".

I had a further requirement, which was to show all tabs containing invalid controls with a background-color. This is more difficult as you need to identify the <li> containing the tab heading, and the tab scope doesn't have anything identifying the element.

I marked each tab with a class like this:

<uib-tab ng-repeat="(roomtype, roominfo) in data.roomtypes track by roomtype" heading="{{roominfo.title}}" class="roomtype-{{roomtype}}" >

and the roomtype property of the tab containing the invalid control is

var roomtype = tab.$parent.roomtype;

and I can set a class to indicate invalid like:

angular.element('li.roomtype-' + roomtype ).addClass('tab-invalid'); This statement relies on full jQuery being loaded as jqLite doesn't do lookups by CSS selector.

Nik Dow
  • 584
  • 4
  • 10