6

We are using grunt-html-angular-validate package for HTML lints. It uses W3C online validator tool under-the-hood and, so far, it did a great job in validating our angular templates.

Today, it failed while checking the latest changes pulled from the repository with the following error:

Validating src/login/login.html ...ERROR [L37:C108]

Bad value {{regCodeRequired}} for attribute autofocus on element input.

Here are the related lines where it fails:

<div class="auth-reg-code-block" ng-if="regCodeRequired">
    <input class="form-control" type="text" name="regCode" 
           id="regCode" ng-model="user.regCode" autofocus="{{regCodeRequired}}" 
           placeholder="Registration Code" required>
</div>

This is basically a field for entering a registration code for the two-factor authentication. regCodeRequired is a boolean variable that is set to true once the user passed the first login/password authentication step.

And I see the input appearing with a focus on it (using chrome 39) - it is working.

Question:

I'm pretty sure there is a reason for the validation tool to complain, but I'm not sure how to proceed. Are we using autofocus attribute incorrectly? How should we fix the validation error?

I've looked through the W3C validator errors trying to find an explanation, but there is nothing about autofocus there. Also, nothing inside the w3cjs github repository.


Here is the grunt configuration for htmlangular:

htmlangular: {
    options: {
        relaxerror: [
            'Element head is missing a required instance of child element title.',
            'Attribute href without an explicit value seen.',
            '& did not start a character reference.',
            'not allowed on element form at this point.',
            'not allowed as child of element',
            'Element img is missing required attribute src.'
        ],
        reportpath: null
    },
    all: [
        "<%= app.src %>/*.html",
        "<%= app.src %>/**/*.html"
    ]
}

Would appreciate any pointers.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • 2
    Couple of sanity checks for you: you have only **one** `autofocus` attribute specified in your document at one time; you are setting the attribute value to "" (empty string) or "autofocus" (to represent `true`), or are not setting the value at all (e.g. ``) (any other values are invalid). Perhaps the validator is confused with the angular syntax because it isn't expecting an explicit value? – Cᴏʀʏ Jan 11 '15 at 05:14
  • i might be wrong, but have you tried ```ng-autofocus``` – mido Jan 11 '15 at 05:15
  • @Cory thanks for the inputs. `autofocus` is set only on this input and the value is getting set to `true/false` - at least, this is not right. But, this is static analysis, it cannot know what the value of the scope variable would be - I suspect it doesn't like the angular syntax there.. – alecxe Jan 11 '15 at 05:25
  • @Cory if you would elaborate more on how to proceed to fix the error, it can be a legitimate answer here. Thank you! – alecxe Jan 11 '15 at 17:44
  • It looks like grunt-html-angular-validate module is running the validation before the angular digest cycle gets applies to the template, that's why it is trying to validate the unprocessed statement `{{regCodeRequired}}` instead of the processed value true or false. Can you provide the code for your initConfig? Did you check if `options.angular` is set to true in your initConfig? – JoMendez Jan 21 '15 at 16:50
  • @JoseMendez edited the question with the `htmlangular` grunt task configuration. Thanks! – alecxe Jan 21 '15 at 19:23
  • Just be aware that when autofocus is present in a webpage the element will have the focus. `autofocus` is boolean meaning that it just has to be present to activate the focus. If you use `autofocus="false"` the element will still have the focus. See this fiddle: http://jsfiddle.net/2kec7qv8/ The correct usage example of autofocus is: – Travis Pettry Jan 21 '15 at 19:43
  • The `input` is only displayed if `regCodeRequired` true, so a value for `autofocus` would be unnecessary anyway. – a better oliver Jan 22 '15 at 14:29

2 Answers2

7

According to the specs, the autofocus attribute is a boolean attribute:

A number of attributes are boolean attributes. The presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value.

If the attribute is present, its value must either be the empty string or a value that is an ASCII case-insensitive match for the attribute's canonical name, with no leading or trailing whitespace.

The values "true" and "false" are not allowed on boolean attributes. To represent a false value, the attribute has to be omitted altogether.

The last paragraph pretty much explains why the validator is complaining.

In other words, you can replace

<div class="auth-reg-code-block" ng-if="regCodeRequired">
    <input class="form-control" type="text" name="regCode" 
           id="regCode" ng-model="user.regCode" autofocus="{{regCodeRequired}}" 
           placeholder="Registration Code" required>
</div>

with:

<div class="auth-reg-code-block" ng-if="regCodeRequired">
    <input class="form-control" type="text" name="regCode" 
           id="regCode" ng-model="user.regCode" autofocus
           placeholder="Registration Code" required>
</div>

You might be interested in ng-autofocus plugin.

dnozay
  • 23,846
  • 6
  • 82
  • 104
Salman A
  • 262,204
  • 82
  • 430
  • 521
  • 1
    Thanks! Correct me if I'm wrong: since this `regCodeRequired` binding would be evaluated to true/false - we are using `autofocus` correctly. Would you recommend making the validator ignore the error in this case? – alecxe Jan 23 '15 at 08:10
  • 2
    `autofocus` is a boolean attribute, just like `required`. Both `autofocus="true"` and `autofocus="false"` are incorrect; both will be interpreted as `autofocus` attribute *is present* causing the input to autofocus. Since the input is shown when regCodeRequired is true, you can safely replace `autofocus="{{regCodeRequired}}"` with `autofocus`. – Salman A Jan 23 '15 at 08:17
1

Try to put the angular option explicitly to true in your configuration (this should enables the process (digest) of the angular bindings {{}} and {{regCodeRequired}} should be substituted for the value of the variable regCodeRequired before it validate the html):

htmlangular: {
    options: {
        angular: true, //per documentation: Turns on ignoring of validation errors that are caused by AngularJS.
        relaxerror: [
            'Element head is missing a required instance of child element title.',
            'Attribute href without an explicit value seen.',
            '& did not start a character reference.',
            'not allowed on element form at this point.',
            'not allowed as child of element',
            'Element img is missing required attribute src.'
        ],
        reportpath: null
    },
    all: [
        "<%= app.src %>/*.html",
        "<%= app.src %>/**/*.html"
    ]
}

If this doesn't works then you'll need to treat this parameter as a custom directive:

 options: {
        customattrs: ['autofocus']
     //...
 }

Per documentation: https://www.npmjs.com/package/grunt-html-angular-validate

options.customattrs

Type: Array Default value: []

List all of the custom attributes you have created through directives and other means here. The validator will ignore warnings about these attributes.

You can use the * wildcard, e.g.: 'custom-attrs-*'

JoMendez
  • 880
  • 9
  • 22
  • First of all, thank you for trying to help! Neither option worked for me - same error. Though, I would like to see not only how to suppress the error , but also an insight about `autofocus` in general - as I understand we are not working with it correctly. FYI, adding `'for attribute autofocus on element input'` to the `relaxerror` helps to ignore the error. – alecxe Jan 22 '15 at 21:41