问题
I am having a difficult time binding a view model using an "Associative Array" with Kendo UI's MVVM. I've attempted to amalgamate a demo together, but it is really hard to when I don't have even a half-working one to go off of. But this is the best I've managed... Here is my code, along with a jsBin to demonstrate. It just doesn't seem to like the idea of an associative array, and I'm not really certain how else to hook into it.
The reason for the associative array is because I am pulling a lot of details out of the database, but they'll need to be invoked in certain places by name. Rather than write a bunch of searching/sorting methods, an associative array is a lot simpler for this. But in a few places where I do need to just list the data outright, it is giving me a great deal of trouble.
jsBin Demo
Javascript
var viewModel = new kendo.data.ObservableObject({
Id: "test/id",
Associative: new kendo.data.ObservableArray([])
});
var array = viewModel.get("Associative");
array["One"] = { Id: "id/one" };
array["Two"] = { Id: "id/two" };
array["Three"] = { Id: "id/three" };
kendo.bind('body', viewModel);
HTML
<div data-bind="text: Id"></div>
<div data-template="display-associative-many" data-bind="source: Associative"></div>
<script type="text/x-kendo-template" id="display-associaite-many">
<div>
${ data.Id }
</div>
</script>
Update
The data I need to bind to is stored in RavenDB
as an IDictionary<string, T>
, where T
is a specific kind of object (it kind of varies at times, so I can't give you a concrete type - nor is it really relevant)
So it is stored in the database like ...
"Model" : {
"ONE" : {
"Id" : "id/one"
},
"TWO" : {
"Id" : "id/two"
},
"THREE" : {
"Id" : "id/three"
}
}
Obviously there is more data than this, but this is all that is truly relevant at the moment.
While I do have the physical ability to change this, it is contrary to many other parts of the program. A lot of various places in the software work already on the premise of this being a dictionary. So I would like to avoid having to change all of that if possible. If that is truly, truly the only way to make this work at all, I will make the change.
What I could do though is do some mapping when it deserializes. My thought now is to assign the key
to a new property, Name
, and try to kendo bind to that. So the data would become, if my mental image is right ...
Associative: [
"One" : {
Name: "One",
Id: "id/one"
},
"Two" : {
Name: "Two",
Id: "id/two"
},
"Three" : {
Name: "Three",
Id: "id/three"
}
]
If I understand Kendo's observable
system right, that would make it ...
kendo.data.ObservableArray([
kendo.data.ObservableObject,
kendo.data.ObservableObject,
kendo.data.ObservableObject
])
And as I grasp it, that should be possible to model bind ... right?
Update 2
Following my own idea, I have made a somewhat successful version work with this method... However, I am not entirely sure if this is safe or efficient. I am growing concerned with the performance. I'm still trying to find other ways to achieve this result.
kendo template
<script type="text/x-kendo-template" id="display-items-many">
# for(var key in data) { #
# if (data.hasOwnProperty(key) && data[key].hasOwnProperty("Id")) { #
<tr>
<td>
<strong>#= data[key].Id #</strong>
</td>
<td class="text-right">
<code>#= data[key].Total #</code>
</td>
</tr>
# } #
# } #
</script>
html
<table class="table borderless table-hover table-condensed" data-bind="source: Associative data-template="display-items-many">
</table>
回答1:
First, Your template name is wrong:
data-template="display-associaitive-many"
id="display-associaite-many"
Second, JavaScript arrays don't work like that.
Plain JS (no Kendo involved):
var array = [];
array["One"] = { Id: "id/one" };
array["Two"] = { Id: "id/two" };
array["Three"] = { Id: "id/three" };
array; // prints "[]"
array.length; // prints 0
Associative arrays should be represented as objects http://www.laurencegellert.com/2012/01/associative-arrays-in-javascript/ which you can then wrap into a Kendo ObservableObject
. However, that means it isn't really an array with a length, so you can't bind it to a Kendo ListView.
Off the top on my head, the only way I can think of to represent that as a associative array (object) and still bind it to a ListView would be to bind your ListView to a function that then translates your object to an array. Tracking changes gets a little weird then though...
In response to your comments and updates to the original post:
I'm typing this off the top of my head, so my apologies if it doesn't work if you directly copy/paste it, but assuming you have a DataSource laoding the data, you could use the schema.parse
method to turn your data into an actual array, like:
var _parseTheData = function (data) {
var array = [];
var item;
for(var name in data) {
item = data[name];
item.Name = name;
array.push(item);
}
return array;
};
var ds = new kendo.data.DataSource({
transport: {
read: {
url: "http://wherever.com/theData"
},
schema: {
parse: _parseTheData
}
}
});
The idea is that if your server returned the object:
{
"ONE" : {
"Id" : "id/one"
},
"TWO" : {
"Id" : "id/two"
},
"THREE" : {
"Id" : "id/three"
}
}
Then the parse function would convert it to the Array:
[
{
"Id" : "id/one",
"Name" : "ONE"
},
{
"Id" : "id/two",
"Name" : "TWO"
},
{
"Id" : "id/three",
"Name" : "THREE"
}
]
Which you can then MVVM bind to a widget like normal. For example a ListLiew:
<div data-role="listview"
data-bind="source: ds"
data-template="item-template"></div>
<script id="item-template" type="text/x-kendo-template">
<div data-bind="text: Name"></div>
<div data-bind="text: Id"></div>
</script>
来源:https://stackoverflow.com/questions/24727545/difficulty-with-kendo-ui-mvvm-and-an-associative-array