Model.raiseDataChanged and 'location' property

hi,

I have a node template that looks like:

var defaultTemplate =
    M(go.Node, "Auto",
        { resizable: true },
        new go.Binding("location", "location"),
        new go.Binding("width", "width"),
        new go.Binding("height", "height"),
        ....

that works great initially… but if I later want to update the location by doing:

        model.raiseDataChanged(this, "location", oldLocation, this.location);

it doesn’t do anything…

what I noticed is that the location does get updated whenever I do a data changed for ‘width’ or ‘height’… like:

        model.raiseDataChanged(this, "width", oldWdth, this.width);
        model.raiseDataChanged(this, "height", oldHeight, this.height);

any idea about what I’m doing wrong here?

thanks,
cAndrei

Model.raiseDataChanged (and Model.raiseChangedEvent) notify Changed listeners that something changed. They are not responsible for actually making any state changes in the model.

What’s the value of “this” in your quoted code? I’ll assume it’s a node data object, to which some Node is data bound. You’ll want to call:

        model.setDataProperty(this, "location", ...somePoint...);

Because the corresponding Node has that Binding of Node.location to data.location, the Node will be moved to the new point.

thanks for the reply,

I changed that to be:

        model.setDataProperty(this, 'location', new go.Point(newData.X, newData.Y));

and I can confirm that the ‘location’ property gets set to the new value…

but it still doesn’t update the node’s location unless I also update some other property… :(

any other ideas that I might try?
I’ll try to isolate this into a small test project in case something else is messing it up…

thanks,
cAndrei

yup… still happens… my test project has a model with 1 node, an input box for height, an input box for x and a button to update the node… the “update” code is this:

onButtonClick() {
    var newX = parseInt(this.xInput.val());
    var newH = parseInt(this.hInput.val());
    if (newX != this.node.location.x) {
        this.model.setDataProperty(this.node, 'location', new go.Point(newX, this.node.location.y));
    }
    if (newH != this.node.height) {
        this.model.setDataProperty(this.node, 'height', newH);
    }
}

send me a private message if you are interested in my test project…
and yes… this is TypeScript code… but I doubt that matters…

thanks,
cAndrei

Remember that every time that you modify either the diagram or its model you must conduct a transaction. The only exception is when initializing both. Every sample does this.

Note that some operations are documented to perform transactions, so that you don’t have to. This is particularly true for some listeners and event handlers that are called within documented transactions.

ok… that fixed the issue… thanks :smile:

actually… if I use transactions… it now works fine using ‘raiseDataChanged’ too… which is better for my needs…

but just so I better understand this… any idea why it would work for ‘height’/‘width’ without a transaction… but not for ‘location’?

thanks,
cAndrei

Why would it be better for you to call raiseDataChanged? It’s easier and more reliable to call setDataProperty.

Or do you have code that you cannot control modifying your model’s node data (or link data)? This happens with some frameworks such as AngularJS.

My guess regarding the “height” and “width” properties (which delegate to the “desiredSize” property) is that such changes will modify the size of the nodes, which will invalidate the layout, causing the layout to be performed eventually. Maybe. That’s why it’s better to control things by using a transaction.

it’s “better” because that way I control all my data and then just notify GoJS that stuff changed…
while if I use setDataProperty I will actually rely on GoJS to update my data… (and also I have to implement property setters, which I don’t need for anything else)

not a very good reason I guess… just a personal preference of keeping parts as separate as possible… :smile:

I don’t think you need to implement property setters any more or less whether you use Model.setDataProperty or Model.raiseDataChanged. (By the way, the former method calls the latter method.)

If you don’t care about undo/redo, you could call Model.updateTargetBindings. Or call Diagram.updateAllTargetBindings, if most model objects may have been modified outside of your control.

hmm… that’s actually a good point… :smile:

I guess undo/redo doesn’t quite work unless you use setDataProperty… right?

my problem is that I have to sync the diagram with a bunch of server-side object on each operation… so not really sure if goJS’s undo/redo would help me in any way… as it’s just a view of a much more complex thing…

Well, your code:

does pass both the previous value and the new value for the properties, so undo and redo should work.

Regarding:

Are you just doing the synchronization when ChangedEvent.isTransactionFinished? And that consists of running through the ChangedEvents in the Transaction.changes list of the Transaction that is the value of ChangedEvent.object, and sending to the server those changes that you care about preserving?

ummm… no… I listen to “SelectionMoved” and “PartResized” diagram events… and update the server side model accordingly… there is also the possibility for nodes to get moved/resized from server side events… that’s the case when I’m using the raiseDataChanged thing…

OK. If that’s all that users can do, that should work. I assume you don’t have a Diagram.Layout that would cause nodes to be moved, or any other code that moves or changes the size of nodes.

What I was suggesting is a standard way to get any number of changes sent to the server in an easily understood and extensible manner.