Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    ValuesManager.validate() bug : No request is sent

    Hi Isomorphic,

    I have the following problem using 10.0p_2015-08-24/PowerEdition Deployment:

    See attached testcase and add the following to your supplyItem.ds.xml's SKU-field:
    Code:
    <validators><validator type="isUnique" errorMessage="SKU already in use!" /></validators>
    1. Set a breakpoint in Dev Mode on "Boolean doesNotTriggerRequest..." AND "if (doesNotTriggerRequest)".
    2. Open the sample, change the SKU and click save.
    3. First breakpoint is hit.
    4. Clear the server log.
    5. Hit F8
    6. See that there is nothing in the server log (validate() did not validate the change to SKU, this is the 1st bug) Click image for larger version

Name:	Breakpoints.png
Views:	180
Size:	15.1 KB
ID:	231566
    7. Hit F8 again
    8. See the Developer Console. Although the validation, which occurred now for the super.save(), had errors (missing required fields), the update was executed (this is the 2nd bug). Click image for larger version

Name:	DeveloperConsole.png
Views:	164
Size:	56.2 KB
ID:	231565
    Best regards
    Blama
    Attached Files

    #2
    Simple testing of changing the item from 45300 to 90600 did result in a failed validation for SKU being unique. However, the wrapper around VM.saveData() with a call to validate() isn't valid for this test. validate() validates client fields locally then issues a server request to validate the isUnique validator. The server request is asynchronous so the result of validate() only indicates success validating on the client. The update server call will also run all validators so a duplicate SKU will be trapped during the save.

    In general a VM performs validation per-form and only for items actually defined on the form. The category and unitCost fields are not defined on any form so they are ignored by the client validation. The server validation noticed the issue and reported it but the client discards these errors and will call VM.hiddenValidationErrors() if defined. You will notice that on the update request category and unitCost are included because they are part of the complete record.

    When using isUnique validator and calling validate() directly, you should place the PK field (itemID here) into each form so it is sent to the server with the validation request. It is needed to isolate the current record from the check.

    Comment


      #3
      Hi Isomorphic,

      Originally posted by Isomorphic View Post
      When using isUnique validator and calling validate() directly, you should place the PK field (itemID here) into each form so it is sent to the server with the validation request. It is needed to isolate the current record from the check.
      This sounds like a solution. I did not try this yet and will do so now.

      Originally posted by Isomorphic View Post
      Simple testing of changing the item from 45300 to 90600 did result in a failed validation for SKU being unique. However, the wrapper around VM.saveData() with a call to validate() isn't valid for this test. validate() validates client fields locally then issues a server request to validate the isUnique validator. The server request is asynchronous so the result of validate() only indicates success validating on the client. The update server call will also run all validators so a duplicate SKU will be trapped during the save.
      OK, thanks for the explanation. Further question in this area after reading the docs: Is there a difference between DynamicForm.validate() and DynamicForm.validateData() or are they synonyms? Also, there is DynamicForm.validateData(DSCallback), but no such method taking a CallBack on ValuesManager. Is it missing?

      Best regards
      Blama

      Comment


        #4
        Hi Isomorphic,

        I'm preparing a testcase in a similar area and found this thread. It has no priority for me, but it seems the APIs are still missing.
        This is DynamicForm:
        Click image for larger version

Name:	Validate_DF.png
Views:	138
Size:	23.2 KB
ID:	234063

        ValuesManager has only validate().

        Best regards
        Blama

        Comment


          #5
          Hi Isomorphic,

          could you explain the difference between DynamicForm.validate() and DynamicForm.validateData() (post #3).
          Also validateData(DSCallback callback) is missing javadoc-content.
          Also (minor) validate() is somewhere in the docs, not next to the other validation-methods. Normally you have similar methods doc'd together.

          Best regards
          Blama

          Comment


            #6
            validateData() is a rarely used API - we're going to add more to it's JavaDoc:

            <code>validateData()</code> checks for errors in server-side validators without applying such
            errors to the form. Errors, if any, can be discovered by looking at the
            <code>DSResponse</code> object returns in the callback.
            <p>
            <code>validateData()</code> will first call +link{validate()} to check for client-side errors,
            which will cause such errors to be displayed if present. To avoid this and purely perform
            silent, server-side validation, you can use +link{dataSource.validateData()} with the form's
            +link{getValues(),current values}.

            Comment


              #7
              Hi Isomorphic,

              I'll continue discussion for

              Originally posted by Isomorphic View Post
              We clarified some of the usage of validateData() in your other thread, covering that it's a rarely used API (arguably even superseded entirely by new behaviors of validate()).

              validateData() performs client-side validation first, and returns false if a client-side validator fails. In this case no server request will be issued so your callback won't fire. Currently, the SGWT API for validateData() doesn't actually return a boolean value, so you can't detect this scenario - we're fixing that. We'll also be fixing the issue where two requests can be sent.

              Having said all that - what are you actually trying to accomplish? It's unlikely that validateData() is the right API, as improvements elsewhere in the framework have rendered it mostly inapplicable - we might even deprecate it.
              and this thread here.

              I think as well that validateData() is not the right API for me, as I want to display server validation errors as well.
              With the change of the return type from void to boolean I could do this manually, but I'd like using validate() better.

              For this it would be great to have
              • validate() and ValuesManager.validate() to be boolean (already that way)
              • validate() and ValuesManager.validate() support a DSCallback
              For me, it would be OK with the Callback not being called in the case of client-validation failing (should be mentioned in the Docs then).
              I don't care for a validateHiddenFields-version with a Callback or at ValuesManager.
              Minor: I noticed the ValueManager uses java.lang.Boolean while DynamicForm uses primitive data type boolean.

              What I want to accomplish is to do validation and only save if there are no errors. In this thread I have the following problem.
              Pseudocode:
              1. Start Queue
              2. For all changed Forms/ValuesManagers, call validation, if it passes, save
              3. Send Queue
              My problem is that if a changed form includes a serverside-validator and only this one fails, the whole queue fails.
              In case of a clientside-only validation the form would not be saved, therefore not be in the queue, therefore the queue would succeed and only the erroneous form would not be saved.

              So what I want to do is
              1. Start "validation" Queue
              2. For all changed Forms/ValuesManagers, call validation
              3. Send "validation" Queue
              4. Start "save" Queue
              5. For all changed and error-free Forms/ValuesManagers, call save
              6. Send "save" Queue

              I can build a test case in the mentioned thread if needed.

              Best regards
              Blama

              Comment


                #8
                It's not clear why it's a problem that the whole queue fails in this case. Is the issue that, beyond seeing a validation error, the user also sees messages for the other operations failing?

                To perform server-side validation "silently" (where errors, if any, will not be shown to the user) and have a callback for completion, you can just take the values from the form or ValuesManager and call DataSource.validateData().

                Comment


                  #9
                  Hi Isomorphic,

                  yes, that is one part of the problem:
                  1. Transaction failed popup where I'd only expect a Validation error
                  2. Other requests not persisted, even though they do not have problems
                  I think I could do a combination of
                  • Queue with DataSource.validateData(Record values, DSCallback callback)
                  • DynamicForm.setErrors(java.util.Map errors, boolean showErrors) in the Callback
                  • Queue to save() the error-free Forms
                  Is that what you suggest?

                  Best regards
                  Blama

                  Comment


                    #10
                    Not saving data when there is an error is presumably a desirable result of using a transaction, right? If it's not, use two (or more) separate transactions.

                    As far the error message appearing, you could add code to suppress or modify the message shown for transaction failure - in any case you're going to need some kind of handling of that failure, since you presumably need to move the user to whatever form had the validation error that aborted the transaction.

                    If for whatever reason you prefer to do two separate operations, yes, you have the right idea.

                    Comment


                      #11
                      Hi Isomorphic,

                      I'm using the Queue to save HTTP requests, I'm not interested in separate transactions in this particular case (see above "Other requests not persisted, even though they do not have problems").

                      I'll go for the two-Queues solution then.

                      Can you log DynamicForm/ValuesManager.validate() with a Callback as an low-priority enhancement?
                      Also, is there a way to know in code (not from looking at the .ds.xml) if a call to validate() will require server-validation?

                      Best regards
                      Blama


                      Comment


                        #12
                        Hi Isomorphic,

                        it turns out I can't use DataSource.validateData() out of the box, as my clientside restrictions are more restrictive than the server ones.
                        I could overwrite validate() in my DMI, but don't like to do that (much boilerplate code in my case).

                        This is my new pseudocode for validation errors:
                        • if(!validate()) to change the tab icon for clientside validation errors (ValuesManager and DynamicForm)
                        • Forms now have AsyncValidationReplyHandler to do the same in case of server side validation errors (DynamicForm only)
                        Click image for larger version

Name:	TabSet.PNG
Views:	127
Size:	4.4 KB
ID:	236093


                        This is my code to trigger validation of all changed tabs and to trigger saving after successful validation (client+serverside (if needed));
                        Code:
                        RPCManager.startQueue();
                        for (DETAILTYPE dt : DETAILTYPE.values())
                            if (hasChanges(dt))
                                validateData(dt, mode);
                        if (RPCManager.hasCurrentTransactionQueued()) {
                            RPCManager.sendQueue(new RPCQueueCallback() {
                                @Override
                                public void execute(RPCResponse... response) {
                                    doSave(mode); //starts save-Queue
                                }
                            });
                        } else {
                            RPCManager.cancelQueue();
                            doSave(mode); //starts save-Queue
                        }
                        It seems to be working and I should be fine for now.
                        The only problem I'm seeing is that ValuesManager currently does not have addAsyncValidationReplyHandler(). This will become a problem once I have a ValuesManager that requires serverside validation.

                        Could you therefore also log ValuesManager.addAsyncValidationReplyHandler() as a low priority enhancement?

                        Best regards
                        Blama

                        Comment


                          #13
                          Yes, it makes sense for ValuesManager to have those same APIs for async validation, we'll get those added.

                          Note, another API you may have missed is valuesAreValid(), which is a way to determine if client-side validators would all pass, without displaying errors if they would not.

                          Comment


                            #14
                            Originally posted by Isomorphic View Post
                            Yes, it makes sense for ValuesManager to have those same APIs for async validation, we'll get those added.
                            That's great, thanks.

                            Originally posted by Isomorphic View Post
                            Note, another API you may have missed is valuesAreValid(), which is a way to determine if client-side validators would all pass, without displaying errors if they would not.
                            I really did not see valuesAreValid(), thanks.

                            Best regards
                            Blama

                            Comment


                              #15
                              Hi Isomorphic,

                              I bumped into this one again today and wanted to let you know that this is still missing, also in the 12.0d docs. No blocker for me, as there are workaround in my case, but would it be good to have that API nevertheless.

                              Best regards
                              Blama

                              Comment

                              Working...
                              X