locked
Validation Results in HTML Client RRS feed

  • Question

  • In my Silverlight client, I have code similar to the following to check validation results before saving and display a message box detailing any validation failures so that I can track down the cause:

                If (Me.Details.ValidationResults.HasErrors = False) Then
                    'Save to the database
                    Me.Save()
                Else
                    'If validation errors exist,
                    Dim res As String = ""
                    'Add each one to a string,
                    For Each msg In Me.Details.ValidationResults
                        res = res & msg.Property.DisplayName & ": " & msg.Message & vbCrLf
                    Next msg
    
                    'And display them in a message box
                    Me.ShowMessageBox(res, "Validation error", MessageBoxOption.Ok)
                End If

    I found the following code somewhere in the forums and figured it would do something similar:

        myapp.commitChanges().then(null, function fail(e) {
            myapp.cancelChanges();
            throw e;
        });
    But all that is contained in e is the message: "Cannot continue. There are validation errors on the page."

    That's not very helpful. I'd like to know what is failing validation. I had a few items get a red outline very briefly before the screen disappeared. I fixed those and now there are no red outlines but there are still validation errors. 

    Is there any way to do something similar to what I had in the Silverlight client in the HTML client?

    Tuesday, October 6, 2015 9:17 PM

Answers

  • Hey Kyle,

    The out-of-box experience passing of validation results from the server to the HTML Client falls short, unfortunately.  Basically it sometimes works just well enough to surface the built-in validation (IsRequired, Max Length, etc.).  And of course it requires a save operation round trip to the server.  Sometimes you get the validation message and red box on the HTML screen and sometimes you get the useless message that you found.

    The solution in the other forum adds the missing validation to the client-side so it doesn't specifically address your request to surface the server validation results.

    However, you understand it correctly, the bottom piece of code is a helper that simply looks for _validate methods in your client-side table code and hooks them up to contentItems on the screen.  Once that is in place, all you have to do is add property_validate methods in your table.lsml.js files and then call the helper in each screen.created method.  The result is you will get the validation messages (red box and red text) on your screen after each property is changed by the user and a trip to the server is not required.  In a later post of that thread, I explain it in a bit more detail.

    That said, back to your request...I do believe there is a chance that the property-specific server-side validation messages are coming back in the server response (at least for the built-in validation).  I would start by inspecting the response in fiddler to see what data is available.  There may be a way to intercept the generic error message and instead apply validation results to individual properties on the screen.  I'm guessing this would involve some hefty changes to the msls.js script since they don't expose much of the internals in this area.

    HTH,

    Josh

    • Marked as answer by kyle ls Monday, February 1, 2016 6:22 PM
    Wednesday, October 7, 2015 3:28 PM
  • This should help: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f84e841d-d5fe-4c63-84d8-9e3d25e7615d/best-place-to-put-client-side-property-validation-code-html-client?forum=lightswitch
    • Marked as answer by kyle ls Monday, February 1, 2016 6:22 PM
    Wednesday, October 7, 2015 10:40 AM

All replies

  • This should help: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f84e841d-d5fe-4c63-84d8-9e3d25e7615d/best-place-to-put-client-side-property-validation-code-html-client?forum=lightswitch
    • Marked as answer by kyle ls Monday, February 1, 2016 6:22 PM
    Wednesday, October 7, 2015 10:40 AM
  • I saw that but was hesitant to use it due to the lack of explanation of what is going on. I've stared at it a bit more and don't think it will do what I want.

    First of all, I know that with _Click and _Tap events, you must get the stub first by clicking "Write Code" and then the method otherwise it doesn't link. But there is no _validate. So do I just writ it and it just works? The bottom piece of code, is that just some global helper function and then I need to write individual _validates for each property in an entity?

    But my major problem with it is that it is providing custom validation for field and, if it fails, adding a validation result. My commitChanges is throwing an exception saying that something already isn't validated. So I don't need to add to the validation results. I need to retrieve them to see what is failing automatic validation because I don't know what it is.

    But I would like to understand the code you linked a bit better because I will have use of it in the future. Since you were the OP, can you explain how you used it and how it works a little better than the answerer did?

    Wednesday, October 7, 2015 1:53 PM
  • Hey Kyle,

    The out-of-box experience passing of validation results from the server to the HTML Client falls short, unfortunately.  Basically it sometimes works just well enough to surface the built-in validation (IsRequired, Max Length, etc.).  And of course it requires a save operation round trip to the server.  Sometimes you get the validation message and red box on the HTML screen and sometimes you get the useless message that you found.

    The solution in the other forum adds the missing validation to the client-side so it doesn't specifically address your request to surface the server validation results.

    However, you understand it correctly, the bottom piece of code is a helper that simply looks for _validate methods in your client-side table code and hooks them up to contentItems on the screen.  Once that is in place, all you have to do is add property_validate methods in your table.lsml.js files and then call the helper in each screen.created method.  The result is you will get the validation messages (red box and red text) on your screen after each property is changed by the user and a trip to the server is not required.  In a later post of that thread, I explain it in a bit more detail.

    That said, back to your request...I do believe there is a chance that the property-specific server-side validation messages are coming back in the server response (at least for the built-in validation).  I would start by inspecting the response in fiddler to see what data is available.  There may be a way to intercept the generic error message and instead apply validation results to individual properties on the screen.  I'm guessing this would involve some hefty changes to the msls.js script since they don't expose much of the internals in this area.

    HTH,

    Josh

    • Marked as answer by kyle ls Monday, February 1, 2016 6:22 PM
    Wednesday, October 7, 2015 3:28 PM
  • I noticed something interesting today.  The server validation errors are indeed passed back and even get assigned to the property screen.serverErrors.

    So for example, if you have a property called 'Phone' with server-side custom validation.  In screen.created method you can use a changeListener on the serverErrors property to show the server validation results on the phone contentItem like so:

    myapp.AddEditAccount.created = function (screen) {
        // Write code here.
        jabls.addScreenValidation(screen);
        screen.details.addChangeListener("serverErrors", function (e) {
            alert(e.target.serverErrors[0].message);
            e.target.screen.findContentItem("Phone").validationResults = e.target.serverErrors[0];
        });
    };

    To bring this to completion all we'd have to do is iterate the serverErrors array and set the validationResults for each contentItem respectively.

    HTH,

    Josh

    Wednesday, October 7, 2015 9:09 PM
  • Okay, this looks like it will give me the information I want. But I think my lack of experience in javascript is giving me some trouble in the "bringing this to completion" part so I'd like to ask you a few more questions.

    First, probably an unrelated tangent. What the heck is "jabls"? In your other answer, you use myapp.addScreenValidation. But here you use "jabls" which doesn't exist. Just curious about that one.

    Second, I tried in my button's execute method to create an array variable containing the validation results so that I could loop over them as you suggested. So I did this, which I'm pretty sure is completely wrong by the way it is behaving.

    myapp.AddEditQuote.BeginQuote_execute = function (screen) {
        myapp.commitChanges().then(null, function fail(e) {
            myapp.cancelChanges();
    
            var valArray = screen.findContentItem("Quote").validationResults;
    
            throw e;
        });
    };

    Previously, I'd put a breakpoint on the throw e and then look at e to see that useless message. Now, it never gets to e. After it hits the variable assignment line, it just continues on breaking out of the function and never hitting the trow. So could you kindly explain the proper way to loop over the validation results array?

    Another thing I noted was that the addition of this assignment line seemed to delay the screen transition long enough for me to see which field was causing my a problem. It was the primary key field which happens to be a GUID. For this particular table in the Silverlight client I did this:

    Me.qQuoteByFirm.SelectedItem.QuoteID = Guid.NewGuid()

    Which I don't think is necessary because my table is created like so:

    create table Quotes (
        "QuoteID" uniqueidentifier default newid()
            not null primary key,
        ...
    )

    And in other places in my code on different tables, I don't need to assign a GUID because the default newid() takes care of that for me. Unless I'm completely misunderstanding that interaction.

    Since javascript doesn't have a GUID class/function I'll have to write my own and have found several compliant examples online. But this all seems like far too much work for Lightswitch. I'm just trying to replicate the AddAndEditNew functionality from the Silverlight client. Am I going in the complete wrong direction or is the HTML client really this difficult to work with?

    Thursday, October 8, 2015 7:10 PM
  • Am I going in the complete wrong direction or is the HTML client really this difficult to work with?

    It really is not that difficult to work with if you are willing to do things differently.

    With Silverlight apps we tend to put multiple tables on the screen at one time. With the HTML Client you only want a small amount of information on he screen at any one time.

    You may think this would be slower than the Silverlight client but in my experience the app moves faster (we waste a lot of time waiting for all those bindings to refresh in Silverlight).

    This brings us to validation. With the HTML Client I do mostly server side table level validation and those show by using code such as:

    myapp.BrowseCustomers.ApplyChanges_execute = function (screen) {
        screen.getCustomers().then(function (customers) {
            // Delete selected
            customers.deleteSelected();
            // Save changes
            myapp.applyChanges().then(null, function fail(e) {
    
                // If error occurs, show the error.
                msls.showMessageBox(e.message, { title: e.title }).then(function () {
                    // Discard Changes
                    screen.details.dataWorkspace.ApplicationData
                        .details.discardChanges();
                });
    
            });
        });
    };
    See: Deleting Data In The Visual Studio LightSwitch HTML Client


    Unleash the Power - Get the LightSwitch HTML Client / SharePoint book

    http://LightSwitchHelpWebsite.com


    Thursday, October 8, 2015 8:32 PM
  • First, probably an unrelated tangent. What the heck is "jabls"? In your other answer, you use myapp.addScreenValidation. But here you use "jabls" which doesn't exist. Just curious about that one.

    jabls is my own namespace for a javascript library used in msls.  I put helper code in there rather than change the myapp namespace.  Rather than get into the additional steps for creating another js file, and knowing many folks who'd use the addScreenValidation function would put it in their own helper library, I simply used myapp in the other thread.

    Second, I tried in my button's execute method to create an array variable containing the validation results so that I could loop over them as you suggested. So I did this, which I'm pretty sure is completely wrong by the way it is behaving.

    myapp.AddEditQuote.BeginQuote_execute = function (screen) {
        myapp.commitChanges().then(null, function fail(e) {
            myapp.cancelChanges();
    
            var valArray = screen.findContentItem("Quote").validationResults;
    
            throw e;
        });
    };

    Previously, I'd put a breakpoint on the throw e and then look at e to see that useless message. Now, it never gets to e. After it hits the variable assignment line, it just continues on breaking out of the function and never hitting the trow. So could you kindly explain the proper way to loop over the validation results array?

    not sure if it will work in button execute or commitChanges callback, but the validation results eventually land in the screen.details.serverErrors property.  You could try this (air-code not tested):

    myapp.AddEditQuote.BeginQuote_execute = function (screen) {
        myapp.commitChanges().then(null, function fail(e) {
            myapp.cancelChanges();
            //not sure if serverErrors has valResults at this point(?)
            var valArray = screen.details.serverErrors;
            //not sure if the following loop is right(?)
            //for each validationResult
            $.each(valArray,function(){
                //assign to respective contentItem
                screen.findContentItem(this.property.name).validationResults = this;             
            });
        });
    };

    I'll play around with this in next few days and let you know how it goes.

    Another thing I noted was that the addition of this assignment line seemed to delay the screen transition long enough for me to see which field was causing my a problem. It was the primary key field which happens to be a GUID. For this particular table in the Silverlight client I did this:

    Me.qQuoteByFirm.SelectedItem.QuoteID = Guid.NewGuid()

    Which I don't think is necessary because my table is created like so:

    create table Quotes (
        "QuoteID" uniqueidentifier default newid()
            not null primary key,
        ...
    )

    And in other places in my code on different tables, I don't need to assign a GUID because the default newid() takes care of that for me. Unless I'm completely misunderstanding that interaction.

    Since javascript doesn't have a GUID class/function I'll have to write my own and have found several compliant examples online. But this all seems like far too much work for Lightswitch. I'm just trying to replicate the AddAndEditNew functionality from the Silverlight client. Am I going in the complete wrong direction or is the HTML client really this difficult to work with?

    I would suggest assigning the GUID just as you have in the screen code above, but instead, do so in the Quote_Inserting method in server-side table code.  This may be too late since the field is required, but give it a try anyway. 

    HTH,

    Josh


    • Edited by joshbooker Thursday, October 8, 2015 9:02 PM
    Thursday, October 8, 2015 8:55 PM
  • Totally willing to switch gears. The problem is that there is no easy comparison guide. Like, this is how you do something in Silverlight and here is how you do the same thing in HTML.

    The documentation for Lightswitch, in general, is crap. Your website is probably the best resource out there for learning these things. But my feet are kinda to the fire right now to get an HTML client up and running that mirrors the functionality of our Silverlight client and I just can't read your articles fast enough. Which is why I end up asking questions here.

    And the maddening thing about talking to pros like you (not picking on you, you just happened to provide a convenient example), is that you gloss over how someone would find certain things. For example, how did you know that the e parameter had a title and message property? Intellisense only lists 6 methods and no properties. And I'm not even sure that it does have those properties. When I implement your code all I get is a box with no title, no message and an OK button. Though it does pause execution long enough for me to see which box get highlighted in red which is very helpful.
    Thursday, October 8, 2015 10:08 PM
  • "Totally willing to switch gears. The problem is that there is no easy comparison guide. Like, this is how you do something in Silverlight and here is how you do the same thing in HTML."

    "The documentation for Lightswitch, in general, is crap"

    That's the quote of the day.  There is indeed no good comparison or even transition guidance from SL to HTML and there is little real documentation at all.

    Intellisense only works part of the time for javascript.  You have to place breakpoints and inspect objects at runtime, unfortunately.

    The only difference between 'pros' and non is the former have gone blindly down the maddening rabbit hole and surfaced unscathed a dozen or so more times than have the latter.

    Try things and then ask specific questions in this forum is the best any of us can do so keep your chin up - you're on right track. 

    Thursday, October 8, 2015 11:11 PM
  • My book starts from the beginning and walks you through each step.

    Also, there are full working examples you can download from the site for all the examples in the book.


    Unleash the Power - Get the LightSwitch HTML Client / SharePoint book

    http://LightSwitchHelpWebsite.com


    Friday, October 9, 2015 2:45 AM
  • Well then prepare for a crap load of questions in the upcoming weeks. :-)

    I'm going to take a few steps back and work through Michael's book from the beginning since his example project is similar enough to what I'm trying to do that I think it will be a useful step-by-step exercise. In the meantime I'm going to leave this thread open since you had mentioned playing around more. Hopefully by the time I reach this point again, this thread will have a definitive answer that I can mark. And I definitely want to give assigning a GUID on the server a try as well, so thank for that suggestion and all your help thus far.

    Friday, October 9, 2015 3:20 PM
  • Purchased. Your example order system is close enough to what I'm trying to do that I think I'll be able to follow along until I get a foothold in the HTML client. Thanks for the excellent resources!
    Friday, October 9, 2015 3:21 PM
  • Well then prepare for a crap load of questions in the upcoming weeks. :-)

    I'm going to take a few steps back and work through Michael's book from the beginning since his example project is similar enough to what I'm trying to do that I think it will be a useful step-by-step exercise. In the meantime I'm going to leave this thread open since you had mentioned playing around more. Hopefully by the time I reach this point again, this thread will have a definitive answer that I can mark. And I definitely want to give assigning a GUID on the server a try as well, so thank for that suggestion and all your help thus far.

    Best of luck kyle.  Did you try the code I provided?  It might just work.

    Josh

    Friday, October 9, 2015 4:14 PM
  • I haven't yet since I deleted most of my work to start from scratch and follow Michael's book step by step. Once I get back to where I need validation though, that will be the first thing I try.
    Friday, October 9, 2015 9:17 PM
  • Best of luck Kyle.  Just an update regarding my code from above, it doesn't work. ;(

    myapp.AddEditQuote.BeginQuote_execute = function (screen) {
        myapp.commitChanges().then(null, function fail(e) {
            myapp.cancelChanges();
            //not sure if serverErrors has valResults at this point(?)
            var valArray = screen.details.serverErrors;
            //not sure if the following loop is right(?)
            //for each validationResult
            $.each(valArray,function(){
                //assign to respective contentItem
                //this.property is null - Bug I think (?)
                screen.findContentItem(this.property.name).validationResults = this;             
            });
        });
    };

    When I was playing around with this I found a function called tryGetServerErrors (around line 6496 of msls-2.5.3.js). 

    This reads the odata.error from the server response body and parses validationResults. 

    The problem is, the function expects an entity URL in the validationResult.Target node of the server errors and all I get is "$0".  If I force the target to be the unique URL of the entity in the dataService.loadedEntities collection it works like a charm - automatic red box & error on screen contentItem. 

    Anyway, I'm pretty sure I stopped making sense a few sentences ago.  Suffice to say I think this is a bug on the server side.  Too bad cuz if was neat to see the red box and text automatically after hitting save - beats the message popup. 

    PS...come to think of it, some server validation messages didn't show the red box in desktop client either did they?  Instead they show at the top in a band under 'Server Errors', correct?  It's been so long I cannot recall, but this may be 'by-design'.

    Josh


    • Edited by joshbooker Tuesday, October 13, 2015 10:58 PM Entity URL
    Tuesday, October 13, 2015 10:54 PM