Jump to content

Select field values not getting edited in front-end form


onjegolders
 Share

Recommended Posts

Hi guys,

Am having an issue with a front-end form where page-fields via a select field are not getting updated.

Could someone check that my syntax is correct? I'm not really sure why they're not matching up.

The form part:

<label for="edit_terms">Terms</label>
<select name="edit_terms">
	<?php foreach ($pages->find("template=payment_term") as $term) { ?>
		<option value="<?php echo $term->id; ?>"<?php if ($term->id == $page->invoice_terms->id) {echo " selected";} ?>><?php echo $term->title; ?></option>
	<?php } ?>
</select>

<label for="edit_status">Status</label>
<select name="edit_status">
	<?php foreach ($pages->find("template=invoice_status") as $status) { ?>
		<option value="<?php echo $status->id; ?>"><?php echo $status->title; ?></option>
	<?php } ?>
</select>

The editing page via API part:

<?php  

$error = 0;
$out = "";

// Form was submitted
if ($input->post->estimate_edit_submit) {

	$page_name = $sanitizer->pageName($input->post->number);
	$p = $pages->find("template=estimate, name=$page_name")->remove($page);  
	if (count($p)) { 
		$error = 1;
		$out = "Sorry, that page name is already taken...";
	} 

	if ($error == 0) {

	$page->of(false);
	// $page->parent = $pages->get("/estimates");
	// $page->template = "estimate";
	$page->title = $sanitizer->name($input->post->number);
	$page->name = $sanitizer->pageName($input->post->number);
	$page->invoice_number = $sanitizer->name($input->post->number);
	$page->invoice_date = $sanitizer->text($input->post->date);
	$page->invoice_client = $sanitizer->text($input->post->client);
	$page->invoice_terms = $sanitizer->text($input->post->edit_terms);
	$page->invoice_status = $sanitizer->text($input->post->edit_status);
	
	$page->invoice_line->removeAll();

	$total = 0;

	for ( $i=0;$i<count($input->post->invoice_billable);$i++) {
	${'rp'.$i} = $page->invoice_line->getNew();
	${'rp'.$i}->invoice_billable_line = $input->post->invoice_billable[$i];
	${'rp'.$i}->invoice_billable_amount = $input->post->line_value[$i];

	$total += $input->post->line_value[$i];

	}

	$page->invoice_total = $total;
	$page->save();

	$out = "Estimate saved successfully";

	}

}

All the text fields are getting updated but all three select fields (client, terms and status) aren't updating.

I have an almost identical template for create instead of edit and everything works fine. Been scratching my head now for a good few hours, can anyone see anything wrong with the way I'm using the API?

Thanks.

Link to comment
Share on other sites

Just a quick thought....Could the problem exists because <select> elements are non treated as <input> elements and then never passed?

Thanks 3fingers, I'm not quite sure how that work, I'm pretty sure that PW ought to be able to accept select elements? In fact I've used them before as select multiple and it has worked.

It just seems strange as after much debugging, I have checked and $input->post->invoice_terms are getting set correctly but then they're not being passed to the DB.

Link to comment
Share on other sites

onjegolders - I know this is not answering your question directly, but I have been doing a lot of front-end forms direct from templates using this code from diogo as a starter:

http://processwire.com/talk/topic/59-module-want-form-builder/?p=11639

It lets PW take care of building and submitting the form.

If you need to it is very easy to manipulate data before submission with some conditional statements in the final foreach eg:

		foreach($mypage->fields as $f) {
                    if($condition_met){
			$mypage->set($f->name, transform_result($form->get($f->name)->value)));
                    }
                    else{
                        $mypage->set($f->name, $form->get($f->name)->value);
                    }
		}

Back to your original question, I have sent pagefield data to the DB like this. This allows the user to add a new option (child) to the page field and then it populates that new value to the selected field. My point is that if you are doing things manually like you are, I think you need to pass an actual "page" to the field - like I have done with: $newpage->organization = $neworganization;

$neworganization = new Page();
$neworganization->template = $templates->get("organization");
$neworganization->parent = $pages->get("/organizations/");

$neworganization->of(false);
$neworganization->name = $sanitizer->pageName($form->get($f->name)->value);
$neworganization->title = $sanitizer->text($form->get($f->name)->value);

$neworganization->save(); // Save the new organization as a child in the organizations page

$newpage->organization = $neworganization; //add it to the main organization field
$newpage->organization_other = ''; //empty the organization_other field - no longer needed since it is now in the main organization field

Anyway, hope that provides some insight into what the problem might be (in a roundabout kinda way). I would definitely suggest using that code from diogo though - it works beautifully :)

Link to comment
Share on other sites

onjegolders - I know this is not answering your question directly, but I have been doing a lot of front-end forms direct from templates using this code from diogo as a starter:

http://processwire.com/talk/topic/59-module-want-form-builder/?p=11639

It lets PW take care of building and submitting the form.

If you need to it is very easy to manipulate data before submission with some conditional statements in the final foreach eg:

		foreach($mypage->fields as $f) {
                    if($condition_met){
			$mypage->set($f->name, transform_result($form->get($f->name)->value)));
                    }
                    else{
                        $mypage->set($f->name, $form->get($f->name)->value);
                    }
		}

Back to your original question, I have sent pagefield data to the DB like this. This allows the user to add a new option (child) to the page field and then it populates that new value to the selected field. My point is that if you are doing things manually like you are, I think you need to pass an actual "page" to the field - like I have done with: $newpage->organization = $neworganization;

$neworganization = new Page();
$neworganization->template = $templates->get("organization");
$neworganization->parent = $pages->get("/organizations/");

$neworganization->of(false);
$neworganization->name = $sanitizer->pageName($form->get($f->name)->value);
$neworganization->title = $sanitizer->text($form->get($f->name)->value);

$neworganization->save(); // Save the new organization as a child in the organizations page

$newpage->organization = $neworganization; //add it to the main organization field
$newpage->organization_other = ''; //empty the organization_other field - no longer needed since it is now in the main organization field

Anyway, hope that provides some insight into what the problem might be (in a roundabout kinda way). I would definitely suggest using that code from diogo though - it works beautifully :)

Thanks Adrian, that's a really detailed and helpful post. I will take a look at Diogo's code - it could be very interesting indeed.

Regarding having an actual page for the page field, all those pages already exist. In theory I think I should be able to just specify the page ID for that field so if I wanted to hardcode it I could say $page->page_field = 1023. Is that not the case?

Link to comment
Share on other sites

Hmmm it seems even with Diogo's code, the fields aren't getting updated. When the page is saved they display correctly on the form (so you'd think the values have been updated) but when I check in the admin, it's the old values still.

I'm stumped :(

Link to comment
Share on other sites

I figured they already existed for you. I don't think you can specify the page ID. I think you need to assign the page array itself. In my example above you can see that I assign: $newpage->organization = $neworganization

where $newpage->organization is the "organization" page field from the page that was just created for the user's form submission and $neworganziation is the page array, rather than the ID of the page (I think that is right and makes sense :))

Link to comment
Share on other sites

Is it possible that there is a discrepancy between the fields "Dereference in API as" and its "Input field type". ie is one multi and the other singular? If singular, try the "Single page (Page) or boolean false when none selected" option instead of the other one. I found I had to use this the other day - don't remember why but it worked for me :)

Link to comment
Share on other sites

I don't understand exactly what you want to do. If your select fields are actually Pw Page fields, then IMO you need

to store page objects and not just integers.

As you are sending the ID's back to your template, you could just do this:

$editTermsId = (int) $input->post->edit_terms;
$page->invoice_terms = $pages->get($editTermsId);

Does this work?

Edit: Just saw that adrian recommended the same thing.

If you allow to store multiple terms, then you need to store a PageArray.

But as you let the user select only one value with the <select>, I assumed that 'invoice_terms' is a single page field.

Cheers

Link to comment
Share on other sites

If it's a multiple page field (or no output formatting!) you just do 

$page->invoice_terms->add((int) $input->post->edit_status);

add() works with page array, page or id's

  • Like 1
Link to comment
Share on other sites

If output formatting is off, it doesn't matter.

OK thanks Soma.

Edit: I'm getting the following error but I definitely have of(false)

Error: Exception: Method Page::add does not exist or is not callable in this context

I don't understand exactly what you want to do. If your select fields are actually Pw Page fields, then IMO you need

to store page objects and not just integers.

As you are sending the ID's back to your template, you could just do this:

$editTermsId = (int) $input->post->edit_terms;
$page->invoice_terms = $pages->get($editTermsId);

Does this work?

Edit: Just saw that adrian recommended the same thing.

If you allow to store multiple terms, then you need to store a PageArray.

But as you let the user select only one value with the <select>, I assumed that 'invoice_terms' is a single page field.

Cheers

Hi Wanze, it seems like this ought to work but for some reason it doesn't. I'll have to take a further look.

Link to comment
Share on other sites

Ah ok just looked at source again and it seems it doesn't matter if output formatting is on or off...

$page->invoice_terms = (int) $input->post->edit_status;

is correct (for single page field), if the edit_status is the id of the page you want to add.

Is practically the exact same as doing...

$editTermsId = (int) $input->post->edit_terms;
$page->invoice_terms = $pages->get($editTermsId);

just this is having an additional not necessary db query. $pages->get($editTermsId) will return the id again.

Link to comment
Share on other sites

Ah ok just looked at source again and it seems it doesn't matter if output formatting is on or off...

$page->invoice_terms = (int) $input->post->edit_status;

is correct (for single page field), if the edit_status is the id of the page you want to add.

Is practically the exact same as doing...

$editTermsId = (int) $input->post->edit_terms;
$page->invoice_terms = $pages->get($editTermsId);

just this is having an additional not necessary db query. $pages->get($editTermsId) will return the id again.

Thanks for looking. Still the values aren't getting transferred. Must be something completely different. I appreciate all of your help.

Link to comment
Share on other sites

Not sure if you want to go with diogo's option in that thread I linked to, but I just remembered - be sure to check out the last comment in that thread by me, because there is one change that should be made (fix a non-fatal error), and one key one (saving the page) that has to be made :)

I have found his approach really great for front-end forms - if you're still having troubles, I'd definitely revisit it as an option!

Link to comment
Share on other sites

I don't think that should be a problem. I think you should just have to edit:

foreach($mypage->fields as $f) {
	$mypage->set($f->name, $form->get($f->name)->value);
}

to iterate through the fields from the $input->post, assuming the fields already exist in the backend. Even if they don't you could easily add them through a foreach that uses the posted form data.

Might be a little fiddly, but not too difficult.

Link to comment
Share on other sites

A huge thanks to Diogo who has been helping me debug this. He eventually found out the cause of the error was the $page->invoice_line->removeAll(); line.

It seems to require a save() after this line and then a further save at the end.

if ($error == 0) {

$page->of(false);
$page->invoice_line->removeAll();
$page->save();

$page->of(false);

$page->title = $sanitizer->name($input->post->number);
...
$page->save();

Could Ryan confirm this is the correct way?

Diogo, mucho obrigado ;)

  • Like 2
Link to comment
Share on other sites

I think you've got it right. Because a removeAll(); is an action that is ultimately reflected in the database when the page is saved (rather than when you called removeAll), it's a good idea to do that save() after the removeAll() so that it's not getting mixed in and potentially voiding the other operations. 

Also wanted to recommend adding validation to this:

$page->invoice_terms = (int) $input->post->edit_status;

Something like this:

// using find rather than get ensures the item is retrieved with access control
$item = $pages->find((int) $input->post->edit_status)->first(); 

// double check the item you are trying to add is what you expect by checking
// something like the template or the parent, etc. 
if($item && $item->template == 'your-expected-template') $page->invoice_terms = $item;
  • Like 3
Link to comment
Share on other sites

Update to the last post– I am adding this validation check to FieldtypePage so that the above won't be necessary in PW 2.3.1 and higher (it will throw an exception).

This is now present on the dev branch. It throws an exception at save() time if the field contains pages that are outside the defined rules in the Inputfield.

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...