Jump to content

Create simple forms using API


Soma

Recommended Posts

On 4/25/2018 at 8:22 PM, Ivan Gretsky said:

Thanks for the thread @Soma. One of the most important and cited ones in the whole forum history!

In the original post there are a few points that seem to be not discussed later in the thread, but which are extremely interesting to me.

1.

Are there any good examples of those to dig into? Gists maybe?

2.

Looking here it seems arrays are not allowed. I might be not understanding it right or things might change since when it was written. Is there actually a way to process input from a page or an array?

3.

There was already a question about what kind of validation processInput does and @adrian's answer too. I read the code a few times but still not sure should I sanitize values after processInput before saving to page fields or not. Is it necessary?

Thanks again! Learning ProcessWire is still fun (or am I doing it too slow?!)

1. There's a example in the code itself with email:

if($email && (strpos($email->value,'@hotmail') !== FALSE)){        // attach an error to the field
        // and it will get displayed along the field
        $email->error("Sorry we don't accept hotmail addresses for now.");

    }

Anything the API provides is possible. I can't go into details as there's too much and don't have any examples ready.

2. Of course an array is possible, input->post is also and array. You just have to make it a WireInputData array. https://github.com/processwire/processwire/blob/341342dc5b1c58012ae7cb26cffe2c57cd915552/wire/core/WireInputData.php

3. "Validation" is per Inputfield and it depends. Some inputfields do some sanitations to make sure an expected format or type of value is given (for example email https://github.com/processwire/processwire/blob/341342dc5b1c58012ae7cb26cffe2c57cd915552/wire/modules/Inputfield/InputfieldEmail.module) but most do nothing at all. You can look at all the Inputfields processInput() method to see what it does. Text and Textarea have some Inputfield settings to strip tags for example. It depends also on what the Form is used for and where you use the data afterwards. It's never an issue to save data to DB ie Pages, it's always about what and where you output the data (website, email, ...).

  • Like 2
Link to comment
Share on other sites

  • 11 months later...
On 7/9/2013 at 8:32 PM, Soma said:

You could even use the form building method in this thread starting post and render fields where you like. There'll be still markup being outputed depending on the inputfieldtype, but maybe allows for more flexibility.

 


$showform = true;

$form = $modules->get("InputfieldForm");

$field = $modules->get("InputfieldEmail");
$field->attr("name", "email");
$field->label = "Email";

$form->append($field);

if($input->post->submit) $form->processInput($input->post);

if($form->getErrors()) {
    $showform = true;
} else {
    $showform = false;
   // form valid, do something
}

if($showform) {
  echo "<form action='#' method='post'>";
  echo "<div class='row'>" . $form->get('email')->render() . "<div>";
  ...
}

Anything is possible, just use what you need. Think it's almost same as you would work with fields or pages. 

Hi Soma using form api with this method but form errors always shows after first submit. How to clear after reload page ?

 

<?php
$form = $modules->get("InputfieldForm");

// create a text input
$field = $modules->get("InputfieldText");
$field->label = "Name";
$field->attr('id+name', 'name');
$field->required = 1;
$form->append($field); // append the field to the form

// create email field
$field = $modules->get("InputfieldEmail");
$field->label = "E-Mail";
$field->attr('id+name', 'email');
$field->required = 1;
$form->append($field); // append the field

// oh a submit button!
$submit = $modules->get("InputfieldSubmit");
$submit->attr("value", "Subscribe");
$submit->attr("id+name", "submit");
$form->append($submit);


if ($input->post->submit) {
    $form->processInput($input->post);
}

echo "<form action='./' method='post'>";
echo "<div class='row'>" . session()->CSRF()->renderInput() . "</div>";
echo "<div class='row'>" . $form->get('name')->render() . "</div>";
echo "<div class='row'>" . $form->get('name')->getErrors()[0] . "</div>";
echo "<div class='row'>" . $form->get('email')->render() . "</div>";
echo "<div class='row'>" . $form->get('email')->getErrors()[0] . "</div>";
echo "<div class='row'>" . $form->get('submit')->render() . "</div>";
echo "</form>";

 

Link to comment
Share on other sites

  • 3 weeks later...

calling $inputfield->getErrors(true) after form render solves this. 

another question if InputfieldFile in InputfieldFieldset form not get " enctype="multipart/form-data" " attr, this is bug ?

$form = $modules->get("InputfieldForm");

$col1 = $modules->get("InputfieldFieldset");
$col1->importArray([
    [
        'type' => 'InputfieldFile',
        'name' => 'images',
        'label' => 'Images',
        'destinationPath' => $upload_path,
        'extensions' => 'jpg jpeg gif png',
        'maxFiles' => 3,
        'maxFilesize' => 2*1024*1024,
        'required' => 1
    ],  
]);

$form->add($col1);

 

Link to comment
Share on other sites

  • 1 year later...

On the frontend template I have this in an edit form:

    $field = $modules->get("InputfieldCheckbox");
    $field->label = "Discard";
    $field->attr('id+name', 'prop_discard');
    if($page->discard == 1) $field->attr("checked");
    $proform->append($field);

Because $field->value = $page->discard does not work, nor does anything else I've tried. How do I get the checkbox to reflect if it is checked? Right now on save if it was checked it needs to be re-checked every time.

Link to comment
Share on other sites

  • 3 weeks later...
On 5/23/2020 at 4:33 PM, hellomoto said:

On the frontend template I have this in an edit form:


    $field = $modules->get("InputfieldCheckbox");
    $field->label = "Discard";
    $field->attr('id+name', 'prop_discard');
    if($page->discard == 1) $field->attr("checked");
    $proform->append($field);

Because $field->value = $page->discard does not work, nor does anything else I've tried. How do I get the checkbox to reflect if it is checked? Right now on save if it was checked it needs to be re-checked every time.

A bit late but hey: If you only pass one argument to attr it will retrieve the value. So to set / tick a checkbox try $field->attr("checked", 1). Note that even attr("checked", 0) will set the checked attribute, so simply do nothing to leave it un-checked.

If discard is already an InputfieldCheckbox from your template, you can simply do 

$field = $page->getInputfield('discard');

and it will automatically come with the correct label, value and checked attr from the backend.

To also make this work in a "create new" form (when there is no $page yet) you can also get fields via $fields and a NullPage: 

$f = $fields->get('discard');
$p = $do_we_already_have_a_page ? $page : new NullPage();
$field = $f->getInputfield($p);

 

Link to comment
Share on other sites

For anyone like me who's slowly descending into madness wondering why their fields are ignoring the required validation: Make sure to set required=1 before setting the HTML5 required attribute. Otherwise the required flag will reset to 0. 

Correct order:

$field->required = 1;
$field->attr('required', true);

Using requiredAttr is more fool-safe, here the order does not matter (and it looks nicer):

$field->required(true);
$field->requiredAttr(true);

 

Link to comment
Share on other sites

  • 5 months later...
  • 1 year later...

How to you add a page reference dropdown to the  form? I´ve got this

 $county = $modules->get( 'InputfieldSelect' );
          $county->label = $this->_( $fields->county->$label );
          $county->attr( 'id+name', 'county' );
          
          $county->required = 1;    
          $county->fhSanitizer = 'text';
          $county->addHookAfter( 'processInput', function ( $event ) {
          $field = $event->object;
          $mySanitizedCustomInput = wire('fu')->form->fhValue( $field->name );
          wire('fu')->userObj->county = $mySanitizedCustomInput;
          });  

 

Link to comment
Share on other sites

10 hours ago, Flashmaster82 said:

How to you add a page reference dropdown to the  form? I´ve got this

 $county = $modules->get( 'InputfieldSelect' );
          $county->label = $this->_( $fields->county->$label );
          $county->attr( 'id+name', 'county' );
          
          $county->required = 1;    
          $county->fhSanitizer = 'text';
          $county->addHookAfter( 'processInput', function ( $event ) {
          $field = $event->object;
          $mySanitizedCustomInput = wire('fu')->form->fhValue( $field->name );
          wire('fu')->userObj->county = $mySanitizedCustomInput;
          });  

 

You would use $county->setOptions($optionsArray) to populate the select options.

Example:

    /** @var array $optionsArray */
    $optionsArray = $pages->findRaw('template=basic-page', 'title'); // returns an array with page ids as keys and page titles as value
    $county->setOptions($optionsArray);
    // each option will have value="{pageID}" and label page title

You need to adjust the selector to your needs.

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

$optionsArray = $pages->findRaw('template=location', 'title');
          $location->setOptions($optionsArray);
            
          $location = $modules->get( 'InputfieldText' );
          $location->label = $this->_( $fields->location->$label );
            
          $location->attr( 'id+name', 'location' );
          $location->required = 1;     
          $location->fhSanitizer = 'text';
          $location->addHookAfter( 'processInput', function ( $event ) {
          $field = $event->object;
          $mySanitizedCustomInput = wire('fu')->form->fhValue( $field->name );
          wire('fu')->userObj->location = $mySanitizedCustomInput;
          });

Thanks for the reply.. I´m a beginner with php so don´t know how to insert this.. 😞 Getting Fatal Error: Uncaught Error: Call to a member function setOptions()

Link to comment
Share on other sites

6 hours ago, Flashmaster82 said:

Thanks for the reply.. I´m a beginner with php so don´t know how to insert this.. 😞 Getting Fatal Error: Uncaught Error: Call to a member function setOptions()

Multiple problems with your code.

  • in the last code sample you used InputfieldSelect. Now you are using InputfieldText. The latter will give you a text input and has no method setOptions()
  • you set the options before you define $location 
  • $fields->location->$label needs to read $fields->location->label

Here is working sample code for a form with location select as only field:

// define form
/** @var InputfieldForm $form */
$form = $modules->get('InputfieldForm');
// define location first before you can use setOptions()
/** @var InputfieldSelect $location */
// you need to use InputfieldSelect here, InputfieldText has no setOptions() method
$location = $modules->get('InputfieldSelect'); 
$location->attr('id+name', 'location');
$location->label = $this->_($fields->location->label);
$location->required = 1;
$location->attr('required', 'required');
// build options array
$optionsArray = $pages->findRaw('template=location', 'title');
// set options to the select field
$location->setOptions($optionsArray);

// add field to your form
$form->add($location);
echo $form->render(); // will print out the markup for the whole form

I left out the whole fhSanitzer stuff and the hook. Let's go step by step and first make the inputfield work. You need to adjust this to the rest of your code. If you want to have a standalone field, not inside a form you would do something like this:

$location = $modules->get('InputfieldSelect'); 
$location->attr('id+name', 'location');
$location->label = $this->_($fields->location->label);
$location->required = 1;
$location->attr('required', 'required');
// build options array
$optionsArray = $pages->findRaw('template=location', 'title');
// set options to the select field
$location->setOptions($optionsArray);
// print markup
echo $location->render();

This will give you markup like:

<select id="location" class="required" name="location" required="required">
  <option value="">&nbsp;</option>
  <option value="1001">Location 1</option>
  <option value="1002">Location 2</option>
  <option value="1004">Location 3</option>
</select>

 

  • Thanks 1
Link to comment
Share on other sites

@gebeer Thanks for the detailed reply.. very appreciated. 🙂

This is my current code. The dropdown with all its option is now visible but when i submit the form the value is not selected. (County) is the option field.. any clues?

          <?php
          $fu = $modules->get( 'FrontendUser' );
          $redirectDestination = htmlentities( $_SERVER[ 'REQUEST_URI' ] );
            
          $firstname = $modules->get( 'InputfieldText' );
          $firstname->label = $this->_( $fields->firstname->$label );
          $firstname->attr( 'id+name', 'firstname' );
          $firstname->required = 0;
          $firstname->fhSanitizer = 'text';            
          $firstname->addHookAfter( 'processInput', function ( $event ) {
          $field = $event->object;
          $mySanitizedCustomInput = wire('fu')->form->fhValue( $field->name );
          wire('fu')->userObj->firstname = $mySanitizedCustomInput;
          });  
            
          $location = $modules->get( 'InputfieldText' );
          $location->label = $this->_( $fields->location->$label );
          $location->attr( 'id+name', 'location' );
          $location->required = 0;    
          $location->fhSanitizer = 'text';
          $location->addHookAfter( 'processInput', function ( $event ) {
          $field = $event->object;
          $mySanitizedCustomInput = wire('fu')->form->fhValue( $field->name );
          wire('fu')->userObj->location = $mySanitizedCustomInput;
          });
            
          
           /* Option field */
            
            $form = $modules->get('InputfieldForm');

            $county = $modules->get('InputfieldSelect'); 
            $county->attr('id+name', 'county');
            $county->label = $this->_($fields->county->label);
            $county->required = 1;
            $county->attr('required', 'required');
     
            $optionsArray = $pages->findRaw('template=county', 'title');
          
            $county->setOptions($optionsArray);
         
            $form->add($county);
            $form->render();        

            $county->fhSanitizer = 'text';
            $county->addHookAfter( 'processInput', function ( $event ) {
            $field = $event->object;
            $mySanitizedCustomInput = wire('fu')->form->fhValue( $field->name );
            wire('fu')->userObj->county = $mySanitizedCustomInput;
            });
   
            
          $fu->addHookBefore('save', function($event) {
          $form = wire('fu')->form;
          $user = wire('fu')->userObj;
          $user->addRole('member');
          $user->parent = "/medlemmar";    
          $user->template = "member-page";
          });

          $fu->register( array( 'username', 'email', 'password', $firstname, $county) );

          $redirectDestination = $pages->get( '/logga-in' )->url;
          $fu->process( $redirectDestination );
          echo $fu->render();

          ?>
    

 

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...