Jump to content

FrontendForms - A module for creating and validating forms on the frontend


Juergen

Recommended Posts

On 6/27/2024 at 8:37 PM, dotnetic said:

Another thing: I made my own TailwindCSS adapter which was very easy, with the json files for the other frameworks as a base.

@dotnetic it would be great if you post the json file here, so I maybe include it in the next update ?

Link to comment
Share on other sites

Sure, I can do that, but it's very rudimentary and not optimized for all purposes (for example I did not use CAPTCHAS or other stuff).

It also depends on classes like primary that I have defined in the colors option of my theme in the tailwind.config.js

const colors = require("tailwindcss/defaultTheme");
module.exports = {
theme: {
    colors: ({ colors }) => ({
      primary: "#E85E27",
      secondary: "#89508e",
      black: "#000",
      white: "#ffffff",
      accent: "#c64511",
      transparent: "transparent",
      neutral: "#ffffff",
      info: "#ffffff",
      success: "#10b981",
      warning: "#f37f1e",
      error: "#e11d48",
      current: "currentColor",
      gray: colors.gray,
      slate: colors.slate,
      darkgray: "#1F2227",
    })
};

Please also note that you want to add the path to the file to the content section in your tailwind.config.js so the parser sees which classes to compile:

 content: [
    './dist/site/templates/*.{php,latte}',
    './dist/site/modules/FrontendForms/CSSClasses/*.json',
    './dist/site/templates/RockForms/Renderer/*.php',
    './dist/site/templates/RockForms/*.{php,latte}',
    './dist/site/templates/partials/**/*.latte',
    './dist/site/templates/RockPageBuilder/blocks/**/*.{php,latte}',
    './src/js/*.js',
  ],

I also wanted to add that it might be better to store these styling files under site/templates/FrontendForms/, as I think they would be customized for every project.

Right now, when I do a module update they would be overwritten.

 

tailwindcss.json

  • Like 2
Link to comment
Share on other sites

10 hours ago, dotnetic said:

I also wanted to add that it might be better to store these styling files under site/templates/FrontendForms/, as I think they would be customized for every project.

This is  a good idea for an addition, but you have to keep in mind that it would probably not work for all frameworks. The problem is that not every framework has the same markup structure for inputfields. As an example would be the difference between UIKit and Boostrap: There are slightly differences in the markup, especially on checkboxes. Only changing the classnames does not work in this case. The markup rendered has to be changed too.

That is the reason, why I have written the code to be able to use different render functions depending on the framework set.

10 hours ago, dotnetic said:

Right now, when I do a module update they would be overwritten.

That is right, but do you know that you are able to change the classnames directly inside the module configuration, so the classnames will be stored inside the database? In this case the classnames will not be overwritten during an update. The main disadvantage is that you cannot use it on another installation.

You will find it under "Markup and styling/Settings for markup and styling/Own CSS classes

172005589_Screenshot2024-07-05at07-14-23ModuleFrontendFormswebseite7_at.thumb.png.8f94cf7f0782db3b9f6866f395fb66e2.png

Best regards

  • Like 2
Link to comment
Share on other sites

Hi @Juergen !

I have a question about using the form to create new pages. It has worked nicely, but I am facing some issues with images upload. I haven't tried yet for page reference but that is also on the table...

Here is what I've got so far, as soon as I have tried to upload images I am getting errors; is there a better way?
I do have and images field in my template; and a page reference (using ASM multi select option) where I'd like to add the checked items.
 

 <?php
    $content =  '';

    $form = new \FrontendForms\Form('myform');
    
    // some more inputs ......
    
    $file = new \FrontendForms\InputFile('fileupload');
    $file->showClearLink(true); // show an link to empty the input field under the input field
    $file->setLabel($page->p_title);
    $file->setDescription('<span>'.$page->p_upload_label.'</span>')->setPosition('beforeLabel');
    //    $file->setNotes('Description fileupload notes');
    $file->setRule('allowedFileSize', '60000');
    $file->setRule('allowedFileExt', ['jpg','png']);
    $file->setRule('uniqueFilenameInDir', true);
    $form->add($file);


    $items = new \FrontendForms\InputCheckboxMultiple('items');
    $items->setLabel('<p>'.$page->p_select_stickers.'</p>');
    foreach($pages->get("template=items")->children() as $item){
        $option = $items->addOption($item->number, $item->id);
    }
    $form->add($items);

    $form->setSuccessMsg('<div class="success"><h2>'. $pages->success_message .'</h2></div>');

    if ($form->isValid()) {

        // save the content as page
        $p = new Page();
        $p->template = $form->getValue('newPage');
        $p->parent = wire('pages')->get('template=parent');
        $p->title = $form->getValue('title'); 
        $p->save();

        $upload_path = $config->paths->assets . "files/{$p->id}/";
        $upload_url = $config->urls->assets . "files/{$p->id}/";

        if(count($form->getValue('fileupload'))) {
            foreach($form->getValue('fileupload') as $fileItem) {
                $sFile = $sanitizer->pageName($fileItem, true);
                $pathname = $upload_path . $sFile;

                // Move the uploaded file to the correct directory
                if (wire()->files->move($fileItem, $pathname)) {
                    $p->images->add($pathname);
                    $p->save();
                } else {
                    // Handle the error if the file could not be moved
                    $form->addError('fileupload', 'The file could not be uploaded.');
                }
            }
        }
    }

    $content .= $form->render();

    echo $content;


    ?>

Thanks a lot !

Link to comment
Share on other sites

Hello @marie.mdna

Here is the code that should make what you want:

      $form = new \FrontendForms\Form('myform');
        $form->setSuccessMsg('<div class="success"><h2>Everything is fine</h2></div>');

        // some more inputs ......

        $file = new \FrontendForms\InputFile('fileupload');
        $file->showClearLink(true); // show an link to empty the input field under the input field
        $file->setLabel($page->p_title);
        $file->setDescription('<span>'.$page->p_upload_label.'</span>')->setPosition('beforeLabel');
        //    $file->setNotes('Description fileupload notes');
        $file->setRule('allowedFileSize', '60KB'); // you can use the unit, if you want
        $file->setRule('allowedFileExt', ['jpg','png']);
        $file->setRule('uniqueFilenameInDir', true);
        $file->setSanitizer('pageName'); // set sanitizer
        $form->add($file);


        $button = new \FrontendForms\Button('submit');
        $button->setAttribute('value', 'Send');
        $form->add($button);


        if ($form->isValid()) {

            // save the content as page
            $p = new Page();
            $p->template = $form->getValue('newPage');
            $p->parent = wire('pages')->get('template=parent');
            $p->title = $form->getValue('title');
            if($p->save()){
        
                $destPath = wire('config')->paths->assets.'files/'.$p->id; // the path to the destination directory

                foreach($form->getUploadedFiles() as $file){
                    wire('files')->copy($file, $destPath);// copy the file to the new folder
                    wire('files')->unlink($file);// remove the file from the old folder
                }
            }
        }

        echo $form->render();

 

A little bit information about the code:

  • First of all, add the sanitizer "pageName" to the file input field instead inside the foreach loop
  • You can set the max filesize now using units (so instead of writing allowedFileSize('60000'), you can write allowedFileSize(60KB) which is more handy I think. This is relatively new and I have added it a few versions before - but it is not wrong if you enter the value in Bytes ?.
  • To get all uploaded files use the getUploadedFiles() method, which outputs only the file paths of the currently uploaded files. You can use the file paths for the next steps to move the files to another directory
  • The copy and unlink methods are PW methods and they are the best way to move files to another directory.

Hope this helps!

  • Thanks 2
Link to comment
Share on other sites

hi @Juergen!

Thank you for you very fast answer, always!

I was about to edit my comment as I got some progress, but yours feels a lot more coherent; I will add my previous solution below in case it helps someone to get to your answer ? 

$upload_path = $config->paths->assets.'files/'.$page->id."/";

foreach($form->getValue('fileupload') as $filename) {
    $pathname = $upload_path . $filename;
    $p->of(false);
    $p->images->add($pathname); 
    $p->save();
    unlink($pathname);
}

Thanks again!

  • Like 2
Link to comment
Share on other sites

It would be awesome if there were a way to indicate whether a form input should be displayed, right within FrontEndForms, when we define our fields. I know this was asked on page 11 of this post/thread. Something like…

$privacy = new \FrontendForms\InputCheckbox('privacy');
$privacy->setLabel('I accept the privacy policy');
$privacy->setRule('required')->setCustomMessage('You have to accept our privacy policy');
$form->add($privacy);

$customNote = new \FrontendForms\Textarea('message');
$customNote->setLabel('Custom Note');
$customNote->setRule('displayIf')->$privacy(true);
$customNote->setRule('required');
$form->add($customNote);

I’m not a programmer but 'displayIf' was meant to check if a form field (in this case the privacy checkbox) was selected. But the same should be true if a radio button was selected or a choice in a dropdown or a value entered into a standard text/message input field.

And of course, the required rule of customNote in the example would only fire off if that field was displayed on the page. Otherwise, that field is hidden.

Link to comment
Share on other sites

Version 2.2.5 is out!

It includes 2 bug fixes and 1 new feature: Inputfield dependencies!

Most of you will know Inputfield dependencies from the ProcessWire backend. This is the same feature for FrontendForms, but it relies on a different code than the one used in the backend. I have found an interesting script on Github written by Ali Khallad and I have implemented it into FrontendForms.

If you are interested in: Here is the the code on Github.

Short description of Inputfield dependencies:

Let's say you have two fields in your form: a number input field (field 1) and a text input field (field 2).

Field 2 should only be visible if the value "1" is selected inside field 1. Otherwise, field 2 should be hidden.

The input field dependencies allow you to add the condition directly to field 2 without having to write a line of JavaScript.

$field2->showIf([
        'name' => 'field1', 
        'operator' => 'is',
        'value' => '1'
    ]);

Here is an example in action:

mf-conditional-rules.gif.7c4b2484ec65115e58f2cde9749fe609.gif

I have written a very detailed documentation and added a lot of examples. You will find all about the new feature here.

As always: This is a brandnew feature, so keep an eye if everything works as expected. Report issues or suggestions here or directly on Github. Before using it on live sites make a backup.?

Jürgen

 

  • Like 2
  • Thanks 2
Link to comment
Share on other sites

@HMCB I guess the new feature is exactly what you are looking for ?

Every rule that has been added to an inputfield is only active if the field is visible. If the field is hidden every rule added to this field is disabled.

For example: You have an input field that is hidden by default and you have added the required rule. As long as the field is hidden, the required rule is inactive.

If the field is visible, than the required rule will be checked during the form validation.

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Hi @Juergen, sorry to bother again ! I am facing another question, I am managing profile pages for users (in combination with your module FrontendLoginRegister) using url segments. So far no form has been submitted successfully form those pages. Is there a reason, or a way to work around it ? Thanks a lot !

Link to comment
Share on other sites

Hello @marie.mdna

Just to clearify: It happens not on pages created by the FrontendLoginRegister module, but it happens on pages that you have created for the user profile. The template of this pages allows url segments and a form which is on such a page cannot get submitted.

In other words if a form is on a page which contains an url segment, than the form cannot be submitted successfully. What means  "not successfully" exactly in this case? Does the form output error messages, or is there a PHP error. Please specify the problem a little bit more precious.

Thanks

Link to comment
Share on other sites

Hi @Juergen

To go more on details, I use the profile page created by the module (template fl_profilepage (so it shows as "/profilePage/username1")), just added the url segment option to show more content related to specific users. There is no error message/alert or PHP error, but a javascript related error "frontendforms.js?v=2.2.2:350 Uncaught TypeError: Cannot read properties of null (reading 'innerHTML') at xhr.onload (frontendforms.js?v=2.2.2:350:39)".

For my specific case I believe that I can manage without the url segment for the loggedin user's profile, and keep url segments in a different template to show different users' content. I mostly wondered if there was a specific reason since it is actually my first attempt with url segments but your answer already clears the air ?

Also, thanks again for the modules, I am relearning how to build forms with them and I have been enjoying this transition !

Link to comment
Share on other sites

Hello @marie.mdna

It seems that there is an Ajax problem in the JS file. As far as I can see, you have an older version installed (2.2.2). Please update FrontendForms and FrontendLoginRegister to the latest version, but I recommend you to make a backup first (just for the case) and try it again. I can remember that I have also updated the JS file since 2.2.2.

Please give me a short info, if the problem persists after the update.

Glad to hear that you like it ?!

Link to comment
Share on other sites

Hello @marie.mdna

You are right, it does not work inside url segments. The failure is inside the form action attribute and/or the redirects which does not recognize the segments after the url, so every redirect leads to the base url instead of the base url including the segments. I try to fix this now!

  • Like 2
Link to comment
Share on other sites

Hello @marie.mdna

I hope I have fixed the problem now ?.

For testing purposes I have added the profile form inside segment 2 so it was reachable under      /profile/segment1/segment2. After form submission it redirects successfully to the same url (on success and error) - so everthing works fine.

I have tested it on a single and a multi-language site and with/without Ajax. On my local installation it works as expected. So please update FrontendForms to 2.2.8 and FrontendLoginRegister to 1.3.4 and let me know if it works for you now.

Best regards

  • Like 3
Link to comment
Share on other sites

Hello @Juergen since the update to the newest version I get extra br elements in a vertical radio button list. That looks ugly, is there any way I can prevent them?

Thank you for all the other additions. I think I will need field dependencies in the future.

image.thumb.png.c64e2b6251ecca1aac9c269ea317a3a1.png

  • Thanks 1
Link to comment
Share on other sites

Hi @Juergen, another request from me. Would it be possible that the json file for different frameworks is located in site/templates/FrontendForms/frameworks instead of site/assets/files/FrontendForms/frameworks? The problem I have is that I excluded the assets/files/ directory in my gitignore file. So my tailwindcss.json file which lies there isn't processed by the compiler, as it is not part of the repository. So the styles for my forms are missing.

What you think of that idea?

  • Like 1
Link to comment
Share on other sites

Hello @dotnetic

It is possible to store the file everywhere as long as the permission for this directory allows it. I can add the possibility to choose a custom directory, lets say a text input where you can add the path to your prefered directory. As the default directory path 'site/assets/files/FrontendForms/frameworks' will be set and you can overwrite it with your path.

I'll inform you, if the update is ready ?

Link to comment
Share on other sites

Version 2.2.11 contains a new feature: Use FrontendForms inside CKEditor fields

This new feature allows you to load forms inside CKEditor fields via the usage of placeholders. It supports the loading of the same form multiple times in one or more fields.

Short description: Use placeholders like {{myform}} inside your CKEditor field. The placeholders will be replaced with forms during the page render process on the frontend.

newFFversion.jpg.e7638aaf16d57c504decf0af42c816f1.jpg

A more detailed description about how it works and containing a code example can be found inside the docs. This is a brandnew addition, so test it carefully before using it on live sites.

Jürgen

 

 

 

  • Thanks 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...