admin管理员组

文章数量:1333490

<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.

<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.

Share Improve this question edited Dec 19, 2013 at 10:53 Pranav Singh 20.2k32 gold badges82 silver badges108 bronze badges asked Dec 13, 2013 at 6:38 Maxim SuponyaMaxim Suponya 1,5143 gold badges22 silver badges48 bronze badges 4
  • You say your widget has public methods .show() and .hide(). What object are those methods on? I think we need to see your jQuery widget code to better understand what your situation is and what you're asking. – jfriend00 Commented Dec 13, 2013 at 6:53
  • The widget is huge I don't think I can post it here but you're absolutely right, what object are those methods on? The problem is, I probably don't understand widgets 100%. What happens now is the widget factory adds .input() method to $, when I call it on a DOM element ._create() gets called, it creates new DOM elements and replaces this.element with them. But what is left after it exits? The DOM was modified and the element on which .input() was originally called is removed and replaced with new DOM elements. So how to turn them into "the widget"? – Maxim Suponya Commented Dec 16, 2013 at 3:58
  • Consulting the documentation for your widget library and looking at coding examples is probably in order. Not much I can do to help without seeing the doc/code for the widget library. – jfriend00 Commented Dec 16, 2013 at 4:07
  • Rewritten the question with basic code for the widget, please give it one more chance :) – Maxim Suponya Commented Dec 16, 2013 at 5:15
Add a ment  | 

3 Answers 3

Reset to default 6 +25

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

function show(){
   $("#field1").input({....});
}

function hide(){
    $("#field1").input("hide");
}

<button onclick="show()">show</button>
<button onclick="hide()">hide</button>

i think to replace the origin element which initial dropbox() is not a good solution,

because this will force you to rely on the implemention details of jQuery ui factory,

it is easy to make a mistake or introduce bugs, sometimes harder for other people to understand your code

if jquery ui factory change the implemention in the future, you have to modify all your code to make it work

(sorry for my limit understand of jquery ui)

i think we can put the <input/> into a container and initial dropbox() on the container which inturn

replace <input/> with <select> datepicker ..etc.. we can build modules easily by doing so:

<form>
  <div class="dropbox"><label for="someID">aaaaaa</label><input id="someID"/></div>
  <div class="datepicker"></div>
  <div class="othermodule"></div>
</form>

js:

$(".dropbox").dropbox(); // init dropbox you defined 
$(".datepicker").datepicker(); // ...
$(".othermodule").othermodule(); // ...

$(".dropbox").dropbox("errorText", "error"); // invoke it smoothly

here is a simple demo: http://jsfiddle/m4A3D/

@Wouter Huysentruit's answer provides a list of good suggestion for me

<form>
  <div class="dropbox">
      <label for="someID">aaaaaa</label>
      <input id="someID"/>
  </div>
  <div class="datepicker"></div>
  <div class="othermodule"></div>
</form>
<button id="button1">Press me</button>



  <script>
  (function ($){
     $.widget("my.dropbox", {
        _create: function () {
            var $input = this.element.find("input");
            var sID = $input.attr("id");
            var $select = $("<select>");
            $select.attr("id", sID);
            $input.replaceWith($select);

            this.element.append("<div class='errors'></div>");
        }, // end _create()
        errorText: function (text) {
            this.element.find(".errors").text(text);
        } // end errorText()
    }); 
  }(jQuery));


$(".dropbox").dropbox();
$("#button1").click(function () {
    $(".dropbox").dropbox("errorText", "this is error");
});
  </script>

本文标签: javascriptReplacing widget element with a newly constructed DOM structureStack Overflow