knockout.js模板中的唯一id

qgzx9mmu  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(101)

假设我有这样的knockout.js模板:

<script type="text/html" id="mytemplate">
    <label for="inputId">Label for input</label>
    <input type="text" id="inputId" data-bind="value: inputValue"/>
</script>

如果我在页面上的几个地方呈现这个模板,我最终会得到几个具有相同id的输入(以及几个具有相同 for 值的标签),这会产生不好的后果。特别是,所有依赖于id的代码可能无法正常工作(在我的例子中,我使用jquery.infieldlabel插件,它会被具有相同id的多个输入所混淆)。我现在解决这个问题的方法是我将唯一的id属性添加到我绑定到模板的模型中:

<script type="text/html" id="mytemplate">
    <label data-bind="attr: {for: id}>Label for input</label>
    <input type="text" data-bind="attr: {id: id}, value: inputValue"/>
</script>

这是可行的,但它不是很优雅,因为我必须在我的模型中有这个人工id属性,而不是用于其他任何东西。我想知道这里是否有更好的解决方案。

r7xajy2e

r7xajy2e1#

另一种不依赖于字段绑定顺序的方法是在数据本身上设置一个id属性,这需要是一个可观察的。

ko.bindingHandlers.uniqueId = {
  init: function(element, valueAccessor) {
    var value = valueAccessor();
    value.id = value.id || ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);

    element.id = value.id;
  },
  counter: 0,
  prefix: "unique"
};

ko.bindingHandlers.uniqueFor = {
  init: function(element, valueAccessor) {
    var value = valueAccessor();
    value.id = value.id || ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);

    element.setAttribute("for", value.id);
  }
};

var viewModel = {
  items: [{
      name: ko.observable("one")
    },
    {
      name: ko.observable("two")
    },
    {
      name: ko.observable("three")
    }
  ]
};

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<ul data-bind="foreach: items">
  <li>
    <label data-bind="uniqueFor: name">Before</label>
    <input data-bind="uniqueId: name, value: name" />
    <label data-bind="uniqueFor: name">After</label>
  </li>
</ul>

(也可使用JSFiddle sample
将属性添加到observable函数的好处是,当您将其转换为JSON并发送回服务器时,它将自然消失,因为observable将转换为其未 Package 的值。

fdbelqdn

fdbelqdn2#

我过去做过这样的事情:

ko.bindingHandlers.uniqueId = {
    init: function(element) {
        element.id = ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);
    },
    counter: 0,
    prefix: "unique"
};

ko.bindingHandlers.uniqueFor = {
    init: function(element, valueAccessor) {
        var after = ko.bindingHandlers.uniqueId.counter + (ko.utils.unwrapObservable(valueAccessor()) === "after" ? 0 : 1);
          element.setAttribute("for", ko.bindingHandlers.uniqueId.prefix + after);
    } 
};

你可以像这样使用它们:

<ul data-bind="foreach: items">
    <li>
        <label data-bind="uniqueFor: 'before'">Before</label>
        <input data-bind="uniqueId: true, value: name" />
        <label data-bind="uniqueFor: 'after'">After</label>
    </li>
</ul>

因此,它只是保持绑定本身的状态,递增ko.bindingHandlers.uniqueId.counter。然后,uniqueFor绑定只需要知道它是在字段之前还是之后,就知道如何获得正确的id。
示例如下:http://jsfiddle.net/rniemeyer/8KJD3/
如果标签不在它们的字段附近(在每个标签之前绑定了多个输入,可能在一个表的不同行中),那么您需要考虑不同的策略。

4ktjp1zp

4ktjp1zp3#

我无法回复所选的答案,但我有一个增强版的代码,它支持每个输入值有多个唯一的id。这是我的博客在http://drewp.quickwitretort.com/2012/09/18/0和重复这里:

ko.bindingHandlers.uniqueId = {
    /*
      data-bind="uniqueId: $data" to stick a new id on $data and
      use it as the html id of the element. 

      data-which="foo" (optional) adds foo to the id, to separate
      it from other ids made from this same $data.
    */
    counter: 0,
    _ensureId: function (value, element) {

    if (value.id === undefined) {
        value.id = "elem" + (++ko.bindingHandlers.uniqueId.counter);
    }

    var id = value.id, which = element.getAttribute("data-which");
    if (which) {
        id += "-" + which;
    }
    return id;
    },
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        element.id = ko.bindingHandlers.uniqueId._ensureId(value, element);
    },
};

ko.bindingHandlers.uniqueFor = {
    /*
      data-bind="uniqueFor: $data" works like uniqueId above, and
      adds a for="the-new-id" attr to this element.

      data-which="foo" (optional) works like it does with uniqueId.
    */
    init: function(element, valueAccessor) {
        element.setAttribute(
        "for", ko.bindingHandlers.uniqueId._ensureId(valueAccessor(), element));
    } 
};

现在,您可以为一条具有自动ID的记录设置多个带标签的复选框:

<li data-bind="foreach: channel">
  <input type="checkbox" data-which="mute" data-bind="uniqueId: $data, checked: mute"> 
     <label data-which="mute" data-bind="uniqueFor: $data">Mute</label>

  <input type="checkbox" data-which="solo" data-bind="uniqueId: $data, checked: solo"> 
     <label data-which="solo" data-bind="uniqueFor: $data">Solo</label>
</li>

相关问题