I have an observable array. For every array element I generate some html form, very extended, as the observable array items are large objects with observables in turn:
I made a version of your fiddle that uses components to supply the input fields. The component used is named 'my-' plus whatever the type
field is (this was necessary to distinguish my components from input
and select
tags). I don't know how well this will perform, but it's simple enough that you should be able to do some testing and see.
ko.components.register('my-input', {
viewModel: InputModel,
template: {
element: 'input-template'
}
});
ko.components.register('my-select', {
viewModel: InputModel,
template: {
element: 'select-template'
}
});
ko.components.register('my-mu', {
viewModel: InputModel,
template: {
element: 'mu-template'
}
});
function InputModel(params) {
return params;
}
function Model() {
records = ko.observableArray([
[{
type: "input",
id: "Date",
size: "100px",
value: ko.observable()
}, {
type: "select",
id: "Weather",
size: "100px",
value: ko.observable(),
options: [{
optId: "w1",
optTxt: "Cloudy"
}, {
optId: "w2",
optTxt: "Sunny"
}, {
optId: "w3",
optTxt: "Rainy"
}, {
optId: "w4",
optTxt: "Snowy"
}, {
optId: "w5",
optTxt: "Foggy"
}]
}, {
type: "input",
id: "Lat",
size: "80px",
value: ko.observable()
}, {
type: "input",
id: "Long",
size: "80px",
value: ko.observable()
}],
[{
type: "input",
id: "Date",
size: "100px",
value: ko.observable()
}, {
type: "select",
id: "Temperature",
size: "120px",
value: ko.observable(),
options: [{
optId: "t0",
optTxt: "<-10"
}, {
optId: "t1",
optTxt: "]-10 : 0]"
}, {
optId: "t2",
optTxt: "]0 : 20]"
}, {
optId: "t3",
optTxt: "]20 : 40]"
}, {
optId: "t4",
optTxt: ">40"
}]
}, {
type: "select",
id: "Wind",
size: "70px",
value: ko.observable(),
options: [{
optId: "wind1",
optTxt: "Strong"
}, {
optId: "wind2",
optTxt: "Weak"
}]
}],
[{
type: "input",
id: "Date",
size: "100px",
value: ko.observable()
}, {
type: "select",
id: "Weather",
size: "100px",
value: ko.observable(),
options: [{
optId: "w1",
optTxt: "Cloudy"
}, {
optId: "w2",
optTxt: "Sunny"
}, {
optId: "w3",
optTxt: "Rainy"
}, {
optId: "w4",
optTxt: "Snowy"
}, {
optId: "w5",
optTxt: "Foggy"
}]
}, {
type: "input",
id: "Lat",
size: "80px",
value: ko.observable()
}, {
type: "input",
id: "Long",
size: "80px",
value: ko.observable()
}],
[{
type: "input",
id: "Date",
size: "100px",
value: ko.observable()
}, {
type: "select",
id: "Temperature",
size: "120px",
value: ko.observable(),
options: [{
optId: "t0",
optTxt: "<-10"
}, {
optId: "t1",
optTxt: "]-10 : 0]"
}, {
optId: "t2",
optTxt: "]0 : 20]"
}, {
optId: "t3",
optTxt: "]20 : 40]"
}, {
optId: "t4",
optTxt: ">40"
}]
}, {
type: "input",
id: "Humidity",
size: "70px",
value: ko.observable(),
options: [{
optId: "wind1",
optTxt: "Strong"
}, {
optId: "wind2",
optTxt: "Weak"
}]
}, {
type: "mu",
id: null,
value: '%'
}
]
]);
}
var myModel = new Model();
ko.applyBindings(myModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<template id="select-template">
<select data-bind="style: {width: size}, value: value, options: options, optionsText: 'optTxt', optionsValue: 'optId'"></select>
</template>
<template id="input-template">
<input type="text" data-bind="style: {width: size}, value: value" />
</template>
<template id="mu-template"> <span data-bind="text: value"></span>
</template>
<div data-bind="foreach: records">
<div data-bind="foreach: $data">
<label data-bind="text: id"></label>
<!-- ko component:{name:'my-'+type, params:$data} -->
<!-- /ko -->
</div>
</div>
From your Fiddle, I see that you render each field as an individual item. You could bypass all the if
bindings if each item were presented the same, as a custom-bound text item that, when clicked, transforms into its editable field type.
If you want to preserve tabbing, the default presentation could be input, but upon focus, the appropriate field type displays.
Update: it occurs to me that you could even have your custom binding insert the appropriate input type into a bound div
, so your presentation would be exactly as it is, but all the logic is in the custom binding.
I've made a Fiddle that dynamically inserts the inputs of appropriate types. It's a little rough, but gives the general idea of the approach. I don't know whether it's a performance advantage over the if
bindings; it might just be doing the same things the hard way. Certainly the above suggestions of rendering as text or simple input and changing one field at a time when the user wants to edit would be faster on initial load.