0

Background

I have a form with many text inputs (<input type="text" />). On pageload, I loop through the form and create a JS object variable for each one, that holds methods such as validate, and properties such as original value, current formatted value, validation requirements, etc:

field = new Field(wrapperElements[i]);

When an input has the blur event fired, I run validation on that field. I do this so that I can run my validation as the user is working through the form, rather than wait until the very end when the form is submitted.

I then cache the validity result in the Field object. When the user submits the form, I don't have to validate every field, I just have to check the already calculated validity, which improves speed at the end.


Problem

The user edits only one field, the cursor is still in that field, and the user hits enter. This fires the form's submit before firing the field's blur event. The form tries to submit without validating the edited field.

I know that I could just force validate all fields on submit, but that seems inelegant to me, and seems like wasted calculation. I just need to force validate the currently focused element, if that element is an input.


Part Solution

I've tested out document.activeElement, and that works. However, I can't figure out how to get the already existing JS variable that is associated with the input, from the node that document.activeElement returns.


Specific Question

If I have an HTML element, and I create a JS variable with it as such...

<input type="text" value="My input!" id="mainInput" />
---
var field = document.getElementById('mainInput');

... how can I get that field variable just from knowing returning the node again, separately, via document.activeElement?

Community
  • 1
  • 1
Kelderic
  • 6,502
  • 8
  • 46
  • 85
  • If you make more than one field required and use the code on this answer to prevent submit on enter, i think your issue might be solved http://stackoverflow.com/questions/16062525/disable-enter-submit – Cruiser Jul 05 '16 at 13:41
  • I already use event.preventDefault(), because I loop through the Field objects and check validity. I just don't want to have to calculate validity on all of them on pageload, I want to calculate it as it happens, in the background, to avoid a delay at the end. I cache the validity in the Field object, along with the HTML variable. Field is actually `{ data: {}, el : {}, validation: {} ... }`, and several attached methods. – Kelderic Jul 05 '16 at 13:44
  • right. what i'm saying is if you have required fields and the user can't press enter to submit, you'll force the .blur validate function to fire. – Cruiser Jul 05 '16 at 13:48
  • I do have all required fields using the official HTML5 require tag, and that does not force the blur event. I just double checked and confirmed this. Would be nice if it did. – Kelderic Jul 05 '16 at 13:51
  • Have you considered instead using a flag to indicate if a field has been validated (could be `null` for not having been validated, `false` for failed validation, and `true` for passed) and looping over them on submit to make sure **all** fields have been validated? Also, I'm sure you're aware of the issues with client-side validation, but I should probably mention (just in case) that you should not rely on it and always double check the validation on the server side. – Joseph Marikle Jul 05 '16 at 13:59
  • Using a flag would still leave the problem, because the flag would be set after validating the field, and I would still have to trigger validation, on top of looping through and checking each flag. As to client vs server, I do server in addition. – Kelderic Jul 05 '16 at 14:03

1 Answers1

1

Javascript lets you compare to HTMLElement variables with an == or === comparator. So you could loop through your stored variables, and compare them to document.activeElement.

...
fields[i] = form.children[i]
...

for ( ... ) {
    if ( fields[i] == document.activeElement) {
        // force validation of fields[i]
    }
}

This will check the active element against your stored elements. One potential issue here is performance. If you have a large number of elements, it might take a bit to loop through them.

Another option if you are super worried about that is during page load, add a data attribute to your element that is an integer, that you can reference the stored variable with.

...
fields[i] = form.children[i]
fields[i].dataset.interator = i;
...


var iterator = document.activeElement.dataset.iterator;
// force validation of fields[iterator];

This avoids the loop, and should take just a bit less time. If you have less than 50 fields though, it shouldn't be noticeable either way.

Kelderic
  • 6,502
  • 8
  • 46
  • 85
Mako
  • 168
  • 1
  • 1
  • 6
  • I'm going to try this out and see what type of performance hit it causes. The other option that I've thought about since posting this question is during the Field creation, tagging the HTML input element with a number that cooresponds to the global array of Field objects that I keep. Then I could just grab that `dataset-fieldlocation` and plug it into `self.fields[NUMBER]`. Testing both now. – Kelderic Jul 05 '16 at 14:06
  • That works! I looped through my global Field tracking array, and tested to see if the `field.el.input == document.activeElement` and if so, forced that field to revalidate itself, before processing the form. Do you mind if I edit your answer just a bit for clarity for later readers? – Kelderic Jul 05 '16 at 14:11