Announcement Announcement Module
Collapse
No announcement yet.
Not updating a form field on setFormObject()? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Not updating a form field on setFormObject()?

    In our application, we send our form object off for asynchronous calculation and, when it returns, we update the form with the new form object. This works very well. The problem is that when a user is in the process of editing a form field when the calculation returns, we're currently blowing away their work. Obviously not good.

    One thought I have on this is, when the calculation returns, to register a VetoablePropertyChangeListener for the field with focus (assuming it's in my form and a bound control) and veto the update request, the drop the listener. Seems kind of hokey, but I was thinking that it would keep the field from getting updated nicely. However, with the SwingFormModel I can't add a veto listener.

    Anyone have any thoughts on this? I'm going to keep trying other things, but I thought I'd enlist the help of the experts.

    Thanks,
    Scott

  • #2
    It looks like you are using an older version of Spring-rich, as SwingFormModel has now been removed and replaced. After rummaging through (the latest) Spring-rich source, I can't find anywhere that VetoableChangeListener is used, except in AbstractPropertyChangePublisher, which is just a support class providing vetoable "fire" methods that are never called in the source. This tells me that there probably isn't support for Vetoable changes in spring-rich at the moment. I imagine, based on my current understanding of Oliver's (relatively new) form code that a good home for such Vetoable support would be ValueModel. I imagine something like this:
    Code:
      ValueModel formProperty = formModel.getValueModel("someFormProperty");
      formProperty.addVetoableChangeListener(someVetoableChangeListener);
    The ValueModel will then fire a PropertyChangeEvent at the VetoableChangeListener whenever the value changes and revert the value if the change is vetoed. Special care will have to be taken so that when the form object changes this PropertyChangeEvent is fired and that the "old" value to revert to if the change is vetoed is the value that the ValueHolder contained before the form object was changed. Hhhm.. not the greatest sentence in the world, but hopefully you get the idea.

    - Andy

    Comment


    • #3
      Yep, that's exactly what I want, but it sounds like it's neither in the version of RCP that we're using now, nor would it be in the new one if we upgraded (which unfortunately isn't an option now since we're on a minor patch of a product that uses it).

      Out of curiosity, can any of you come up with a good way to do this in the current world order?

      Comment


      • #4
        One thing to try is to create your own ValueModel for that property. I'm basing this on the latest sources, so I'm not sure how compatible this is to your version, but most FormModels will implement the ConfigurableFormModel interface, which provides the "add(String formPropertyPath, ValueModel valueModel)" method. You could use this method to supply your own custom ValueModel for the property. Another approach would be to supply your own MutablePropertyAccessStrategy (which is provides the source ValueModels to your FormModel). You would have to be careful to preserve default behavior when doing either of these (BeanPropertyAccessStrategy does all sorts of things with its ValueModel, for example)... maybe using the decorator pattern or extending BeanPropertyAccessStrategy? Anyway, once you have your custom ValueModel in place, you could design it to protect the property when the form object is changed - maybe even using Vetoable property change events.

        - Andy

        Comment


        • #5
          I can think of 2 solutions:

          1) Copy the property being edited from the current form object over to the new result object and then set that result object back into the form (make sure you do all this on the event dispatch thread). You could quite easily extend this to all properties modified since the last calculation started rather than just the currently focused property.

          2) If your calculation is only modifying some of the form's properties you could make your form object a PropertyChangePublisher and them just copy the appropriate properties from the result object to the form object. This would mean that only the properties modified by the calculation would be updated. Though this would still overwrite the field being updated by the user if that field was also updated by the calculation.

          Though as you're using an old version of the code I'd recommend you go with 1 - from memory the PropertyChangePublisher support was quite flaky.

          HTH

          Ollie

          Comment


          • #6
            Thanks, guys. Yeah, that's what I was implementing when this message came in. I have it working pretty well now. It helps that I really only have to worry about this for text components, because they're the only types of components that can be in a working state when the calculation returns. Other components like combo boxes, date pickers, etc., change values immediately and queue up their own calculation requests immediately. With a text component you can be in the middle of making a change when the calculation comes back.

            I think I'm there. Thanks again!

            Comment


            • #7
              Hi,

              now I came up with the same problem. Have you a little code-snippet that demonstrates how it works. This does not work:
              Code:
              ..
              MyObject myObject = (MyObject)getFormObject();
              myObject.setText("This is a test");
              setFormObject(myObject);
              --> no new value in the textfield
              thank you for your help

              Comment


              • #8
                Your call to setFormObject will do nothing as it will notice that you are setting the same object that is already contained in the form.

                This will work:
                Code:
                ..
                MyObject myObjectClone = (MyObject)getFormObject().clone();
                myObjectClone .setText("This is a test");
                setFormObject(myObjectClone);
                Or you need to make your MyObject class a property change publisher and fire a property change event when you change the "text" property.

                Ollie

                Comment


                • #9
                  thank you. But which way is better or do you prefer? A clone or a property change publisher?
                  Is there any example where a property change publisher is implemented?

                  markus

                  Comment


                  • #10
                    I think the suggestion of cloning the object was meant to help exemplify the point that calling setFormObject with the same object won't do what you wanted.

                    Using property changes would certainly be a better solution. Take a look at AbstractFormModel and its superclass AbstractPropertyChangePublisher for examples on how this works.

                    HTH,
                    Larry.

                    Comment


                    • #11
                      Actually I like both styles:

                      For demo's example, implementing property change support gives you the most natural API to work with, and as he's only updating one property, it's overkill to update the entire form object, which is what the clone will do, however, PCS does pollute your form objects with a whole lot of support code. This is an area where AOP would be very helpful as you could simply apply a PCS mixin and get the support without writing any code.

                      Lately I've started using cloning as a replacement for buffered form models as I've found with more complex master details forms implementing buffering at the value model level gets very complicated. While cloning is easy and gets me a buffer which is also a POJO. In fact this works so well I'm thinking that moving forward I'm going to switch our form handling code from buffering using value models to buffering using clones.

                      Ollie

                      Comment


                      • #12
                        I'm assuming the "clone" process would be done by instantiating a new instance and then copying the properties (typical bean model) since you can't assume that the domain objects will expose (or even support) a call to clone().

                        Could you expand on the sort of "complications" you've encountered with the buffered models?

                        Thanks.

                        Comment


                        • #13
                          I'm assuming the "clone" process would be done by instantiating a new instance and then copying the properties (typical bean model) since you can't assume that the domain objects will expose (or even support) a call to clone().
                          Right. You'd offer users a strategy for this.

                          Could you expand on the sort of "complications" you've encountered with the buffered models?
                          The "complications" are not just related to master details forms but I'll start my explanation there.

                          Given a basic M-D form with one form model for the master form and one form model which allows for editing a single detail item at a time and some logic for switch between which detail item is edited (along the lines of the M-D code you posted on the Wiki).

                          Now a user comes in and makes some edits to detail item number 1 and then decides to start editing detail item number 2. If we're buffering what do we do with the buffered edits for item 1 at this point? Well, at the moment, you must commit them back to into the item 1 form object or lose them, however once you've commited them back you loose an benefits you gain by using buffering - dirty checking no longer works, you can no longer revert the form etc.

                          Buffering also makes it impossible to use validation implementations that access the form object directly (implementations of Spring Validator for instance) rather than through a property access strategy.

                          Ollie

                          Comment


                          • #14
                            Since this conversation has moved into a distinct new area, I've moved the thread here "buffered value models vs. cloning (was Not updating form...)":

                            http://forum.springframework.org/showthread.php?t=17689

                            I hope no one objects.
                            Last edited by robyn; May 14th, 2006, 09:25 PM.

                            Comment

                            Working...
                            X