I need to be able to 'map' some certain data incoming to an existing javascript object that called upon the appropriate code of my MVVM framework, so I took my hand at trying it myself and I thought I had done a pretty good job, but I am running into a problem.
Basically, I draw a "mapping" like this, using Kendo's model system.
I know that on the outside, this looks a bit unnecessary, but it works well for me and fits my thinking process. I'm open to suggestions for other ways to do it, but ...
Anyway, the purpose of this is to "map" the `onRemove` functions to the `Tags` array when it comes in from the server, and to map the `onRemove, onEdit, onSave` functions to each child in the `Mutations` array. I can do this 'after' they are loaded, but I wanted to try this approach to learn more about javascript.
So then, this is my mapping code.
This will call the following code, which I felt pretty proud of myself for writing, considering this is my first time trying to do anything like this in javascript.
Now for a while, I thought this was awesome. It was working how I wanted, as demonstrated here;
So this code goes to my controller and gets a JSON list of all of the relevant items from the database (stored in `RavenDB` as JSON). This returns flat items, which is exactly how I want them in the database (since the functions can't be serialized, obviously). But when I get them into my UI, I want those functions. So in the `change` function, I take the data and pass it through my `fromJSON` function, which accepts the mapping defined in the view model.
This works, it works very well I think. But then when I try to go further and have other bindings on the view model.. .like this..
This is really normal kendo code. I attach the `change` event to a function so that it runs whenever that `ObservableArray` changes. This works fine in my other pages where I don't use mapping, but on this one, once the mapping runs, it seems to become 'unbound'. I have found that if I put the `bind` code _after_ the mapping is done, it works.
So I have to assume that what is happening is that the code that does the binding is somehow hidden inside of the `ObservableArray`, and that it gets deleted when it runs the mapping.
Can anyone help me with this?
Edit
I have also created a jsBin to show this behavior exists even without my mapping. This is something that is occuring in the `set` function of kendo, and I want to find a way to stop itjsBin
Basically, I draw a "mapping" like this, using Kendo's model system.
var
Model = kendo.data.Model.define({
Id:
"Id"
,
fields: {
Id: {
type:
"string"
,
},
Name: {
type:
"string"
,
},
Mutations: [],
Tags: []
},
mapping: {
Tags: {
children:
function
(data) {
return
$.extend(data, {
onRemove:
function
(e) {
// execute code
}
});
}
},
Mutations: {
children:
function
(data) {
return
$.extend(data, {
Label:
null
,
onRemove:
function
(e) {
// execute code
},
onEdit:
function
(e) {
// execute code
},
onSave:
function
(e) {
// execute code
}
});
}
}
}
});
I know that on the outside, this looks a bit unnecessary, but it works well for me and fits my thinking process. I'm open to suggestions for other ways to do it, but ...
Anyway, the purpose of this is to "map" the `onRemove` functions to the `Tags` array when it comes in from the server, and to map the `onRemove, onEdit, onSave` functions to each child in the `Mutations` array. I can do this 'after' they are loaded, but I wanted to try this approach to learn more about javascript.
So then, this is my mapping code.
kendo.data.ObservableObject.prototype.fromJSON =
function
(source, mapping) {
var
name,
value,
observable =
this
;
// if there is mapping given, then pass it through that first
if
(mapping) {
source = kendo.mapping(source, mapping);
}
for
(name
in
source) {
if
(observable.hasOwnProperty(name)) {
observable.set(name, source[name]);
}
}
}
This will call the following code, which I felt pretty proud of myself for writing, considering this is my first time trying to do anything like this in javascript.
kendo.mapping =
function
(source, mapping) {
var
name,
value;
// if the user provides us a mapping, we can use that to help
// build the objects appropriately
for
(name
in
source) {
if
(source.hasOwnProperty(name)) {
// get the value for this property or item
value = source[name];
// try to determine if this is an array, or just a
// normal object. That will greatly dictate our choice of behavior
if
(value
instanceof
Array) {
// if this is an array, then we will try to check for a
// key in the mapping schema
if
(mapping[name].children) {
// if we discover a mapping key for this array, we
// will use it to reconstruct the array data
for
(
var
i = 0; i < value.length; i++) {
source[name][i] = mapping[name].children(value[i]);
}
}
}
else
{
// attempt to match any non array type keys
if
(mapping[name]) {
source[name] = mapping[name](value);
}
}
}
}
return
source;
}
Now for a while, I thought this was awesome. It was working how I wanted, as demonstrated here;
// -------------------------------------------------------------
// create a kendo ui grid to show the existing prototypes
// -------------------------------------------------------------
widgets.grid = $(
'#grid'
).kendoGrid({
dataSource: {
transport: {
read: {
url:
"/administrator/data/prototypes"
,
dataType:
"json"
,
type:
'GET'
}
},
schema: {
total:
"total"
,
data:
"data"
},
page: 0,
pageSize: 15,
take: 15,
serverPaging:
true
,
serverFiltering:
true
,
type:
"aspnetmvc-ajax"
},
pageable: {
refresh:
true
,
pageSizes:
true
},
selectable:
"row"
,
columns: [
{
field:
"Id"
,
width: 25,
title:
"Identity"
},
{
field:
"Name"
,
width: 40,
title:
"Name"
}
],
change:
function
(e) {
// get the selected row from the grid
var
selected =
this
.select();
// get the data from the selected row
var
data =
this
.dataItem(selected);
// update the model
viewModel.fromJSON(data.toJSON(), viewModel.mapping);
},
}).data(
"kendoGrid"
);
This works, it works very well I think. But then when I try to go further and have other bindings on the view model.. .like this..
viewModel.Mutations.bind(
"change"
,
function
(e) {
// do something else
});
So I have to assume that what is happening is that the code that does the binding is somehow hidden inside of the `ObservableArray`, and that it gets deleted when it runs the mapping.
Can anyone help me with this?