Question
Michael Davidovich · Apr 5, 2022

Stop server side code when <form onSubmit> method finds errors

The documentation suggests this method for calling server side methods via SUBMIT: https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY...

Following that, the form I'm submitting needs to validate the dates entered (the startDate isn't past the endDate).  

Trying to keep everything in the .CSP file, I add a tag:

<script language="Cache" method="Validate" arguments="startDate:%Date,endDate:%Date">

I'm able to validate the dates here, but not matter what I do (quit, return false, redirect) the code that runs on the SUBMIT goes:

<script language="Cache" runat="server">

Essentially, how can I stop the runat="server" script from going when I find an error onSubmit from the form?

0
0 156
Discussion (8)3
Log in or sign up to continue

I guess more generally, I'm not sure when using this tag is supposed to be used:

<script language="Cache" runat="server">

It's clearer when to use:

<script language="cache" method="OnPreHTTP">>

<script language="Cache" method="SomeMethod">

If I move my code from the tag with the runat="Server" argument, then I can't seem to access the %request.Data object.  If I keep my code in that block, I can't use any &js<> syntax.

Can someone explain in a kindergarten way to me where this lives in the HTTP lifecycle?

@Michael Davidovich it might be helpful to look under the hood - specifically, at the class generated for the CSP page ("View Other" in Studio/VSCode).

OnPreHTTP is special in that it runs before the page is rendered (and can e.g. redirect you somewhere else). Generally, I would put code that runs on form submit / POST in OnPreHTTP.

Where you just have <script language="Cache" runat="server">, that'll run as the page is rendered whenever it gets to that block. This would generally be used to render more complex content for which other tag-based CSP options are in sufficient. If you're familiar with PHP, this is equivalent to the <?php ... ?> block in:

<html>
 <head>
  <title>PHP Test</title>
 </head>
 <body>
 <?php echo '<p>Hello World</p>'; ?> 
 </body>
</html>

<script language="Cache" method="SomeMethod"> would be used in hyperevents (i.e., #server(..SomeMethod())# and #call(..SomeMethod())#).

From a coding/design best practices perspective: you should be able to do input validation on the client to provide a friendly error message without needing to go back to the server (e.g., via #server). BUT you should also do validation on the server to make sure that even if the user (maliciously or otherwise) bypasses the client-side validation, they can't submit invalid data.

@Timothy Leavitt thank you!

I wouldn't have thought to do form logic OnPreHttp . . . the documentation suggests checking the %request.Data node for the form in the runat="server" script.  This does make sense if you plan to do a redirect, I think.

Thank you for helping me better understand the runat="server" timing.  It's been a while since I've touched PHP but this all rings a bell.  

You need to use HyperEvents to accomplish what you want. Use #server or #call. Although if I'm following your use case #server is the right one. In the corresponding javascript function you'll have code similar to

myfunction() {

...

var myvar = #server(mycachemethod());

//check myvar value

// return true or false based value

}

@Warlin Garcia thank you!  In fact, I'm doing something like this but I must be missing something.

Form has an attribute:

onSubmit="return #server(..Validate(date1,date2))#"

Validate() is in the CSP code as such:

<script language="Cache" method="Validate" arguments="startDate:%Date,endDate:%Date">
   startDate=$ZDH(startDate,3)
   endDate=$ZDH(endDate,3)
   if startDate>endDate {
  &js<
         alert('Invalid date range.');
          return false;>
   }
 </script>

I get my alert, but my page continues to reload, which would be fine I guess, but the %request.Data object with the data from the form is still populated. 

So when the following block runs, the process that I don't want to execute on the server side keeps going when I want it to not run.  I guess I'm not sure what returning false to the onSubmit actually does?  What is does not seem to do is clear or not set the %request.Data form nodes.  

 <script language="Cache" runat="server">
 
  If ($Data(%request.Data("FormThatWasSubmitted",1))) {
         startdate=%request.Data("STARTDATE",1)
         startdate=$ZDH(startdate,3)
  
        enddate=%request.Data("ENDDATE",1)
        enddate=$ZDH(enddate,3)

        job process^routine(startdate, enddate)

</script>

Side note: I'm jobbing off that routine which sends and email . . . if I do the job in the foreground with a DO the email sense, if I use JOB the email does not send (file still generates).  Anyone know why?

@Michael Davidovich you could/should definitely do that validation on the client as well. No need to go to the server to compare two dates.

To work as written, the ObjectScript method itself should return a truthy/falsy result (e.g., quit 0 or quit 1) rather than doing that return in JS.

If you turn on auditing for Terminate, Login, Logout, and Protect events you may see helpful things about what's happening with the JOB command (e.g., if it hits an error).

Ah ok, so just onClick=return fromAJavaScriptFunction()?

Define that in <script language="javascript">, right?

Returning 0 on the server-side method didn't seem to stop the form, my file was still generated from the process that runs after checking the %reqeust.Data("sumbitButton",1) node.  But I think I'll get rid of this anyway.

<script language="Cache" method="Validate" arguments="startDate:%Date,endDate:%Date">
   
   startDate=$ZDH(startDate,3)
   endDate=$ZDH(endDate,3)
   if startDate>endDate {
  &js<
  alert('Invalid date range.');>
  quit 0
   }
   quit 1
 </script>

I turned on that auditing btw and I'm not seeing anything. But doing some other debugging it seems that the %Net.SMTP.Send() method is getting hung up.  If I step through it, it's endless lines of code.  I put a break after the Send() method and it never reaches it.  Not sure if it's infinite looping or just getting hung.

So fun fact: in JavaScript, the string "0" is truthy (although the number 0 is falsy). That's what you're seeing here.