I have an observable array like this:
arrayName = ko.observableArray([
{name: First Name, type: normal},
{name: Second Name, type: low},
{name: Third Name, type: high}]);
and want to set my DOM element's class something like this:
<div data-bind="foreach: arrayName">
<div data-bind="text: name"> </div>
<div data-bind="css: type"> </div>
</div>
anybody know how to make it possible ?
Try to use this :
Example in JSFiddle
HTML:
<div data-bind="foreach: arrayName">
<div data-bind="text: name, css: type"> </div>
</div>
SCRIPT:
var myModel = function() {
this.arrayName = ko.observableArray([
{name: "First Name", type: "normal"},
{name: "Second Name", type: "low"},
{name: "Third Name", type: "high"}]);
}
ko.applyBindings(new myModel());
First of all, all your values for classes should be defined in string representation.
You add class (in your example) to the empty div, which doesn't have any content and you can't see it, if i understand you right you should add the class to the same div to which you add name property .
HTH.
Your example works, only need to add quotes for strings for each property:
<div data-bind="foreach: arrayName">
<div data-bind="text: name"> </div>
<div data-bind="css: type"> </div>
</div>
<script>
function vm (){
this.arrayName = ko.observableArray([
{name: "First Name", type: "normal"},
{name: "Second Name", type: "low"},
{name: "Third Name", type: "high" }]);
}
ko.applyBindings(new vm());
</script>
Related
I try to create a (for me) complex template (form). My data is like this
var fields = [
{ name: "field1", type: "text", label: "Name" },
{ name: "field2", type: "text", label: "Address" },
{ name: "field3", type: "date", label: "Birth date" }
];
My template (part of it) is like this:
<form id="EditForm">
<table width="100%" border="0">
<tr>
{{for}}
<td>
<div class="form-group">
<label for={{>name}}>{{>label}}</label>
<input type={{>type}} class="form-control" id={{>name}}>
</div>
</td>
{{/for}}
... etc...
I tried some different things but it is looks like it is not looping all my field.
I use jsREnder like this:
<div id="test"></div>
<script type="text/javascript">
$("#test").html(
$("#UpdateTemplate").render(fields, true)
);
</script>
I changed my code. It is working now. Just had to do a "for" without adding a field
I want to create a JSON that produces the following HTML form:
<div class="row">
<div class="column row-inner">
<label>First name</label>
<input type="text" value="">
</div>
<div class="column row-inner">
<label>Last name</label>
<input type="text" value="">
</div>
</div>
<div class="row">
<div class="column row-inner">
<label >Message</label>
<input type="text" value="">
</div>
</div>
<div class="row">
<div class="column column-big row-inner">
<label>Message</label>
<input type="text" value="">
</div>
<div class="column row-inner">
<label>Message</label>
<input type="text" value="">
</div>
<div class="column row-inner">
<label>Message</label>
<input type="text" value="">
</div>
</div>
I thought of creating an array and have more arrays inside:
schema: [{ // row
[{ // row-inner
name: 'First name', // label
type: 'text', // input
}, {
name: 'Last name',
type: 'text'
}]
}]
However, I find it overly complicated (I'm already confused myself).
Does anyone have a better suggestion?
// the form array
[
// the first row
[
// the first column
{
// the label
name: "First name",
// the input
type: "text"
},
// the second column
{
name: "Last name",
type: "text"
}
],
// the second row
[
{
name: "Message",
type: "text"
}
],
// the third row
[
{
name: "Message",
type: "text"
},
{
name: "Message",
type: "text"
},
{
name: "Message",
type: "text"
}
]
]
The form will be an array like this:
form = [row, row, row, row, ...]
where row is an array like this:
row = [column, column, column, ...]
and column is an object in this format:
column = {
name: "label's text",
type: "input's type"
}
jQuery code to transform the above structure into a form:
var form = ...;
var $form = $("<form></form>");
form.forEach(function(row) {
var $row = $("<div></div>")
.addClass("row")
.appendTo($form);
row.forEach(function(column) {
var $column = $("<div></div>")
.addClass("column row-inner")
.appendTo($row);
$("<label></label>").text(column.name).appendTo($column);
$("<input/>").attr("type", column.type).appendTo($column);
});
});
// append $form to a container
How about an Array of Person Objects?
var people = [];
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
var person = new Person('Foo', 'Bar');
people.push(person);
console.log(people[0]);
Person {firstName: "Foo", lastName: "Bar"}
Fiddle: https://jsfiddle.net/q1a7k30L/
How can we make the text clickable. Below is a list which is referred to a knockout template. I can directly check the box, but cannot able to make the text clickable so that it can reflect the checkbox.
HTML:
<ul data-bind="template: { name: 'choiceTmpl', foreach: choices, templateOptions: { selections: selectedChoices } }"></ul>
<script id="choiceTmpl" type="text/html">
<li>
<input type="checkbox" data-bind="attr: { value: $data }, checked: $item.selections" />
<label data-bind="text: $data"></label>
</li>
</script>
JS:
var viewModel = {
choices: ["one", "two", "three", "four", "five"],
selectedChoices: ko.observableArray(["two", "four"])
};
viewModel.selectedChoicesDelimited = ko.dependentObservable(function() {
return this.selectedChoices().join(",");
}, viewModel);
ko.applyBindings(viewModel);
Jsfiddle Demo: here
Is there any way, that we can make it clickable?
Put a <label> around the <input> element:
var viewModel = {
choices: ["one", "two", "three", "four", "five"],
selectedChoices: ko.observableArray(["two", "four"])
};
viewModel.selectedChoicesDelimited = ko.dependentObservable(function() {
return this.selectedChoices().join(",");
}, viewModel);
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: choices">
<li>
<label>
<input data-bind="attr: {
value: $data
},
checked: $parent.selectedChoices" type="checkbox" />
<span data-bind="text: $data"></span>
</label>
</li>
</ul>
<pre data-bind="html: JSON.stringify(selectedChoices(), null, 2)"></pre>
In your fiddle: http://jsfiddle.net/x0f1pk6q/
Alternatively, you could construct an id attribute in the loop. You'll have to make absolutely sure it's unique though. I'd advice you to use some sort of utility that increments an index in a closure that is guaranteed to be unique per session.
You need to link the id and for attributes using the same method:
var viewModel = {
choices: ["one", "two", "three", "four", "five"],
selectedChoices: ko.observableArray(["two", "four"]),
getCbId: function(val, i) {
// This combination of value and index aims to create a
// "kind-of-unique" id. See answer for more info.
return "CB_" + val + "_" + i;
}
};
viewModel.selectedChoicesDelimited = ko.dependentObservable(function() {
return this.selectedChoices().join(",");
}, viewModel);
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: choices">
<li>
<input data-bind="attr: {
value: $data,
id: $root.getCbId($data, $index())
},
checked: $root.selectedChoices" type="checkbox" />
<label data-bind="text: $data,
attr: {
for: $root.getCbId($data, $index())
}"></label>
</li>
</ul>
<pre data-bind="html: JSON.stringify(selectedChoices(), null, 2)"></pre>
I want a computed to be updated when an observable array is updated. The array is populated with questions and answer (Yes or No). When the user change the answer of a question, I want some region to be visible or not.
So the computed is5B should be true if one of the question is answered "oui" and this should make the sections visible.
The is5B computed is only calculated at initialization and is not fired when the array is updated (it is updated, I checked with a breakpoint)
Here's the view model:
var section5Model = ko.validatedObservable({
Questions5A: ko.observableArray(GetQuestions('5A')),
Questions5B: ko.observableArray(),
Questions5C: ko.observableArray(),
ContactAQ: ko.observable(),
Date: ko.observable(''),
Heure: ko.observable(''),
CategorisePar: ko.observable(''),
DateCategorise: ko.observable(''),
RepOuiNon: [{ label: 'Oui', value: 0 }, { label: 'Non', value: 1 }]
});
section5Model().is5B = ko.computed(function () {
this.Questions5A().forEach(function (item) {
if (item.reponse == 'Oui') {
return true;
}
});
}, section5Model());
Here's the markup:
<div id="sectionContainer">
<div id='S5FormBlock1' class="formSection5">
<div id="QSection5A" data-bind="foreach: Questions5A">
<div class='mockTable'>
<div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
<div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
<input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
</div>
</div>
<p />
</div>
<div data-bind="visible: is5B">Il s'agit d'une plainte qualité</div>
<div id="QSection5B" data-bind="visible: is5B,foreach: Questions5B">
<div class='mockTable'>
<div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
<div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
<input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
</div>
</div>
<p />
</div>
<div data-bind="visible: is5C">Il s'agit d'une plainte d'insatisfaction</div>
<div id="QSection5C" data-bind="visible: is5C,foreach: Questions5C">
<div class='mockTable'>
<div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
<div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
<input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
</div>
</div>
<p />
</div>
</div>
</div>
The problem that you have is that item.response is not observable. So if it change KnockoutJS doesn't know about that. To fix this you have to change that to observable
section5Model().is5B = ko.computed(function () {
this.Questions5A().forEach(function (item) {
if (item.reponse() == 'Oui') {
return true;
}
});
}, section5Model());
Computed are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change. so in your case no observable inside your computed function. so make at-least one variable in side computed as observable. in your case please make the item.response as observable. for that you need to return observable variable on GetQuestions('5A')
Please do Questions5A observableArray as like
var section5Model = ko.validatedObservable({
Questions5A: ko.observableArray([
{reponse : ko.observable('reponse 1 ') },
{reponse : ko.observable('reponse 2') },
/* other objects */
]),
/* other code */
Consider the following:
self.container = ko.observableArray([{name: 'hello', amount: [{item: name, key: '4', selected: 0}, {item: 'name', key: 2, selected: '1'}]}, {name: 'hello', amount: [{item: name, key: 10, selected: 0}, {item: name, key: 8, selected: '1'}]}]);
self.amountSelected = ko.observableArray();
If I do:
<div data-bind="foreach: container">
<div data-bind="foreach: amount">
<input type="radio" name="radio-selection-name" data-bind="attr: {value: key}, checked: $root.amountSelected()[$index()] || selected" />
</div>
</div>
This works, what doesn't work is notice how one of the amounts it's selected as it has a '1'
How do I say, select the currently selected item or use the selected item for this object?
Is there a way to set, for that index, the radio to selected if the selected attribute on the object is a '1'?
You cannot select more then one radio, so the checked binding dont need to be an observableArray for radios. The best way to set the value of the input is the checkedValue binding, in the snippet there are an example of both, but plese see the documentation Checked binding KO it is very useful.
function ViewModel(){
this.container = ko.observableArray([{name: 'hello', amount: [{item: name, key: 4, selected: 0}, {item: 'name', key: 2, selected: '1'}]}, {name: 'hello', amount: [{item: name, key: 10, selected: 0}, {item: name, key: 8, selected: '1'}]}]);
this.amountSelectedRadio = ko.observable(2);
this.amountSelectedChecked = ko.observableArray([8,4]);
}
ko.applyBindings(new ViewModel())
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h2>Checked Binding: Radio</h2>
<div data-bind="foreach: container">
<div data-bind="foreach: amount">
<input type="radio" name="radio-selection-name" data-bind="checked: $root.amountSelectedRadio, checkedValue: key" />
</div>
</div>
<h2>Checked Binding: CheckBox</h2>
<div data-bind="foreach: container">
<div data-bind="foreach: amount">
<input type="checkbox" name="checkbox-selection-name" data-bind="checked: $root.amountSelectedChecked, checkedValue: key" />
</div>
</div>