views:

269

answers:

2

I'm currently building the client side of a Flex/PHP project using the Presentation Model pattern.

What I'm trying to achieve:
I currently have a view displaying non-editable information about a domain object called Node. Depending on if the Node is editable and the user has the right privileges, an additional view becomes available where it's possible to make changes to this object. Any changes made are only committed to the server once the user decides to "Save Changes". If changes are made to a NodeA and the user navigates away to a different NodeB without saving them, NodeA is reverted to its original state.

Design:
I have a PM for the info view holding a reference to the current Node. The PM for the edit view is extended from this info PM, adding methods to make changes to the wrapped Node object. Both PMs has the same Node reference injected into them and all fields in the info/edit views are bound to the Node via their PMs.

The problem:
When the user makes changes to NodeA but doesn't commit them, I can't seem to think of an elegant solution to revert back to the original state. Basically, what I've thought of so far is to hold separate value copies on the edit PM, either clone-creating a new Node reference or through an identical set of Node properties. Of these two the former seems like the better idea because the Node already houses domain logic, but I wonder whether creating clones of unique domain objects is a bad practice, even if it's used in a limited scope.

A: 

Each view should have it's own instance of your Presentation Model class. Just maintain it in memory if the user has not saved it when moving to another view. Cloning accomplishes basically the same thing through a more convoluted process.

apphacker
The views do have their own PM instances, but both of the PMs hold a reference to the same Node instance which is injected into both. If I was to serve them separate instances of an identical Node, I'm making drastic changes to my model as I'm keeping a map/pool of Node instances (by id).
Stiggler
Your question made it seem as you have two views for two nodes. Why are two views with each their own PM instance referencing the same node? If that's the case maybe your two views are really two parts of the same interface, in which case have just one PM for both.
apphacker
If I had just one PM for both views, how would that solve my problem? I don't really see how it makes a difference.
Stiggler
+1  A: 

I handle similar cases by storing the original data in an XML property of the Value Object ("VO"), and reset all of the other property values when the VO is needed.

So, when it is first needed to be viewed, I go get the XML:

<Node>
    <prop1>value</prop1>
    <prop2>value</prop2>
    <prop3>value</prop3>
    <prop4>value</prop4>
</Node>

When I retrieve the XML, in my result handler, the first thing I do is create an instance of my VO, and set the XML property, and then call a public function in a separate class to set the VO's properties:

private function getNodeResultHandler(event:ResultEvent):void
{
    var myNode:Node = new Node();

    myNode.xmlData = new XML(event.result);

    nodeUtils.setNodeProperties(myNode);
}

public class nodeUtils
{
    public function setNodeProperties(node:Node):void
    {
        var nodeXmlData:XML = node.xmlData;

        myNode.prop1 = nodeXmlData.prop1;

        myNode.prop2 = nodeXmlData.prop2;

        myNode.prop3 = nodeXmlData.prop3;

        myNode.prop4 = nodeXmlData.prop4;
    }
}

Then, any time you switch your view to edit mode, you call that same function to reset the properties to the values stored in the XML.

The only other thing you need to do is reset that XML any time the user commits changes to the VO. I usually handle this by passing back the VO's data in the same format on a Save and Get, and then saving the XML just as above.

I usually do this in a Cairngorm MVC application, so I have event/command chains to handle all of this, but you can put this functionality in any number of classes, or in the VO class itself, whichever is easiest for you to maintain.

Eric Belair
Thanks for your input! It's good to see how other have handled similar situations. In my case, the XML object is a DTO, but I'd rather not maintain a reference to it on my model object. However, storing the DTO and implementing a "reset" method somewhere is probably how I will end up dealing with this. I'll revisit this question once it's been implemented.
Stiggler