Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing widget element with a newly constructed DOM structure

<script>
(function( $ ) {

    $.widget( "my.dropbox", {
        errorText: function(text) {
            $(this.element).next().html(text);
        },

        _create: function() {
             var id = $(this.element).attr("id");
             var customDropbox = $(
                "<div class='form-group'>"+
                   "<label for='"+id+"'>"+getLabelFor(id)+"</label>"+
                   "<select id='"+id+"'></select>"+
                   "<div class='errors'></div>"+
                "</div>"
             );
             customDropbox.attr("id", id);

             $(this.element).replaceWith(customDropbox); // This removes original element from DOM

             populateOptions(id);
        },


    });

}( jQuery ));

$(document).ready(function(){
    $("#field1").dropbox(); //blank input field turns into a select with a label, populated options e.t.c..
    $("#button1").on("click", function(){
        $("#field1").dropbox("errorText", "This is a validation error message"); //throws an error saying dropbox is not initialized 
    });
});
</script>
<html>
     <body>
         <input id="field1" />
         <button id="button1">Press me</button>
     </body>
</html>

So I want a widget with public methods that will replace the original element with all the widget data associated with it. The problem with the above code is that the <select..> element is just a DOM element and if you call .dropbox(..) on it, it will say the widget is not initialized. Is there a way to make the select element into the widget object with the .errorText() method? All widget examples online add stuff around the original element but never replace it. As for the bigger picture, I'm trying to make a generic tool to configure forms dynamically. It's going to be all <input id="..."> in html but then javascript will query a database, get configuration for the field and turn it into a dropbox, checkbox or, say, a date picker with all the labels, validation, and other bells and whistles.

like image 597
Maxim Suponya Avatar asked Dec 13 '13 06:12

Maxim Suponya


1 Answers

There is more than one issue with your widget code. I'll try to summarize them:

1. Copy the data

You're not copying the data to the newly created customDropbox, so before

this.element.replaceWith(customDropbox);

you should copy the data:

customDropbox.data(this.element.data());

Now the widget will remember that it was initialized.

2. this.element is gone

After

this.element.replaceWith(customDropbox);

you should update this.element so that it points to the newly created customDropbox:

this.element = customDropbox;

3. errorText message takes wrong element

Since the widgets element (this.element) is now pointing to the <div class='form-group'></div> element, the errorText function must be slightly modified to:

this.element.find(".errors").html(text);

4. id should be unique

Now, both the wrapper <div> and the <select> have the same id, which is not allowed in HTML so remove the one on the <select> tag. Luckily, <label> can work without the for attribute, just write it like this:

<label>labelForId <select></select></label> 

Then to get the <select>-element, use this.element.find("select") in the widget.

Side note

`this.element` is already a jQuery element, so no need for the additional `$()` wrapping.

See this jsFiddle

like image 86
huysentruitw Avatar answered Oct 20 '22 09:10

huysentruitw