Failing to reevaluate property bound to table row knockout.js-style - javascript

I am failing to get a column updated from an array of objects loaded from the server.
I have got something like this:
self.tenants = ko.observableArray([{"Id":1,"Name":"Tenant 1","IsActive":true}]);
self.selectedTenant = ko.observable(null);
UI:
<tbody data-bind="foreach: tenants">
<tr data-bind="css: { 'active-row': $root.selectedTenant() === $data }">
<td>Select</td>
<td data-bind="text: Name"></td>
<td data-bind="text: Count"></td>
<td></td>
<td></td>
<td data-bind="text: IsActive"></td>
</tr>
</tbody>
Now I am trying to ensure the UI displays it when I set to IsActive to false.
I know that ideally IsActive is observable, but since I get the array straight from the server, I am not sure how I would do that.
Secondly I am somehow trying to get knockout to reevaluate the array.
I have tried several alternatives, one of which looks like this:
var selected = self.selectedTenant();
selected.IsActive = true;
var idx = self.tenants.indexOf(selected);
//self.tenants.remove(selected);
var newArray = self.tenants().splice(idx, 1, selected);
self.tenants(newArray);
//self.tenants.valueHasMutated();
But it all seems futile, the column always displays the original value. Where am I going wrong, or what should I do?

You need to map your server data to TenantViewModels thats using observables either manual or with the Ko mapping plugin
If you are doing it manual you can use the ko.utils.arrayMap function to map each element in the array from server to a new array with TenantViewModels

Related

How do I display an array / object using ng-repeat

I have an array that looks like the following:
I want to display that using angularJS ng-repeat, showing both count and value for each.
This is currently the HTML and angular I have but nothing displays.
I also don't need to display the 0 index in the array, I want to start from 1 if possible.
<tr ng-class="" ng-repeat="x in vm.data | filter: searchArray">
<td>{{x.value}}</td>
<td>{{x.count}}</td>
</tr>
I went back to the basics and understood that an ng-repeat is just a loop in javascript, and what do you need to do if you want to access data in JavaScript if your array is multi-dimensional? well you do a nested for loop, and thats exactly what I'm doing in this case.
This is the updated html/angularjs that displays the data I need:
<tbody>
<tr ng-repeat="x in vm.data">
<td ng-repeat="y in x">{{y.value}} {{y.count}}</td>
</tr>
</tbody>
Thank you guys again!

Angular bind table to generic object

I'm just starting to explore with Angular. Now what I'm trying to do is using an mvc handler that returns a jsonobject. However the returned jsonobject is generic, so it can be different types of object, and they all have a different amount of columns. I want to bind all these columns to a table, but that means i can't just create a fixed amount of columns and bind them like so:
<table class="table">
<tr ng-repeat="r in items">
<td>{{r.ID}}</td>
<td>{{r.Name}}</td>
<td>{{r.FirstName}}</td>
<td>{{r.Telephone}}</td>
<td>{{r.Email}}</td>
</tr>
</table>
this is NOT the way i want it, basically i want to have a table that binds to an object and that creates table columns for every property of the object.
thanks for any advice!
You can iterate the properties of the value like
<tr ng-repeat="r in items">
<td ng-repeat="(key, value) in r">
{{ value }}
</td>
</tr>

Knockout.js Tracking Selected Checkboxes

I have a html grid that returns a checkbox with each row. Currently I have these bound with knockout to my viewmodel. I've gotten far enough to capture the id of what is checked for a row but I'm not sure how to make Knockout give me a list of all rows checked and the content of every cell for the row.
Ultimately the intent is to let users select multiple rows from this table and then export that data. So I need a good way to gather the entire row up.
I've only been using Knockout for about a week so am I trying to get it to track something that perhaps I'd be better of just looping through the table with javascript?
<tbody data-bind="foreach: projectListing">
<tr data-bind="css: $data.rowclass">
<td><input type="checkbox" data-bind="value: $data.id, checked: $root.selectedRows, click: $root.toggleRowSelection"/></td>
<td data-bind="text: $data.SORT_ID"></td>
<td data-bind="text: $data.PROJ_ID"></td>
</tr>
</tbody>
*I know that code isn't enough to go on but I had to put something in here so I could list a link to jsFiddle.
I have a fiddle going that represents this to show code I have so far. What I'd like to do with this fiddle is each time I check the checkbox, the entire row content should show up. That would get me to the place I need to be in my real project.
Any ideas on how to go about this?
Here is what I have so far.
http://jsfiddle.net/robhortn/ad2Yu/4/
Instead of getting the id with the checked binding, you can create a selectedItems computed to get the selected items objects
self.selectedItems = ko.computed(function() {
return self.availableItems().filter(function(item) {
return item.Selected();
});
});
Html
Selected Books:
<div data-bind="foreach: $root.selectedItems">
<span data-bind="text: Name"></span>
<br/>
</div>
See this JSFiddle

Knockout JS foreach looping through array of objects

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.

How to make changes to $data propagate back to Knockout's view-model?

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.

Categories