Most of the time i get some error for 'undefined' property in knockout. I found a solution for the same on stackoverflow answer. It is effective for simple binding, but my question is that how would i use this technique for 'foreach' binding like i have tried like
Demo here
below code is not working
<table>
<tbody data-bind="foreach: model.mappings">
<tr>
<td>
<select data-bind="options:mappings.variableList, optionsText:'Key',optionsValue:'Value', value:mappings.selectedVariable>
</select>
</td></tr></tbody></table>
But below code is working
<table>
<tbody data-bind="foreach:mappings">
<tr>
<td>
<select data-bind="options:variableList, optionsText:'Key',optionsValue:'Value', value:selectedVariable>
</select>
</td></tr></tbody></table>
Js for both is same like:
var list = //some array
var arr =// [{variableList : list}];
var model={
mappings:ko.observableArray(arr)
}
ko.applyBindings......
Imagine your "model" being a function. When binding in html, you are able to access only local variables of model. Model itself is not visible because that is out of your scope. Mappings is a variable in model and that's why you can access it by just writing foreach: mappings. model is not part of model, it is model... Hope this helps.
Also, when you write foreach: mappings then you kind-of enter a foreach loop so that is why you don't write mappings.PropertyName and instead just write PropertyName
edit: my comment on your post was completely wrong so I deleted it
Related
(First allow me to say that I'm just beginning to learn Node-RED concepts; I went through some beginners' guides at nodered.org, and now am trying to extend what I learned so far).
I'm trying to build a flow that starts with a simple JSON tree like
[{"position":"1", "title":"element #1"},
{"position":"2", "title":"element #2"},
{"position":"3", "title":"element #3"}]
To build that treee I use a template node, property is set to msg.payload.
The number of array elements (in theory) is dynamic. To make sure that this tree is true JSON I added a JSON node converting from String to JSON object.
Next I wish to parse that object into a dynamic html table. For this I used a JS function node that's looping through the object and embedding its elements into the according html elements like this:
var return="";
for(var i=0;i<=msg.payload.length-1;i++){
var row=msg.payload[i];
if(row){
return+="<tr>";
return+="<td>"+row.position+"</td>";
return+="<td>"+row.title+"</td>";
return+="</tr>";
}else{
return+="no object at index "+i.toString();
}
}
msg.payload=return;
return msg;
The output of the function then should be passed into a 2nd template like this:
<html>
<head></head>
<body>
<table border="1">
<tr>
<td>#</td>
<td>Title</td>
</tr>
{{ payload }}
</table>
</body>
</html>
I would have expected that the function's result is inserted into the static table of my template, and that happens indeed but not the way I hoped: somehow the html elements that got created by my function are not recognized as what they shoud be; instead I see that they are rendered as
<tr><td>1</td><
instead of
<tr><td>1</td>
etc.
Result is that the browser does not recognize those elements and prints them together with their contents outside my static table
Questions:
what do I need to do so that my 2nd template recognizes my computed string as a set of html elements?
or is this probably a concept not suitable for my purpose?
I'm assuming you are using handelbars for your templating engine. In that case use:
{{{ payload }}}
Instead of
{{ payload }}
However a more elegant approach would be this:
<html>
<head></head>
<body>
<table border="1">
<tr>
<td>#</td>
<td>Title</td>
</tr>
{{#each payload}}
<tr><td>{{this.position}}</td><td>{{this.title}}</td></tr>
{{/each}}
</table>
</body>
</html>
then just
return msg.payload
again thanks to #als9xd for pointing me into the right direction; his 2nd idea indeed sounds much more elegant but first I couldn't get it to work. After some trial-and-error and looking up documentation for the template node I finally came up with this: removed the function node from my original question and then altered the 2nd template to this code:
<html>
<head></head>
<body>
<table border="1">
<tr>
<td>#</td>
<td>Title</td>
</tr>
{{#payload}}
<tr>
<td>{{position}}</td>
<td>{{title}}</td>
</tr>
{{/payload}}
</table>
</body>
</html>
Difference to #als9xd's example is that I replaced {{#each payload}} with a simple {{#payload}}, plus omitted this when referencing the object keys.
Could this be due to different Node-RED versions?
Anyways this is starting to be much fun!
I have table and a select control:
<table>
<tr ng-repeat="object in objects" ng-click="setCurrentSelectObject(object)">
<td>{{object.id}}</td>
<td>{{object.member_id}}</td>
<td>{{object.description}}</td>
</tr>
</table>
<select ng-options="m for m in members" ></select>
members and objects are some arrays that are loaded using $resource by AngularJS.
object.member_id is a foreign key value to members.id , I want to bind object.member_id with the selected member.id in the select control.
How do I do that ?
Edit:
My approach until now:
I use ng-model=selectedMember inside the select control, and that gives me a member array, which is a complex structure from which I only need member.id and on-change="changedMember".
Inside changeMember I have the current selected object from the table to which I do : currentObject.member_id = selectedMember.
But this is a workaround, isn 't there a more ng-model-ish way of doing this ?
I have a need to bind some HTML to an object, but my issue is that I don't know the properties of the object at development time.
I have a selectedItem property in my main view model which I have bound to a section in my HTML:
<div data-bind="with: selectedItem">
</div>
Now I want to generate a table based on the property name and property values:
<div data-bind="foreach: [WHAT DO I PUT HERE?]">
<label class="control-label"><span data-bind="text: [OR HERE?]" /></label>
</div>
I have really no idea how to do this. Any help is greatly appreciated.
Also, just slightly extending this, I would like to handle the properties of the bound object differently, such as, if the property is just a primitive type, just output it, but if its another object/array, then handle it specially.
Can this be done?
If anyone else is looking to bind a simple object's properties. You can do it like this...
<table>
<tbody data-bind="foreach: arrayOfObjects">
<tr data-bind="foreach: Object.keys($data)">
<td data-bind="text: $parent[$data]"></td>
</tr>
</tbody>
</table>
note: object.keys is not supported in older browsers, but you can use this to add backwards compatability http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
Here is a working example using computed observable to select at runtime the data to show. Dynamically selected templates are also used to render the data according to the type of data to render (array or scalar).
I have a observableArray:
self.stats = ko.observableArray([
{"DFTD" : new Stat("Defensive TD", "DFTD",0,20,0,self.playerGroups[1])},
{"GL" : new Stat("Games Lost", "GL",0,16,0,self.playerGroups[2])},
{"FGA" : new Stat("Field Goals ATT", "FGA",0,100,0,self.playerGroups[0])},
]);
and i am trying to loop around it with a foreach and then print out the Stat objects name property which is the first element in that object.
<tbody data-bind="foreach: stats" id="stat-sliders">
<tr>
<td><span data-bind="text: stats.Stat().name"></span></td>
<!--/*<td class="statsListItem">
</tr>
</tbody>
Im not sure if im doing it right. I am a beginner with knockout and wondering if anyone can help?
The fiddle below creates an array of football stats, which contains a key field and a stat field. You could use the key field for quicker access if you like. If you want an object where you have the property be the key, that would allow for the quickest indexing, though its not an array then.
See if this is what you want.
http://jsfiddle.net/johnpapa/CgFjJ/
You shouldn't need to call back into stats. Notice that the span binds to the property of the model that is inside the array.
<tbody data-bind="foreach: stats" id="stat-sliders">
<tr>
<td><span data-bind="text: name"></span></td>
<!--/*<td class="statsListItem">
</tr>
</tbody>
Also, I don't think Knockout works well with keyed arrays like that.
I've got the following code using Knockout.js to display an array of bools as a series of checkboxes:
<table>
<tr data-bind="foreach: Array">
<td><input type=checkbox data-bind="checked:$data"></td>
</tr>
<tr data-bind="foreach: Array">
<td data-bind="text:$data"></td>
</tr>
</table>
<button data-bind="click: toggle0">Toggle Element 0</button>
<script>
var simpleModel = {
"Array" : ko.observableArray([ko.observable(false),
ko.observable(false),
ko.observable(true)]),
"toggle0" : function() {
simpleModel.Array()[0](!simpleModel.Array()[0]());
}
};
ko.applyBindings(simpleModel);
</script>
If you look at http://jsfiddle.net/tP9Dm/3/, you can see that, while the checkboxes respond to changes in the view-model, the view-model doesn't respond to changes in the checkboxes.
According to https://groups.google.com/d/msg/knockoutjs/-dHpOg5ZBPI/1q4iqdTlKvUJ, it looks like $data is unwrapped by the foreach loop, so data-bind doesn't know to use it to update the model.
Clearly I can fix this by making the array contain objects instead of simple booleans, but that seems like it should be an unnecessary extra layer of indirection. Is there a simpler way to propagate changes back to the model?
There doesn't seem to be a way to do this, because $data in this case is the unwrapped value.
Even setting up a click handler doesn't work, because the data sent to your handler is also unwrapped.
Bummer. Looks like the only way to do this is to wrap your observable into an object, another layer of indirection.