We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 33372
    • 1,611 Posts
    Just wondering if anyone here has any recommendations for me in my latest annoyance...

    I have a multi-page form that send these long applications (using tab panes - so it’s really only one page as far as the browser is concerned). It’s done in eForm and works splendidly (thanks again!). However the clients now want me to add some extra functionality, and it’s a lot more work than they realize (isn’t that always the case?).

    Basically they want people to be able to save their unfinished forms and come back to them later. And they want to be able to view people’s unfinished forms so that they can contact them if they’re taking a while and ask them if there’s a problem they can help with. And they want this last week...

    So I set up a database table with the same fields as my form plus id, start date, and last modified date. And I set up a module in the Manager to view the info in this table. Now I’m at the stage where I need to set up the eForm events that save the info into the table and recall it if a person is continuing a previously-started form, and I’m looking for any advice folks may have.

    My thought is to use the applicant’s email address as their key for retrieving their info. I could actually make that a separate form, I guess. If you have previously started an application, enter your email here, if not click here to start one (and return an error if their email is not found, or post their info to the application form if it is).

    So then I’m thinking that I will have a "Save Your Work" button on each page of the form. It will need to submit the form but only so that the correct event function can insert/update to the database table. In order to not send a completed form when saving unfinished ones, my thought is to have a required variable that is set to blank and use JavaScript to set it to "send" only when people click the Submit button at the end, but I’m not sure if that’s the only/best way to do this...

    Has anyone grappled with this before? It seems like there will be several annoying issues, like resetting the validation placeholder so it doesn’t show errors on save, and probably lots that I haven’t thought of yet. Is there any code out there that I might find useful as a starting point or reference?

    THANKS in advance for your replies.
      "Things are not what they appear to be; nor are they otherwise." - Buddha

      "Well, gee, Buddha - that wasn't very helpful..." - ZAP

      Useful MODx links: documentation | wiki | forum guidelines | bugs & requests | info you should include with your post | commercial support options
      • 28042 ☆ A M B ☆
      • 24,524 Posts
      You could use give the non-final "submit" buttons a specific name, then use the "onBeforeFormParse" event to capture it and save the fields to the database then return "false" to stop the eForm processing. Use the same function to re-load the data into the $fields array if the "submit" button’s name is that of the submit for the returning user who just entered their email. only in that case return "true". Or something like that.
        Studying MODX in the desert - http://sottwell.com
        Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
        Join the Slack Community - http://modx.org
        • 33372
        • 1,611 Posts
        Quote from: sottwell at Nov 29, 2006, 01:10 AM

        You could use give the non-final "submit" buttons a specific name, then use the "onBeforeFormParse" event to capture it and save the fields to the database then return "false" to stop the eForm processing. Use the same function to re-load the data into the $fields array if the "submit" button’s name is that of the submit for the returning user who just entered their email. only in that case return "true". Or something like that.

        Return false. That seems like a good place to start. Essentially what I want to do when the save button is pressed is to update the database, alter the validation message ("Your info has been saved" instead of field errors), and stop eForm from trying to process the form any further.

        I wonder if I’ll need to re-populate the $fields array, since they will still be there as POST variables...

        I guess I’ll soon find out...
          "Things are not what they appear to be; nor are they otherwise." - Buddha

          "Well, gee, Buddha - that wasn't very helpful..." - ZAP

          Useful MODx links: documentation | wiki | forum guidelines | bugs & requests | info you should include with your post | commercial support options
          • 30223
          • 1,010 Posts
          Quote from: sottwell at Nov 29, 2006, 01:10 AM

          You could use give the non-final "submit" buttons a specific name, then use the "onBeforeFormParse" event to capture it and save the fields to the database then return "false" to stop the eForm processing. Use the same function to re-load the data into the $fields array if the "submit" button’s name is that of the submit for the returning user who just entered their email. only in that case return "true". Or something like that.

          1.
          The disadvantage of using the eformOnBeforeFormParse event for this is that none of the incoming data is validated by eform before you save it in your database. It is better to use the eformOnValidate event for this. It is ’fired’ before any further processing but at least incoming data is already validated. In your event function you can then test which fields are valid and need to be stored, or - when too many fields are invalid - return an error.

          If the values you want are valid you store them in the database and return true. Now here’s a little catch. If you return false from teh event eForm will simply return with an empty string, without the opportunity to set a message (this is a bit of a drawback of the current events, something I’ll have a closer look at in the future). The way around this is to set a special value either in $_SESSION or in the $fields array and use another event, eFormOnBeforeMailSent. In eFormOnBeforeMailSent you test for this special value and if it has the correct value set the $fields[’validationmessage’] to your custom message, then return false. eForm will now skip the rest and return with your message. The eFormOnBeforeMailSent is the only event where you can do this currently...

          I know it’s a bit of a workaround but I think it’s the best way to achieve what you want for now.

          2.
          If you do want to use the eformOnBeforeFormParse don’t return false! As explained above when you return false from the event eform returns an empty string. Instead, after succesfully storing stuff in the database, replace the $template[’tpl’] variable with a message of your choice and set one of the $fields array values to an invalid value. This will make the validation fail and display the form in $template[’tpl’] As you’ve just replaced that no error messages are displayed but your custom message instead. ...again a bit of a workaround smiley

            • 12652
            • 228 Posts
            Just some side thoughts...

            you should make sure that there isn’t any private or confidential information in this form... otherwise anyone could come along and enter in an email and have access to it.... sure it is unlikely, but still a potentiality.

            They should consider whether their ability to view a partial form and contact the person about it might be a turn-off to the person being contacted too.
              | Identity Developments delivers SEO focused web design and web presence services
              - it's not about websites, it's about your identity. |
              • 33372
              • 1,611 Posts
              Quote from: identity at Nov 29, 2006, 09:56 AM

              Just some side thoughts...

              you should make sure that there isn’t any private or confidential information in this form... otherwise anyone could come along and enter in an email and have access to it.... sure it is unlikely, but still a potentiality.

              That’s true, and it’s something that I’ve thought about. I was considering adding a password as well, but I have more trouble with people forgetting their passwords than anything else I can think of (at the moment anyway). A less secure but somewhat better solution would be to only allow people to reload info from partially-completed forms (not those that have been finished and submitted).

              Quote from: identity at Nov 29, 2006, 09:56 AM
              They should consider whether their ability to view a partial form and contact the person about it might be a turn-off to the person being contacted too.

              Also true. These clients should consider a lot of things, in my opinion, but you know how some people just want what they want and they don’t want to hear any "excuses" for not giving it to them...

              However people who fill out the form will be actively saving their partial info, and we will tell them that we might contact them with questions, so it probably won’t be a major issue in this case.
                "Things are not what they appear to be; nor are they otherwise." - Buddha

                "Well, gee, Buddha - that wasn't very helpful..." - ZAP

                Useful MODx links: documentation | wiki | forum guidelines | bugs & requests | info you should include with your post | commercial support options
                • 33372
                • 1,611 Posts
                Hmm... OK well that’s gotten me closer to my goal, but I still don’t quite have the flow working properly. It’s pretty close though, so maybe I can tweak it from here.

                I can update the database using a function triggered by the eformOnValidate event, so that’s a big step forward. I can actually change the validation message in that function as well. However at that point I don’t seem to be able to stop the form from attempting to send (if they just saved their info, even if it’s all there and validates, I don’t want to send it). And probably for the same reason I can’t stop eForm from displaying validation errors when saving incomplete forms.

                Perhaps I’m not using the eFormOnBeforeMailSent event properly? I can only get it to run my function if all fields validate, so it seems to be triggered too late for my purposes. And returning false does stop eForm from sending the email when the form is complete (so I guess I would need to return true when I do want to send), but it also halts display of the form. So that means that after saving the form you can no longer see it and continue, which of course won’t work.

                //function to store submitted data in the database
                //runs on eformOnValidate event
                function updateDatabase( &$fields ){
                   global $modx;
                   if ($fields['save']=='save'){
                      foreach($fields as $key=>$value){
                         if($key!='formid' && $key!='send' && $key!='save'){
                            // database query in here
                            // for now just displaying values
                            echo '<p>'.$key.' - '.$value.'</p>';
                         }
                      }
                      $fields['validationmessage']='Your information has been saved.';
                   }
                   return true;
                }
                
                //further processing for unfinished applications (don't try to send!)
                //runs on eFormOnBeforeMailSent event
                function checkAction( &$fields ){
                   global $modx;
                   echo 'this doesn\'t execute unless the whole form has been filled out correctly';
                   return false;
                }


                Could I just set a required field to blank in my eformOnValidate function and that way stop it from trying to send the form? And how can I affect (turn off) the display of validation errors? I’m going to go through the eForm code now and see what gets called where, but I wouldn’t turn down suggestions on where to start.

                Thanks!
                  "Things are not what they appear to be; nor are they otherwise." - Buddha

                  "Well, gee, Buddha - that wasn&#39;t very helpful..." - ZAP

                  Useful MODx links: documentation | wiki | forum guidelines | bugs & requests | info you should include with your post | commercial support options
                  • 33372
                  • 1,611 Posts
                  I figured out how to affect the validation error messages by referencing their arrays in my first function:

                  //function to store submitted data in the database
                  //runs on eformOnValidate event
                  function updateDatabase( &$fields, &$vMsg, &$rMsg ){
                     global $modx;
                     global $_lang;
                     $fields['save']='save';  // will be set with JavaScript in form
                     if ($fields['save']=='save'){
                        foreach($fields as $key=>$value){
                           if($key!='formid' && $key!='send' && $key!='save' && $key!='validationmessage'){
                              // database query in here
                              // for now just displaying values
                              echo '<p>'.$key.' - '.$value.'</p>';
                           }
                        $fields['validationmessage']='<h3>Your information has been saved.</h3>';
                        $vMsg=array(' ');
                        $rMsg=array();
                        $_lang["ef_validation_message"]='';
                        }
                     }
                     return true;
                  }


                  And setting the validation message to a single space seems to keep the form from trying to send (since it’s not null) but without a visible error message. And lastly I set the language variable that usually says that there were errors in the form to an empty string so that it wouldn’t be visible either.

                  So assuming I set the value of the ’save’ field using JavaScript when a user clicks the Save button, I think I may now have all the functionality I need to make this work...
                    "Things are not what they appear to be; nor are they otherwise." - Buddha

                    "Well, gee, Buddha - that wasn&#39;t very helpful..." - ZAP

                    Useful MODx links: documentation | wiki | forum guidelines | bugs & requests | info you should include with your post | commercial support options
                    • 33372
                    • 1,611 Posts
                    OK. I’m VERY CLOSE to being able to do what I need to do now. Only one detail seems to be eluding me...

                    I am now able to save unfinished forms to a database table (as well as completed ones). I am using a combination of eForm events to get and save info to a table (code below). However for some reason I haven’t been able to pre-populate the form when people return to finish their application.

                    What I’m trying to do (because it was the only way that seemed to work) is to use a separate form with only an email field to start off the process. All this form needs to do is to pass the email address to the second form in a session variable (plus a flag that lets the second form know to pre-populate itself). This seems to be working fine (the session vars are set by the first form, and the second form receives and processes the info as expected), but I can’t seem to fill in the form fields with the info that was saved previously.

                    I would think this would be just a matter of setting the $fields to the value in the database, but it’s just not working for me.

                    Here is my code:

                    /* functions called by first form */
                    // pass entered info to next form
                    // runs on eFormOnBeforeMailSent event
                    
                    function passInfo( &$fields ){
                    
                       global $modx;
                    
                       $_SESSION['start']='start';
                       $_SESSION['startemail']=$fields['email'];
                    
                       $appdocid=434; //id of application page
                       $apppage= $modx->makeUrl($appdocid);
                       return $modx->sendRedirect($apppage);
                    
                    }
                    


                    /* functions called by second form */
                    // get saved info from database
                    // runs on eFormOnBeforeFormMerge event
                    
                    function populateData( &$fields ){
                       global $modx;
                       if ($_SESSION['start']=='start'){
                          $fields['email'] = strtolower($_SESSION['startemail']);
                          $query = "SELECT * FROM modx_applications WHERE email='".$fields['email']."' and status='unfinished'";
                          $result = $modx->dbQuery($query);
                          if(mysql_num_rows($result)!=1){ // Starting a new application - inserts the data, but doesn't populate the email field in the form
                             $query = "INSERT INTO modx_applications SET email='".$fields['email']."', status='unfinished', started=NOW(), modified=NOW()";
                             $result = $modx->dbQuery($query);
                             $fields['appid'] = mysql_insert_id();
                          }
                          else{ // Continuing a saved application
                             $appInfo=mysql_fetch_array($result, MYSQL_ASSOC);
                             foreach($appInfo as $key=>$value){
                                if($key!='status' && $key!='started' && $key!='modified'){
                                   $fields[$key] = $appInfo[$key];
                                   //echo '<p>'.$key.' - '.$value.'</p>';  // I can tell by echoing this data that the database info is being recalled correctly
                                }
                             }
                          }
                       $_SESSION['start']='';
                       }
                       return true;
                    }
                    
                    // function to store submitted data in the database
                    // runs on eformOnValidate event
                    
                    function updateDatabase( &$fields, &$vMsg, &$rMsg ){
                       global $modx;
                       global $_lang;
                       $fields['email'] = strtolower($fields['email']);
                       //$fields['save']='save';  // will be set with JavaScript in form
                       //if($fields['appid']=='') $fields['appid']=$_SESSION['appid'];
                       if ($fields['save']=='save'){
                          if ( !preg_match('/^(?:[a-z0-9_-]+?\.)*?[a-z0-9_-]+?@(?:[a-z0-9_-]+?\.)*?[a-z0-9_-]+?\.[a-z0-9]{2,5}$/i', $fields['email']) ) {
                          $fields['validationmessage']='You must enter a valid email address in order to save your unfinished application. You will need it to retrieve your information later.';
                          $vMsg=array(' ');
                          $rMsg=array();
                          $_lang["ef_validation_message"]='';
                          }
                          else{
                          $query = 'UPDATE modx_applications SET ';
                             foreach($fields as $key=>$value){
                                if($key!='formid' && $key!='appid' && $key!='send' && $key!='save' && $key!='savebutton' && $key!='validationmessage'){
                                   $query .= $key.'=\''.$value.'\', ';
                                   // echo '<p>'.$key.' - '.$value.'</p>';
                                }
                             }
                          $query .= 'status=\'unfinished\', ';
                          $query .= ' modified=NOW()';
                          $query .= ' WHERE appid=\''.$fields['appid'].'\'';
                          $result = $modx->dbQuery($query);
                          $fields['validationmessage']='<h3>Your information has been saved.</h3>';
                          $vMsg=array(' ');
                          $rMsg=array();
                          $_lang["ef_validation_message"]='';
                          }
                       }
                       return true;
                    }
                    
                    // saves final info into database
                    // runs on eFormOnMailSent event
                    
                    function finalizeDatabase( &$fields ){
                       global $modx;
                       $query = 'UPDATE modx_applications SET ';
                          foreach($fields as $key=>$value){
                             if($key!='formid' && $key!='appid' && $key!='send' && $key!='save' && $key!='savebutton' && $key!='validationmessage' && $key!='postdate' && $key!='disclaimer' && $key!='subject'){
                                $query .= $key.'=\''.$value.'\', ';
                                // echo '<p>'.$key.' - '.$value.'</p>';
                             }
                          }
                       $query .= 'status=\'complete\', ';
                       $query .= ' modified=NOW()';
                       $query .= ' WHERE appid=\''.$fields['appid'].'\'';
                       $result = $modx->dbQuery($query);
                       return true;
                    }
                    


                    What am I missing here? I could set placeholders for most form fields, but that wouldn’t work for checkboxes and such. Plus I know that there must be some minor detail that would fix everything...

                    Anyone able to help me out?
                      "Things are not what they appear to be; nor are they otherwise." - Buddha

                      "Well, gee, Buddha - that wasn&#39;t very helpful..." - ZAP

                      Useful MODx links: documentation | wiki | forum guidelines | bugs & requests | info you should include with your post | commercial support options
                      • 28042 ☆ A M B ☆
                      • 24,524 Posts
                      I was thinking that the $fields array needs to be populated, but eForm has to be faked into believing that it’s reloading the form after a failed validation, only without the error messages.
                        Studying MODX in the desert - http://sottwell.com
                        Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
                        Join the Slack Community - http://modx.org