locked
Two clicks to see the beforeApplyChanges validation results RRS feed

  • Question

  • When applying a validation in the screen beforeApplyChanges, it takes two clicks of the save button to get the validation to appear.  It makes the first click look like it is ignored, but it is executing the beforeApplyChanges event, and then the second one causes the screen to show the error.  My beforeApplyChanges is:

    myapp.AddEditAddress.beforeApplyChanges = function (screen) {
        if (screen.Address.Address2 == undefined) {
            screen.findContentItem("Address2").validationResults = [
                new msls.ValidationResult(screen.Address.details.properties.Address2, "This field is required.")];
            return false;
        }
    };
    Do I add a screen.refresh() or something else to make the validation message appear on the first click?
    Friday, August 2, 2013 12:07 AM

Answers

  • This appears to be because the screen.Address.details.entityState is "unchanged", such as would occur if the data in the database is invalid to the validator.  Then it requires a double-Save to get the validator to appear.  Otherwise, it works as expected.

    • Marked as answer by jwk1 Wednesday, August 7, 2013 11:29 PM
    Wednesday, August 7, 2013 11:28 PM

All replies

  • Have you tried checking if screen.Address.Address2 == null instead of undefined?
    Friday, August 2, 2013 3:05 AM
  • Replacing null for undefined in the code block above does the same thing.  It is not the code checking for the error, but the first time the save button is clicked, the code above runs and applies the validation result; however, the form does not react.  The second time save is clicked, the Error popup appears with "Cannot continue. There are validation errors on the page." and the Address2 field is highlighted in red with the error message from the code above.  I expected the first time to show me the Error popup.

    Monday, August 5, 2013 5:14 PM
  • Refresh() of anything for the screen gives "Object doesn't support property or method 'refresh'".
    Monday, August 5, 2013 5:26 PM
  • I also tried this on one of Beth's samples because my data source is imported from a Sql Server database.  The Contact Manager sample does the same thing where the validation applied in the beforeApplyChanges does not immediately appear when saving.  And the MSDN How to: Modify an HTML Screen by Using Code for Validate data on a screen at http://msdn.microsoft.com/en-us/library/vstudio/jj733572(v=vs.120).aspx#validate is called when the user taps the Save button on an Add/Edit screen, but does not say it only appears after the second tap.
    Monday, August 5, 2013 5:38 PM
  • This appears to be because the screen.Address.details.entityState is "unchanged", such as would occur if the data in the database is invalid to the validator.  Then it requires a double-Save to get the validator to appear.  Otherwise, it works as expected.

    • Marked as answer by jwk1 Wednesday, August 7, 2013 11:29 PM
    Wednesday, August 7, 2013 11:28 PM
  • This appears to be because the screen.Address.details.entityState is "unchanged", such as would occur if the data in the database is invalid to the validator.  Then it requires a double-Save to get the validator to appear.  Otherwise, it works as expected

    Any workarounds for this? I'm experiencing the two clicks before validation occurs as well.

    Nicolás.

    Wednesday, June 25, 2014 3:38 AM
  • I just started working with Lightswitch and came across this issue as well.  Have you found any workaround?  Thanks!
    Tuesday, March 10, 2015 3:05 PM
  • I face the same issue. Has a workaround been found for this as yet? Thanks in advance

    Regards, Xander. My Blog

    Saturday, March 12, 2016 5:25 AM
  • One possible workaround is to validate screen properties in their post_render methods instead of beforeApplyChanges.

    myapp.AddEditScreen.MyField_postRender = function (element, contentItem) {
    
        // screen property validation
        var validate = function (value) {
            if (value) {
                // get the entityState
                var state = contentItem.details.entity.details.entityState;
    
                // only validate if entityState === added, modified, or unchanged
                if (state === msls.EntityState.added ||
                    msls.EntityState.modified ||
                    msls.EntityState.unchanged) {
    
                    // validation logic
                    if (value.length !== 5) {
                        contentItem.validationResults = [
                            new msls.ValidationResult(contentItem.bindingPath,
                                "This field must be 5 characters.")];
                    } else {
                        // otherwise clear validation results
                        contentItem.validationResults = [];
                    }
                }
            }
        };
        // wire up the function
        contentItem.dataBind('value', validate);
    };

    A more robust solution was suggested by Josh Booker over here.



    • Edited by Hessc Monday, March 14, 2016 8:34 PM
    Monday, March 14, 2016 8:30 PM
  • Thanks Hessc, I have seen the above, but in my specific case there is a field that is required, depending on other fields, so using databind on that field does not work as it never fires unless the user actually edits it.

    I came up with the following work around helper functions that work for me:

    // add a validation error message and optionally outline control in red (works on screen variable based controls)
    // does not affect validationResults of contentItem at all
    LightSwitchUtils.displayErrorMessage = function (screen, contentItemName, errorMsg, displayControlRedOutline) {
        displayControlRedOutline = displayControlRedOutline || false;
        // clear existing error messages first
        this.clearErrorMessage(screen, contentItemName);
        // display new error message
        var contentItem = screen.findContentItem(contentItemName);
        if (contentItem && contentItem._view) {
    	var element = contentItem._view._container[0];
    	$(element).append('<div class="msls-validation-error-text msls-vauto">' + errorMsg + '</div>');
    	if (displayControlRedOutline) {
                $(element).find('.msls-presenter-content').addClass('msls-validation-error');
    	}
        }
    };
    
    // remove a validation error message and red outline around control in red (works on screen variable based controls)
    // does not affect/clear validationResults of contentItem at all
    LightSwitchUtils.clearErrorMessage = function (screen, contentItemName) {
        var contentItem = screen.findContentItem(contentItemName);
        if (contentItem && contentItem._view) {
    	var element = contentItem._view._container[0];
    	$('.msls-validation-error-text', element).remove();
    	$('.msls-presenter-content', element).removeClass('msls-validation-error');
        }
    };
    


    I then both set the ValidationResult in the beforeApplyChanges and use the above function to ensure that the error is visually displayed in red and this works for me. LS is "celver" enough not to double up on both the ValidationResult message (when it eventually displays it) and the one I set using the above routines:

    myapp.AdminSystemUserEdit.beforeApplyChanges = function (screen) {
        // check that user password is not null
        if (screen.SystemUser.ChangePassword && screen.SystemUser.PasswordPlainText === null) {
            var message = "Password field must be specified when changing password";
            screen.findContentItem("PasswordPlainText").validationResults = [
                new msls.ValidationResult(
                    screen.SystemUser.details.properties.PasswordPlainText,
                    message
                )
            ];
    	// overcome LS bug where error not immediately displayed (requires 2 clicks to display)
            lsu.displayErrorMessage(screen, 'PasswordPlainText', message, true); 
            return false;
        } else {
            return true;
        }
    };



    Regards, Xander. My Blog

    Tuesday, March 15, 2016 3:23 AM
  • Btw - I'm fairly sure that this is a LS bug, but I'm also fairly sure that there is no point in reporting the bug.

    However, Angie and Weiwei, if you read this post please report the above bug to the team.


    Regards, Xander. My Blog


    • Edited by novascape Tuesday, March 15, 2016 3:27 AM
    Tuesday, March 15, 2016 3:26 AM
  • That linked post from Josh is pretty good - I'll give that a go as well as it certainly makes writing the validation logic much nicer.

    Regards, Xander. My Blog

    Tuesday, March 15, 2016 5:23 AM
  • I think it is a bug.  If I recall, msls intends to hide validation messages at times.  In doing so it tries to toggle this property but loses track of it.

    This helped:

    contentItem._alwaysShowValidationResults = true;

    HTH,

    Josh

    Sunday, March 20, 2016 5:03 PM
  • In the linked post above we use dataBind so it won't validate props that aren't changed by the user.

    You could expand the addScreenValidation function to save the properties array (props with '_validate' methods) in a property of the screen.  Then, in beforeApplyChanges, iterate this array calling _validate methods for all props regardless of whether they were changed.   

    HTH,

    Josh

    Sunday, March 20, 2016 5:09 PM