Jump to content
Soma

Create simple forms using API

Recommended Posts

Don't Show API Form Labels 

(If I may add this here for the sake of completeness.)

I have been looking for a way to leave the label out of the markup that does not involve recreating a module (a silly thing to do). The solution we have been using up until this point was a blank label. (Resulting in unnecessary markup and a negative margin.) However curiosity took me to the Inputfield module. Hey great job on these fields BTW. Reading the file I came across these options.

const skipLabelNo = false; // don't skip the label at all (default)
const skipLabelFor = true; // don't use a 'for' attribute with the <label>
const skipLabelHeader = 2; // don't use a ui-widget-header label at all
const skipLabelBlank = 4; // skip the label only when blank

// wire/core/Inputfield.php

Found in: in Inputfield.php 

The best solution I found to use this in a form builder. (I would like to credit this to somma's comment on checkbox-other-text-in-header-than-label-text)

//controller.php
$submit = $modules->get("InputfieldSubmit");
$submit->skipLabel = Inputfield::skipLabelBlank; //HERE IS THE SOLUTION!
$submit->attr("value","SUBMIT");
$submit->attr("id+name","submit");
$submit->attr("class","button");
$form->append($form_submit);

Thank you Somma!

Thank you Ryan!

  • Like 10

Share this post


Link to post
Share on other sites

Nice first post - very useful to know as I've scratched my head over this before, thanks! :)

Share this post


Link to post
Share on other sites

Who says ProcessWire isn't well documented?  ;)

Share this post


Link to post
Share on other sites

HowTo: InputfieldWrapper classes (Question)

Adding classes to the wrapper via a hook.

So here I am again. Wrestling with the API form. Love it and know I don't know enough to say anything bad about it. I am certain that there is a way to do most things you want when using the Processwire API. 

Short Description

What I am trying to achieve is have all the Inputfields in my form render with unique classes. Why I am trying to do this is I am using a CSS-Framework that has an insanely intuitive grid system and would like to use these classes in the form. So when at render I will output the classes specific to that field. Hooking is one way I have thought of that might be plausible but, as mentioned I don't know how best to do it due to my limited knowledge of ProcessWire. I am open to other suggestions too.

Method

Create a form as in the feed done like Soma has suggested. Add to the form a markup and class array. Now add the fields you desire. In short...

<?php /* contact_contoller.php */
// And a whole lot more code
function hookAppendClassName($event) {
  $otherEvent = $event->arguments(0); // grab event provided to PageRender::renderPage
  $className = " [classes for the grid]";
  $classes_array = $otherEvent->object->getParent()->getClasses();
  $classes_array = array_merge($classes_array, array('item' => $classes_array['item']." ".$className));
  $otherEvent->object->getParent()->setClasses($classes_array);
  $otherEvent->return = $event;
  $event->replace = true;
}
function createForm() {
  $form = $modules->get("InputfieldForm");
  $form->setMarkup(array(
    'list' => "<div {attrs}>{out}</div>",
    'item' => "<div {attrs}>{out}</div>",
    'item_label' => "<label for='{for}'>{out}</label>",
    'item_content' => "{out}",
    'item_error' => "<p>{out}</p>",
    'item_description' => "<p>{out}</p>",
    'item_head' => "<h2>{out}</h2>",
    'item_notes' => "<p class='notes'>{out}</p>",
  ));

  $form->setClasses(array(
    'list' => '[list-class]',
    'list_clearfix' => '',
    'item' => '{class}',
    'item_required' => '',
    'item_error' => '',
    'item_collapsed' => '',
    'item_column_width' => '',
    'item_column_width_first' => ''
  ));

  $form_name = $modules->get("InputfieldText");
  $form_name->addHookBefore('renderValue', $this, 'hookAppendClassName');
  $form_name->label = "Name";
  $form_name->setParent($form);
  $form_name->required = 1;
  $form_name->attr('id+name','name');
  $form_name->attr('placeholder','Name');
  $form_name->attr('class','');
  $form->append($form_name);
}

This code does not work. Was hoping someone could be of assistance. Here is my current output.

<html>
<form id="contact-form" class="InputfieldForm" name="contact-form" method="post" action="./" data-colspacing="1">
  <div class="[list-class]">
    <div class="InputfieldText" id="wrap_name">
      <label for="name">Name</label>
      <input id="name" class="InputfieldMaxWidth" name="name" type="text" maxlength="2048" placeholder="Name">
    </div>
  </div>
</form>
</html>

This is what i desire. Note the [list-class__item].

<form id="contact-form" class="InputfieldForm" name="contact-form" method="post" action="./" data-colspacing="1">
  <div class="[list-class]">
    <div class="InputfieldText [list-class__item]" id="wrap_name">
      <label for="name">Name</label>
      <input id="name" class="InputfieldMaxWidth" name="name" type="text" maxlength="2048" placeholder="Name">
    </div>
  </div>
</form>

Thanks in advance!

Share this post


Link to post
Share on other sites

Your hook and method has a lot wrong.

If this all would work, then you would hook into Inputfield::render() and not Inputfield::renderValue();

And a hook to do what you wanted would look more like this:

function hookAppendClassName($event) {
  $className = " mygrid";
  $classes_array = $event->object->getParent()->getClasses();
  $classes_array = array_merge($classes_array, array('item' => $classes_array['item']." ".$className));
  $event->object->getParent()->setClasses($classes_array);
}

But this is not possible. When a inputfield is rendered in the inputfieldwrapper, the classes and markup is already set and you can not overwrite it at that moment in time.

I also was looking into this and by chance I found a line of code in latest dev, that seems to be added recently. InputfieldWrapper rendering method looks for a $inputfield->wrapClass, I didn't know was there.

So you can now simply do this:

$field = $modules->InputfieldText;
$field->label = "Name";
$field->wrapClass = "mysuperlol-col1--wonder__toootooo";
...
  • Like 6

Share this post


Link to post
Share on other sites

Thanks Soma

Thanks Soma. That should work. Busy downloading Processwire from Github now. I see my mistakes now. I had it correctly but changed it to the wrong code and did not fully correct it when I uploaded the code. Sorry about that renderValue.

The only issue I have with this method is that it comes from the dev branch. Production should be kept separate from dev in my opinion.

Share this post


Link to post
Share on other sites

I'm trying to get a image upload working with the form api. 

	$field = $modules->get("InputfieldImage");
	$field->attr('id+name','images');
	$field->required = 0;
	$field->destinationPath = $config->uploadTmpDir;
	$field->extensions = "jpg jpeg gif png";
	$field->maxFilesize = 2*1024*1024;
	$field->maxFiles = 1;
	$field->skipLabel = Inputfield::skipLabelBlank;
	$form->append($field);

But if I call 

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

I get this error: 

Error: Exception: Nicht zulässiges Bild (in /Users/Benni/Projekte/A-06-2014_HONourables/www2/wire/modules/Inputfield/InputfieldFile/InputfieldFile.module line 282)

or with InputfieldFile

Error: Exception: New page '/mitglieder/postfach/conversation-2014-09-06-10-59/' must be saved before files can be accessed from it (in /Users/Benni/Projekte/A-06-2014_HONourables/www2/wire/core/PagefilesManager.php line 240)

I don't understand why this is trying to create a page in this location, which is the location of the page, which shows the form. The file is supposed to be for a page further down the hierarchy. Also the only template allowed as child of "postfach" doesn't even have a image field which could serve as temporary storage. 

I could use own upload processing, but I would much rather stay consistent with the form api.

  • Like 1

Share this post


Link to post
Share on other sites

@lostkobrakai, you many read this thread again as this has come up multiple times (not only in this thread) from around here https://processwire.com/talk/topic/2089-create-simple-forms-using-api/page-5 or just scan the whole thread as it's full of this. There's also some gist examples https://gist.github.com/somatonic/5236008

Share this post


Link to post
Share on other sites

@Soma
Thanks for your example, but the errors I posted above are happening while "$form->processInput()". I've read the thread and your previous examples, but I can't see what I'm doing different. 

Share this post


Link to post
Share on other sites

I have no idea to be honest. Works fine here. But I'm not using InputfieldImage but InputfieldFile.

  • Like 1

Share this post


Link to post
Share on other sites

I try to generate a form from a (multidimensional) array and searching for the best data format... any suggestions?

It have to map 

1) form / field values

$form->method = 'post';
$form->set('method', 'post'); // should work to?

2) form / field attributes

$form->attr('id+name', 'myForm');

3) defined Inputfield type like

InputfieldText
InputfieldSubmit
...

First array format is something like this...

$formField = array('module' => 'InputfieldText', 
                   'attr' => array('key' => 'value'),
                   'set' => array('key' => 'value'));

So I can cutting attributes, ...

But it looks... confusing *g*

*UPDATE*

But could be parsed with a function like that (untested)...

    protected function createFormFields() {
        foreach ($this->option['formFields'] as $formField) {
            $field = $this->modules->get($formField['module']);            
            
            foreach ($formField['set'] as $key => $values) {
                $field->set($key, $value);
            }
            foreach ($formField['attr'] as $key => $values) {
                $field->attr($key, $value);
            }
            $inputfields[$field->name] = $field;
        }
        return $inputfields;
    }

$this->option['formFields'] is a multidimensional array with the form data / config...

Share this post


Link to post
Share on other sites

The problem ist to find a "simple" data structur as configuration to my form helper.
But also should be parsed without much overhead...

Share this post


Link to post
Share on other sites

The problem ist to find a "simple" data structur as configuration to my form helper.

But also should be parsed without much overhead...

any associative array as:

  • json
  • serialized array
  • or still as php array

??

Share this post


Link to post
Share on other sites

tried to remove all classes from Inputfield and set one single new class. Expected class="loggy" get class="loggy InputfieldMaxWidth". Why? Which method will remove all classes persistent?
 

	$form = $modules->get('ProcessLogin');
	$form->addHookAfter('buildLoginForm',null, function ($event) {
		$new = $event->return;
		$new->get('login_pass')->removeAttr('class'); // removes: class="whatever"
		$new->get('login_pass')->setAttribute('class','loggy');// adds: class="loggy InputfieldMaxWidth" and not class="loggy"
		$event->return = $new;
	});
	echo $form->execute();

Share this post


Link to post
Share on other sites

You can't I guess. PW needs those helper classes. After all it's never intended to be used for front-end. So expect some compromises.

Share this post


Link to post
Share on other sites

How could I change individual field markup and class ?

The default html markup is not or to much for bootstrap.

For example, each input element is wrapped by a div, this html markup is too much and I want to get rid of it.

Share this post


Link to post
Share on other sites
$submit = $modules->get("InputfieldSubmit");
$submit->attr("value","Submit");
$submit->attr("name","submit");

how to get rid of the label of a submit button ?

Even though I don't provide the label attribute, it will use the name attribute as the label name

Share this post


Link to post
Share on other sites

I tried all the four const value on the code
$submit->skipLabel =   xxxxxxx ;

skipLabelHeader

skipLabelBlank

skipLabelFor

skipLabelNo

but not work

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...