Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unique ids in knockout.js templates

Tags:

Suppose I have knockout.js template like this:

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

If I render this template in several places on the page I end up with several inputs with the same id (and several labels with the same for value), which has bad consequences. In particular, all code that depends on ids may not work properly (in my case I use jquery.infieldlabel plugin that gets confused by multiple inputs with the same id). The way I solve this issue now is I add unique id attribute to the model that I bind to the template:

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

This works, but it's not very elegant since I have to have this artificial id attribute in my models that is not used for anything else. I wonder if there is a better solution here.

like image 843
Roman Bataev Avatar asked Feb 10 '12 18:02

Roman Bataev


People also ask

How does Ko identify the template block that needs to be rendered?

Shorthand syntax: If you just supply a string value, KO will interpret this as the ID of a template to render. The data it supplies to the template will be your current model object.

What is two way binding in KnockoutJS?

KO is able to create a two-way binding if you use value to link a form element to an Observable property, so that the changes between them are exchanged among them. If you refer a simple property on ViewModel, KO will set the form element's initial state to property value.

Is KnockoutJS Mvvm?

Yes, knockout. js does apply the MVVM pattern. It's explained in the documentation: A model: your application's stored data.


1 Answers

An alternative that does not rely on the order that the fields are bound is to have the binding set an id property on the data itself, which would need to be an observable.

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);     }  }; 

You would use it like:

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

Sample: http://jsfiddle.net/rniemeyer/JjBhY/

The nice thing about adding a property to the observable function is that when you turn it into JSON to send back to the server, then it will just naturally disappear as the observable will just turn into its unwrapped value.

like image 90
RP Niemeyer Avatar answered Oct 11 '22 12:10

RP Niemeyer