angular-schema-form: Highlight array tab, if form in tab is invalid

I’m using "type":"tabarray" for an array and I’m looking for a way to put a css class on the `

  • ``-element of the tab if any field in that tab is invalid.

    I wonder if there is an elegant way to do it. We’ve found an ugly hack we can do in our controller where we look into the form.$errors and then add that styling…

    I added a custom mapping where I get the elements of the array as form.items and eventually pass these into a <bootstrap-decorator form="item"></bootstrap-decorator> that will render the form-fields.

    Given this extension-template:

    <fieldset ng-disabled="form.readonly" class="schema-form-fieldset {{form.htmlClass}}">
        <label class="control-label" ng-class="{'sr-only': !showTitle() }">{{ form.title }}</label>
        <div ng-init="selected = { tab: 0 }" class="schema-form-translatable {{form.htmlClass}}">
            <ul class="nav nav-tabs">
                <li ng-repeat="item in form.items"
                    ng-disabled="item.readonly"
                    ng-click="$event.preventDefault() || (selected.tab = $index)"
                    ng-class="{ active: selected.tab === $index }"
                    class="has-error tab-required"
                        >
                    <a ng-href="#" class="a-tag-required">{{ item.key.slice(-1)[0] | uppercase }}</a>
                </li>
            </ul>
    
            <div class="tab-content {{form.fieldHtmlClass}}">
                <div class="tab-pane"
                     ng-disabled="form.readonly"
                     ng-repeat="item in form.items"
                     ng-show="selected.tab === $index"
                     ng-class="{ active: selected.tab === $index }">
                    <bootstrap-decorator form="item"></bootstrap-decorator>
                </div>
            </div>
        </div>
        <div class="help-block" ng-show="form.description" ng-bind-html="form.description"></div>
        {{ languages = $$value$$; ''}}
    </fieldset>
    

    Here I would like to put an additional expression into ng-class="{ active: selected.tab === $index }" but I can’t figure out how to find out if just this sub-tree of the form is invalid:

    <li ng-repeat="item in form.items"
         ng-disabled="item.readonly"
         ng-click="$event.preventDefault() || (selected.tab = $index)"
         ng-class="{ active: selected.tab === $index }"
         class="has-error tab-required"
    >
        <a ng-href="#" class="a-tag-required">{{ item.key.slice(-1)[0] | uppercase }}</a>
    </li>
    
  • About this issue

    • Original URL
    • State: closed
    • Created 9 years ago
    • Comments: 18 (3 by maintainers)

    Most upvoted comments

    @ericxinzhang Just to update, I implemented this and it’s working nicely. Many thanks for your suggestion, much appreciated 😃

    Hi @ericxinzhang

    Interesting. That certainly does work. My immediate feeling is that it doesn’t feel particularly ‘angular’, it’s more about adding UI sparkle based on the presence of classes adding following validation. While this is a valid approach, it feels cleaner for us to be basing our evaluation of whether a tab’s pane contains invalid fields on the form object’s $error property rather than whether the markup contains particular classes. That said, I’m very much a newcomer to this project, so I may well be talking complete rubbish (and will happily be told so!).

    Anyway, this is a very good short term solution (which I’m in desperate need of), so will likely implement this as a fix whilst the discussion of how a long term fix should look continues. So thanks very much for posting it! 👍

    Many thanks Andrew

    @ericxinzhang Hey man, I forgot to say thanks!!!

    @raquintero I don’t have a plunker to show my updates at the moment. Will extract the changes from my project and create one when I have time, hopefully by this weekend.

    I had same requirement and worked out a quick solution. Note that the solution is

    • Not self-contained, you will have to expose some function in your model or service for the angular-schema-form directive to call.
    • Not a ideal solution, but the changes required are relatively small.
    1. For tabarray, the angular-schema-form I’m using (v0.8.13) generates the input’s ng-model attribute value as something like model['users']['0']['userid'], but generates the name attribute using the last part in ng-model value, in this case userid, and the only exceptional case is radiobuttons, in which case the name is users.0.userid. I updated all the templates, changed the name attribute to name="{{form.key.join('.')}}", which joins all form.key by ‘.’
    2. I then created a service which called in ng-submit, parses the form.$error object, splits input name by ‘.’ and then stores the errors by tab index, then by input name.
    3. As the angular-schema-form diretives have isolated scope and cannot access controller’s scope, I added a function hasError() to the model (which is passed to directive by sf-model). This function calls the service and return true if a tab has eror given the tab index.
    4. Finally I updated the template to add in the ng-class to the tab: ng-class="{'validation-error': model.hasError($index)}"

    This seems to be a duplicate of #336

    I think this should actually be something that is built into schemaform for better usability.

    User fills out a form that has list wich uses the “tabarray”. User wants to submit the form, but can’t due to validation errors. If that error is inside a tab that is currently not active, it’s not obvious to the user where the problem is.

    Isn’t that a very common thing? How to improve the usability?