Frontend form assistance

Hi All,

I am having some trouble using OJS Frontend Forms. I started by following the instructions as shown on this page: https://docs.pkp.sfu.ca/dev/documentation/en/frontend-forms
I wasn’t able to get that to work, partly due to me being a noob, but there are some errors in the documentation that cause it not work work too. Instead of that I created a Bootstrap 5 form with local validation, which worked, but isn’t secure. I quickly came to realise that the validation on my form wasn’t going to be sufficient so I reverted to using OJS forms, but tried to use a different example instead.

The other example of form code was taken from here: lib/pkp/pages/user/RegistrationHandler.inc.php

There are significant differences between these two examples and I was wondering which would be the best to follow for a real-world frontend form with validation and captcha.

My plugin displays the form, which is not using $this-addField() but a .tpl file, the contents of which are:

<script>
    window.addEventListener("DOMContentLoaded", function(){
        {ldelim}
		jQuery('#clinicalQuerySubmitForm').pkpHandler('$.pkp.controllers.form.AjaxFormHandler');
	{rdelim}
    });
</script>
{include file="frontend/components/header.tpl" pageTitle="plugins.generic.RCVSKClinicalQueries.RCVSKClinicalQueries"}

 <div class="container pt-5 pb-5">
     <div class="row">
        <div class="col-12">{include file="frontend/components/breadcrumbs.tpl" currentTitleKey="plugins.generic.RCVSKClinicalQueries.RCVSKClinicalQueriesSubmit"}
            <h1 id="clinical-queries" class="h5 fs-3">
                {translate key="plugins.generic.RCVSKClinicalQueries.RCVSKClinicalQueriesSubmit"}
            </h1>
        </div>
        <div class="col-12">
             <section aria-labelledBy="clinical-queries">
                 <div class="page page_about">
                    <div class="pt-3 pb-3">
                     {$clinicalQueriesSubmitContent}
                     </div>
                 </div><!-- .page -->
             </section>
             <section aria-label="Submit Clinical Queries">
                <div class="container px-5 my-5">
                    <form class="pkp_form" id="clinicalQuerySubmitForm" method="post" action="{url op="submitQuery"}" novalidate>
                        {* Help Link *}
                        {help file="user-profile" class="pkp_help_tab btn btn-primary mb-2"}
                    
                        {csrf}
                        {include file="controllers/notification/inPlaceNotification.tpl" notificationId="contactFormNotification"}
                        {fbvFormSection class="mb-2" title="user.firstName" for="firstName"} *
                            {fbvElement type="text" class="form-control mt-1 mb-2" multilingual="true" name="firstName" id="firstName" value="" size=$fbvStyles.size.MEDIUM required=true}
                        {/fbvFormSection}
                        {fbvFormSection title="user.surname" for="surname"} *
                            {fbvElement type="text" class="form-control mt-1 mb-2" multilingual="true" name="surname" id="surname" value="" size=$fbvStyles.size.MEDIUM required=true}
                        {/fbvFormSection}
                        {fbvFormSection title="user.email" for="email"} *
                            {fbvElement type="email" class="form-control mt-1 mb-2" id="email" value="" size=$fbvStyles.size.MEDIUM required=true}
                        {/fbvFormSection}
                        ..
						..
						..
                    
                    <p><span class="formRequired">{translate key="common.requiredField"}</span></p>
                    {* recaptcha spam blocker *}
                    {if $reCaptchaHtml}
                        <fieldset class="recaptcha_wrapper">
                            <div class="fields">
                                <div class="recaptcha">
                                    {$reCaptchaHtml}
                                </div>
                            </div>
                        </fieldset>
                    {/if}
                    {fbvFormButtons class="btn btn-primary" hideCancel=true submitText="common.save"}
                    </form>
                </div>
                {block name="page"}
                    <pkp-form
                        v-bind="components.{$smarty.const.FORM_CLINICALQUERY}"
                        @set="set"
                    />
                {/block}
             </section>
         </div>
     </div>
</div>
{include file="frontend/components/footer.tpl"}

The problems I am having are twofold: the first is with the validation - I just can’t seem to get that to work properly. When I submit the form the application crashes with some fatal errors. I am pretty sure this is due to me messing up but I don’t think I’m far away from a solution but I’m struggling to make sense of the examples.

The first question I have is regarding the form action:

<form class="pkp_form" id="clinicalQuerySubmitForm" method="post" action="{url op="submitQuery"}" novalidate>

The {url op=“submitQuery”} action calls the submitQuery function in my plugin handler but that results in a fatal error too:

Fatal error: Uncaught Error: Class 'RCVSKClinicalQueriesSubmitForm' not found in C:\xampp\htdocs\ojs\plugins\generic\rcvskClinicalQueries\RCVSKClinicalQueriesPluginHandler.inc.php:84 Stack trace: #0 C:\xampp\htdocs\ojs\lib\pkp\classes\core\PKPRouter.inc.php(395): RCVSKClinicalQueriesPluginHandler->submitQuery(Array, Object(Request)) #1 C:\xampp\htdocs\ojs\lib\pkp\classes\core\PKPPageRouter.inc.php(255): PKPRouter->_authorizeInitializeAndCallRequest(Array, Object(Request), Array, false) #2 C:\xampp\htdocs\ojs\lib\pkp\classes\core\Dispatcher.inc.php(144): PKPPageRouter->route(Object(Request)) #3 C:\xampp\htdocs\ojs\lib\pkp\classes\core\PKPApplication.inc.php(362): Dispatcher->dispatch(Object(Request)) #4 C:\xampp\htdocs\ojs\index.php(68): PKPApplication->execute() #5 {main} thrown in C:\xampp\htdocs\ojs\plugins\generic\rcvskClinicalQueries\RCVSKClinicalQueriesPluginHandler.inc.php on line 84

The code for he submitQuery function is as follows:-

function submitQuery($args, $request)
  {
    $this->setupTemplate($request);
    $request = Application::get()->getRequest();
    $templateMgr = TemplateManager::getManager($request);
    $context = Application::get()->getRequest()->getContext();

    // The URL where the form will be submitted
    $apiUrl = $request
      ->getDispatcher()
      ->url(
        $request,
        ROUTE_API,
        $context->getPath(),
        'contexts/' . $context->getId()    // *IS this the correct path??*
      );

    // Get a key/map of the locale keys and names supported by this context.  (Note we have only one locale currently)
    $localeNames = $context->getSupportedFormLocaleNames();
    $locales = [];
    foreach ($localeNames as $key => $name) {
      $locales[] = [
        'key' => $key,
        'label' => $name,
      ];
    }
    // Create an instance of the query form
    import('plugins\generic\rcvskClinicalQueries\RCVSKClinicalQueriesSubmitForm');
    $queryForm = new RCVSKClinicalQueriesSubmitForm($apiUrl, $locales, $context); // CRASHES HERE
    $templateMgr->setState([
      'components' => [
        FORM_CLINICALQUERY => $queryForm->getConfig(),  // This function wasn't working either so I created a blank one
      ],
    ]);
    return new JSONMessage(true, $queryForm->fetch($request));
  }

Are there any fully-worked-through examples I can use to get this working? The documentation is what I would describe as a partial example, leaving much up to guesswork.

Or perhaps you can see an obvious issue with the code I am using and can suggest a solution?

I appreciate any help I can get here as I feel very close to a solution but am stumped at the last hurdle.

I am using OJS 3.3.0.10 on one server and 3.3.0.11 on the other.