【问题标题】:Replacing widget element with a newly constructed DOM structure用新构建的 DOM 结构替换小部件元素
【发布时间】:2013-12-31 20:53:38
【问题描述】:
<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>

所以我想要一个带有公共方法的小部件,它将用与之关联的所有小部件数据替换原始元素。上面代码的问题是&lt;select..&gt;元素只是一个DOM元素,如果你在它上面调用.dropbox(..),它会说这个小部件没有初始化。有没有办法使用 .errorText() 方法使选择元素成为小部件对象?所有在线小部件示例都在原始元素周围添加了东西,但从不替换它。至于更大的图景,我正在尝试制作一个通用工具来动态配置表单。这将是 html 中的所有&lt;input id="..."&gt;,但随后 javascript 将查询数据库,获取该字段的配置并将其转换为 dropboxcheckbox,或者,比如说,带有所有 labelsdate pickervalidation 和其他花里胡哨的东西。

【问题讨论】:

  • 你说你的小部件有公共方法.show().hide()。这些方法在什么对象上?我认为我们需要查看您的 jQuery 小部件代码,以更好地了解您的情况以及您的要求。
  • 这个小部件很大,我想我不能在这里发布,但你说得对,这些方法是在什么对象上的?问题是,我可能无法 100% 理解小部件。现在发生的是小部件工厂将 .input() 方法添加到 $,当我在 DOM 元素上调用它时 ._create() 被调用,它会创建新的 DOM 元素并用它们替换 this.element 。但是退出后还剩下什么? DOM 被修改,最初调用 .input() 的元素被移除并替换为新的 DOM 元素。那么如何将它们变成“小部件”呢?
  • 查阅您的小部件库的文档并查看编码示例可能是正确的。如果没有看到小部件库的文档/代码,我无能为力。
  • 用小部件的基本代码重写了问题,请再给它一次机会:)

标签: javascript jquery html jquery-ui widget


【解决方案1】:

我认为替换初始 dropbox() 不是一个好的解决方案的原始元素,

因为这会迫使你依赖jQuery ui工厂的实现细节,

很容易出错或引入错误,有时其他人更难理解你的代码

如果 jquery ui factory 将来更改实现,您必须修改所有代码才能使其工作

(对不起,我对 jquery ui 的理解有限)

我认为我们可以将&lt;input/&gt; 放入一个容器中,然后将初始 dropbox() 放在容器上

&lt;input/&gt; 替换为&lt;select&gt; datepicker ..etc.. 我们可以通过这样做轻松构建模块:

<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

这是一个简单的演示:http://jsfiddle.net/m4A3D/

@Wouter Huysentruit 的回答为我提供了一系列好的建议

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

【讨论】:

  • 我不同意'强迫你依赖jQuery ui工厂的实现细节',我们需要依赖它的唯一部分是变量this.element永远不会被重命名。这不会发生,因为它是公共 API 的一部分。其余代码是纯 DOM 查找/操作。
【解决方案2】:
function show(){
   $("#field1").input({....});
}

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

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

【讨论】:

  • 这根本不是我要问的。
【解决方案3】:

您的小部件代码存在不止一个问题。我会尝试总结它们:

1.复制数据

你没有将data复制到新创建的customDropbox,所以之前

this.element.replaceWith(customDropbox);

你应该复制data:

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

现在小部件会记住它已被初始化。

2。 this.element 消失了

之后

this.element.replaceWith(customDropbox);

您应该更新this.element,使其指向新创建的customDropbox

this.element = customDropbox;

3. errorText 消息包含错误的元素

由于小部件元素 (this.element) 现在指向 &lt;div class='form-group'&gt;&lt;/div&gt; 元素,errorText 函数必须稍微修改为:

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

4. id 应该是唯一的

现在,包装器 &lt;div&gt;&lt;select&gt; 具有相同的 id,这在 HTML 中是不允许的,因此请删除 &lt;select&gt; 标记上的那个。幸运的是,&lt;label&gt; 可以在没有 for 属性的情况下工作,只需这样写:

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

然后要获取&lt;select&gt;-元素,请在小部件中使用this.element.find("select")

旁注

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

看到这个jsFiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    • 2018-07-16
    • 2021-04-06
    相关资源
    最近更新 更多