Dynamically growing an array of text inputs (HTML/JavaScript)

Question!

I'm creating a data entry app for some in-house stuff.

My team needs to enter info about "items" which can have many "categories" and vice versa.

I need a quick way to let them enter an arbitrary amount of categories.

Here's my idea:

On the item entry page, I'll have it so that initially there's one text input for "categories" and if it's tabbed out of while it's empty, the input field is deleted (unless it's the only one) and focus skips to the next field. If it's not empty when it's tabbed out of and if it's the last input field in the array, then an additional "category" text input will be added and focused.

This way people can enter an arbitrary amount of categories really quickly, without taking their hands off the keyboard, just by typing and hitting tab. Then hitting tab twice to denote the end of the list.

First of all, what do you think of this interface? Is there a better way to do it?

Second of all, is there a jQuery (or something) plugin to do this? I've searched but can't find one. I searched scriptaculous/prototype and mootools too, with no luck.

I would obviously rather use something tried and tested than roll my own.

Any and all advice appreciated



Answers

it's actually not too difficult to implement that, even with vanilla JS (ie: no jQuery, prototype, etc), but everything is easier with jQuery, so I'll have a go at it using that:

Assuming a structure like this:

<form id="myForm">
    <div class="inputRow">
        <input type="text" name="myInput[]" />
    </div>
    <div class="inputRow">
        <input type="text" name="myInput[]" />
    </div>
    ...
</form>

Here's the JS

$('#myForm :text').blur(onBlurHandler);

function onBlurHandler() {
    $row = $(this).parent();
    if ($row
        .nextAll(":has(:text)")     // all following divs with a text element
        .length == 0                // but there aren't any, we're on the last one
    ) {
        if ($.trim($row.find(":text").val())) { // the text box isn't empty
            $copy = $row.clone(true);
            $copy
                .find(":text")  // get the new text box,
                .val('')        // remove any text in it
                .blur(onBlurHandler) // and add the event handler (is this necessary?)
            ;
            $copy.insertAfter($row);
        } else if ($row.prev(':has(:text)').length) {   // the text box is empty, and this one isn't the first row
            $row.remove();  // get rid of the row.
        }
    }
}


Response to comments:

thanks for the answer! i've tried it but it doesn't seem to work as intended. i'm on mac firefox. if i tab off the last field, it adds the new one but focuses the address bar. i tried adding: $copy.find(":text").focus(); after the insertAfter line, but it doesn't change anything. any ideas?

also if i shift-tab the blurhandler doesn't know i'm going in the opposite direction. is there any way around that?

Hmm, I hadn't thought about that. What you could try doing is to put an element after all your text fields which can take focus (like a textbox which is rendered off-screen, eg: margin-left: -10000px). Add an onfocus handler onto that to see if the last row is empty, and if it is, then it would have been added just then by the onBlurHandler function, so pass the focus back to the last row. If the last row isn't empty, then pass the focus onto the next element (your submit button, probably). If there are issues with the last row not existing in the DOM yet, then put the above into a timeout.

(If this actually works) this should let your users tab backwards and forwards without hassle.

By : nickf


First I'll try to address the problems commented on nickf solution.

To set the focus on the newly created input $copy.find(":text").focus(); will not work. The jQuery focus method only triggers the event, but does not call the underlying focus method.

You can set the focus with setTimeout(function(){$copy.find(":text").get(0).focus()}, 10); but:

  • setTimeout is needed in firefox or strange things will happen with the blinking cursor.

  • IE7 needs another input to focus when tabbing. I haven't found the way to set the focus on an input if the focus goes to the address bar. I suppose this will not be a problem because you will need at least a submit button.

To control shift-tab I've been trying to track the focused element, in order to skip the blurHandler when the focused element is a previous input, but the resulting code is really ugly so I'll post this and look for a better solution.

And last, you're asking what we think of this UI, and I think that a comma separated list of categories is easier to code an to fill in. :-)

By : Serhii


An easy way to remember it is the way "canonical" is used in theological circles, canonical truth is the real truth so if two people find it they have found the same truth. Same with canonical instance. If you think you have found two of them (i.e. a.equals(b)) you really only have one (i.e. a == b). So equality implies identity in the case of canonical object.

Now for the comparison. You now have the choice of using a==b or a.equals(b), since they will produce the same answer in the case of canonical instance but a==b is comparison of the reference (the JVM can compare two numbers extremely rapidly as they are just two 32 bit patterns compared to a.equals(b) which is a method call and involves more overhead.



This video can help you solving your question :)
By: admin