Form on any page and result on a singel page

4 years ago

tomcat4x
Member | 22
+
0
-

Hi,

i try to implement a simple search from in the menu of ervery page. So i thogt to use the base presenter to crate te form:

protected function createComponentSimpleForm()
{
    $form = new Form;
    $form->addText('name', 'Name:');
    $form->addSubmit('search', 'Search');
    $form->onSuccess[] = array($this,'simpleFormSucceeded');
    return $form;
}

This works fine by inserting in the template {control simpleForm}

Now i want to redirect the search call to the page (presenter) SearchResult to show the results.

And here is the beginning of my problems. I have added the line

$form->setAction($this->link('SearchResult:Simple'));

to the base presenter. How to tell the form, that a callback function named simpleFormSucceeded in the Presenter SearchResult should be called?

I have tried

$form->addHidden('do','simpleFormSucceeded');

but there comes the error:

There is no handler for signal ‘simpleFormSucceeded’ in class App\Presenters\SearchResultPresenter.

Any suggegtions how to realize a form on every page and show the result on just one page?

regards
Frank

4 years ago

newPOPE
Member | 659
+
-1
-

Answer is simple. Just implement handler in SearchResultPresenter

public function simpleFormSucceeded (Form $form) {
    $formValues = $form->getValues(); // $values are filled with inputs from Form.
}

4 years ago

tomcat4x
Member | 22
+
0
-

have i done.

<?php

namespace App\Presenters;

use Nette;
use App\Model;

class SearchResultPresenter extends BasePresenter
{

    public function renderDefault() {}

    public function simpleFormSucceeded(Form $form){
        $values = $form->getValues(TRUE);
        echo $values['name'];
    }
}
?>

But still the error:

There is no handler for signal ‘simpleFormSucceeded’ in class App\Presenters\SearchResultPresenter.

4 years ago

David Matějka
Moderator | 5933
+
0
-

Hi, you should not use POST method for displaying search results. You have two options:

  1. use UI\Form, do not change action etc. and then redirect to the search result page in the form success handler
  2. use Nette\Forms\Form instead of Nette\Application\UI\Form and setup method and action

in both cases, you will handle name parameter in the action (or render) method

4 years ago

tomcat4x
Member | 22
+
0
-

But i want to use the POST method.

I dont want the users to play around with the get parameters they can see.

Is there no solution with the post method?

4 years ago

Michal Vyšinský
Member | 614
+
0
-

Hi, the name of the method should be ‘handleSimpleFormSucceeded’

4 years ago

tomcat4x
Member | 22
+
0
-

Have i done.

public function handleSimpleFormSucceeded(Nette\Application\UI\Form $form){
        $values = $form->getValues(TRUE);
        echo $values['name'];
    }

Now i get the error:

Argument 1 passed to App\Presenters\SearchResultPresenter::handleSimpleFormSucceeded() must be an instance of Nette\Application\UI\Form, null given

The framework does not inject the form into this funktion in the SearchResultPresenter.

4 years ago

old.gandalf
Member | 17
+
+1
-

Hello,

the setAction() method won't pass the Form instance to the method. Moreover, it definitely cannot be done by calling a signal, since handle…() methods expect the params to be passed through GET while Form data is passed by POST, that's the reason why NULL is given to the handler. Also the way you “trigger” the signal by the ‘do’ parameter seems like bad design to me in this case; I suggest using link() for signal referring, it can help you not to fall into trouble in many cases.

It's a good practice to redirect the form in onSuccess callback to prevent form data resend when clicking the F5 button. So I recommend the following solution:

<?php
protected function createComponentSimpleForm()
{
    $form = new Form;
    $form->addText('name', 'Name:');
    $form->addSubmit('search', 'Search');
    $form->onSuccess[] = $this->simpleFormSucceeded;    //this way, the Form instance will be passed to the callback function properly
    return $form;
}

public function simpleFormSucceeded(Nette\Application\UI\Form $form)
{
    //do the work with the form here
    $this->redirect('SearchResult:default', $form->getValues()->name);
}

...

//SearchResultPresenter

public function renderDefault($name){   //GET
    //display your results
}
?>

Another possibility is to move the form along with the callbacks to BasePresenter, but I consider that impractical.

If, for any reasons, you need to access POST values in presenter, you can use $this->getPost() method.

Edit: In fact, my solution is the one @DavidMatějka suggested above in number 1, I overlooked his comment.

Last edited by old.gandalf (2015-09-11 12:55)

4 years ago

old.gandalf
Member | 17
+
0
-

tomcat4× wrote:

But i want to use the POST method.

I dont want the users to play around with the get parameters they can see.

Is there no solution with the post method?

Trust me, there are many reasons why using GET for this purpose is better, for you as well as for the user who will not have to mess with the need to resubmit the form every time to refresh the page. Also consider the situation of a user who wants to send a link to some results to his fellow via email – if the search query is not in GET but in POST instead, they will not be able to do this.

4 years ago

tomcat4x
Member | 22
+
0
-

Okay.

You have convinced me to use the get method with a redirect in this case.

But i think it is an unfortunate solution of the framework to offer a $form->setAction() method which does not work with post parameters. There should be a hint somewhere.

4 years ago

duke
Member | 650
+
0
-

tomcat4× wrote:

I dont want the users to play around with the get parameters they can see.

If you absolutely don't want users to play around with the get parameters, you can simply put the search criteria into session and then redirect. But if you want to be able to have multiple concurrent searches (with additional functionality like paging) for single user (e.g. in 2 tabs in same browser), then you will still need to pass an identifier for the search via GET (and store the criteria in session under this identifier) and likely also some cleanup mechanism for older criteria stored in session.

4 years ago

kengoogle
Member | 1
+
-1
-

Answer is simple. Just implement handler in SearchResultPresenter

4 years ago

tomcat4x
Member | 22
+
0
-

kengoogle wrote:

Answer is simple. Just implement handler in SearchResultPresenter

As you see in this thread it is not so simple.

I have implementend this handler in two ways in SearchResultPresenter.

public function simpleFormSucceeded(Form $form){}
public function handleSimpleFormSucceeded(Form $form){}

In the first the handler will not be executed and in the second the form will not be assgined.

4 years ago

old.gandalf
Member | 17
+
0
-

tomcat4× wrote:

kengoogle wrote:

Answer is simple. Just implement handler in SearchResultPresenter

As you see in this thread it is not so simple.

I have implementend this handler in two ways in SearchResultPresenter.

public function simpleFormSucceeded(Form $form){}
public function handleSimpleFormSucceeded(Form $form){}

In the first the handler will not be executed and in the second the form will not be assgined.

@kengoogle As I explained above, arguments are passed to signal methods ONLY by get. In addition, form onSuccess[] callbacks work in another way than signals do. That's why they are passed the Form instance.

simpleFormSucceeded() is not a handler since it does not start with a “handle” keyword.

4 years ago

tomcat4x
Member | 22
+
-1
-

I have the solution (what i have done wrong)

$form->addHidden('do','simpleFormSucceeded');

must be

$form->addHidden('do','simpleForm-succeeded');

Now you can redirect the search call to an other presenter e.g. SearchResult to show the results.

A form without $form->setAction() method will be rendered with a hidden field like this:

<input type="hidden" name="do" value="registrationForm-submit">

But when you use the $form->setAction() method this field disappears in the html code. I dont know why. Its a bug or a feature.

So you have to rebuild ths field by using

$form->addHidden('do','simpleForm-succeeded');

You must use a hyphen between the form name and ‘succeeded’. Without this hyphen you get the errors as seen above.

now you ca define the function simpleFormSucceeded($form)´in the presenter you have set in $form->setAction() method a everything works.

4 years ago

old.gandalf
Member | 17
+
0
-

tomcat4× wrote:

I have the solution (what i have done wrong)

$form->addHidden('do','simpleFormSucceeded');

must be

$form->addHidden('do','simpleForm-succeeded');

Now you can redirect the search call to an other presenter e.g. SearchResult to show the results.

A form without $form->setAction() method will be rendered with a hidden field like this:

<input type="hidden" name="do" value="registrationForm-submit">

But when you use the $form->setAction() method this field disappears in the html code. I dont know why. Its a bug or a feature.

So you have to rebuild ths field by using

$form->addHidden('do','simpleForm-succeeded');

You must use a hyphen between the form name and ‘succeeded’. Without this hyphen you get the errors as seen above.

now you ca define the function simpleFormSucceeded($form)´in the presenter you have set in $form->setAction() method a everything works.

I cannot help myself stop thinking this is not how form callbacks should be treated. In my opinion, every time you change the do argument in the form it is bad design (you even have to hardcode the name like this, which is normally done by the framework).

I believe a better solution would be to move the onSuccess callback to BasePresenter – that would allow you not to mess around with the setAction() method and do field.

4 years ago

tomcat4x
Member | 22
+
0
-

I think thats now more a philosophic question where the callback should be treated. In the palce where the form is defined (basePresenter) or where the reslut is shown (SearchResultPresenter).

I am more concerned with the question why the hidden do argument disappears when using the setAction() method. In my book that makes no sense.

If it would not disappear there will be no need to mess around with the do field.

Btw I am not changing the do element. I set the element with the same values as before and where do you mean that i have to hardcode the name like this?

4 years ago

old.gandalf
Member | 17
+
0
-

tomcat4× wrote:

I think thats now more a philosophic question where the callback should be treated. In the palce where the form is defined (basePresenter) or where the reslut is shown (SearchResultPresenter).

I meant it differently. My point was, when you move the onSuccess callback method to the BasePresenter, it will then be available in all presenters that extend it. So you would not have to mess around with the do element since it would be created automatically.

Btw I am not changing the do element. I set the element with the same values as before and where do you mean that i have to hardcode the name like this?

I'm talking about this line:

<?php
$form->addHidden('do','simpleForm-succeeded');
?>

The do element is created automatically by the framework, I believe changing it explicitly kind of points to bad design. By hardcoding I mean “translating” the callback method name to the externally (HTML) visible one. If this is not what you are doing, I'm sorry, I might have misunderstood you.