Jump to content

populating repeater fields via API


pppws
 Share

Recommended Posts

hey there,

i'm quite new to processwire but i'm having a great experience using it!

right now i hit a point where i can't help myself out with google/searchfunction.

 

to sketch the basic functions of my page:

visitors can enter their e-mail in a form. when doing this pw creates a new page, using the e-mail's md5 hash as a name. the url of the page is sent to the user. the user now can edit the newly created page and can fill out fields like: name and year of birth (thanks to the docs those two already work like a charm!) but there are other fields like "residencies", which are repeaterfields containing three fields: city (text), country (text), current (checkbox). at my current version i can populate a new repeater field easily by using this code:

$location = $page->locations->getNew();
$location->location = Munich;
$location->country = Germany;
$location->current = 1;
$location->save();
$page->locations->add($location);

now i want to populate the new reapter fields from input fields (using the simple form api). which leads me to my questions:

 

1. can i somehow group/merge input fields to one "repeater input fields" right now i have:

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

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

// create a checkbox -> locations
$field = $this->modules->get('InputfieldCheckbox');
$field->attr('name', 'location_current');
$field->attr('autocheck', 1);
$field->attr('uncheckedValue', 0);
$field->attr('checkedValue', 1);
$field->attr('value', $this->fname);
$form->append($field); // append the field to the form

2. my desired layout for the form looks like this:

Screenshot%202017-09-01%2017.46.28.png?d

by hitting the + button a new line shows. i'm wondering what's the best practice here. can is somehow use the above mentioned code itself as a repeater, or do i have to create several (uniqe) input fields in advance and hide them afterwards (javascript)?

 

any help is appreciated!

thanks!

Link to comment
Share on other sites

  • 2 weeks later...

i finally found this wonderful post from @Soma, but somehow it behaves strange. the first time i'm adding items everything works fine. after a reload the freshly added repeaters are shown as expected. but when i add some new repeater rows i get duplicates of the old ones. everytime i reload the page and try to add/edit repeater items they get more. is there an update to somas code? 

Link to comment
Share on other sites

When reloading the page, you might be repeating the POST request. Refreshing the form page might create the same items over and over. You should get a popup warning you like this. After dismissing it once, you might not be warned again but still keep sending the request.

59b433a9c46b1_2017-09-0921_31_49-pw.dev_signup_.png.be3db71bc94ce473059a987e42991000.png

Also can you share your code, so that we can help you better?

Link to comment
Share on other sites

i'm reloading the page by hitting enter in the url bar again, not f5 – i think that should prevent a resubmitting of the form?

the code is basically the same as in somas example:

<?php
if($input->post->submit){
    $n = 1;
    $title = "profession_$n";
    $page->setOutputFormatting(false);
    while($input->post->$title){
        // on first round remove all repeater items, to keep things easy.
        // teasers is the repeater field
        if($n == 1) $page->professions->removeAll();

        // create new repeater item
        $item = $page->professions->getNewItem();

        // populate any fields in the repeater you want
        $item->profession = $input->post->$title;

        // save the repeater item (a page itself)
        $item->save();

        // add the repeater item to the page
        $page->professions->add($item);
        // update counter and field names
        $n++;
        $title = "profession_$n";
        echo $n . "done";
    }
    if($n > 1) {
        // save the page
        $page->save('teasers');
        echo "save";
    }
}
?>
<form name="test" method="post">

    <?php $count = 1; foreach($page->professions as $key => $t): ?>
    <input type="text" name="profession_<?php echo $key+1?>" value="<?php echo $t->profession?>"/>
    <?php $count++; endforeach; ?>

    <input type="text" name="profession_<?php echo $count; ?>" value=""/>
    <!--<input type="text" name="profession_<?php $count++; echo $count; ?>" value=""/>-->

    <input type="submit" name="submit" value="submit"/>
</form>
Link to comment
Share on other sites

Some points:
  • You can get inputs in an array if you name them as profession[] instead of profession_1, profession_2 ... etc. $input->post->profession will give you an array directly
    Using this method for the input field outside foreach() block (one with count + 1) will achieve what you want without using indices. 
    Also you can clone that field indefinitely to let user create as many jobs as he/she wants
  • Is there a reason why you're outputting professions on the frontend, only to replace with $page's on form submit? Thrashing and creating a lot of pages at once will probably slow the page down to a crawl.

I simplified the code a bit

<?php namespace ProcessWire;
/** @var $input WireInput */
/** @var $page Page */

if ($input->post->submit) {
    // check if there are any professions
    if ($input->post->professions && count($input->post->professions)) {
        $page->of(false);

        $newItems = [];
        foreach ($input->post->professions as $val) {
            // always sanitize user input
            /** @var $sanitizer Sanitizer */
            $val = $sanitizer->entities1($val);
            $val = $sanitizer->text($val);
            if (!$val) continue;

            $item = $page->professions->getNewItem();
            $item->profession = $val;
            $item->save();
            $newItems[] = $item;
        }

        if (count($newItems)) {
            $page->professions->removeAll($newItems);
            $page->professions->add($newItems);
            $page->save('professions');
        }
    }
}
?>
<form method="post">
    <?php foreach ($page->professions as $i => $prof): ?>
        <input type="text" name="professions[]" value="<?= $prof->profession ?>"/>
    <?php endforeach; ?>

    <!-- I guess for a new profession? -->
    <input type="text" name="professions[]" value=""/>

    <input type="submit" name="submit" value="submit"/>
</form>

Frankly, I can't say I fully understand what this form really does, so it'd be better if you explain your requirements a bit more

  • Like 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
 Share

×
×
  • Create New...