Separating data and view

I’m trying to find a good way to separate the model data from the view specific properties. In order to remember things such as size, location, angle etc. I’m currently saving them with the model using two way data binding.

Are there already solutions for how these things can be kept well seperated? Some sort of MVVM architecture perhaps? Unfortunately databinding can’t be done on nested object properties eg. new go.Binding("text", "model.Name"); of course I could use a convertor, but it would only work in one direction. The Inspector also wouldn’t work anymore.

Just wondering if anyone has already put some thought into this.

You can still use TwoWay Binding for such sub-properties – but it requires use of a back-converter function implementing the opposite conversion.

I think the Inspector could be adapted to know about sub-properties.

Hi Walter,

thanks for your response.
You’re right, of course, TwoWay binding works like this:
new go.Binding("text", "model", modelToText).makeTwoWay(textToModel);
and then a back convertor that looks like this:
function textToModel(text, data) { data.model.name = text; return data.model; }
Is that what you were thinking?

The inspector also wasn’t a big problem. However, I found that I had to manually call the raiseDataChanged event. Neither of these calls to setDataProperty triggered it:
model.setDataProperty(data.model, "name", newValue);
model.setDataProperty(data, "model", newModel);
Is that expected behaviour? I assumed that if I set the model property that would be enough. Is that because model is a reference and it doesn’t change when I update the properties inside the object?

I’ll look into this as soon as I get a chance.

So you are right about how to define Bindings on “sub-properties”. If you take a look at a sample I just created at http://gojs.net/extras/bindingSubProperties.html, you will see two helper functions for declaring Bindings whose source is data.details.abc where “abc” is the second argument to the helper function. The name of the property whose value will be an Object is hardcoded to be “details”, but of course you can change that name or parameterize that name.

The OneWay binding helper function also takes an optional conversion function, and the TwoWay binding helper function takes two optional conversion functions.

Regarding the DataInspector, I have found and fixed some more bugs in that code. That will come out in the next release; until then you can grab it from [EDIT: obsolete URL, now in extensions/]. You’ll need its improvements so that you can have the DataInspector show and allow the user to edit those “details” objects.

Hi Walter,

great updates thank you! It does everything I want it to I think.

The idea of a helper function for sub bindings had come to mind, but I was trying to use a helper function to choose the convertor and back convertor. I didn’t think of replacing the whole binding with a helper.

The DataInspector is great too, I will just have to transfer a number of modifications I made (enum properties, adding properties at runtime etc.)

Thanks for the quick responses!

Calling model.updateTargetBindings triggers a SourceChanged event, while calling model.raiseDataChanged triggers a Property event which seems like a cleaner solution, because according to the Model docu the SourceChanged event is, “for internal implementation use only”. Does it matter which one I use?

I’m listening for the events in order to perform validation.

You should call Model.raiseDataChanged when you have the previous and current values for the state being changed. That makes it useful for undo.

If you do not have the previous value, calling Model.updateTargetBindings (or variations on that method) is your only recourse.