Having multiple forms in one page, when i submit one of them, how can i tell wich one was submitted?
I thought about generating uniqe ids for each from, and saving them as hidden fields and to the user-session - while this is a solution, the problem with it is that there is no good place to remove old ids from the session.
Any better ideas how to solve this problem?
Thanks in advance!
First of all: have you considered sending the two forms to two different actions? That way you can handle each form separately in an action each. This should be the "best-pratice" if you're using the Zend MVC component.
The other option is to check for the value of the submit button which will be included in the request, e.g.
<input type="submit" name="save" value="form1" />
// in PHP:
// $_POST["save"] will contain "form1"
<input type="submit" name="save" value="form2" />
// in PHP:
// $_POST["save"] will contain "form2"
Be careful as the value-attribute will be rendered as the button's label.
So perhaps you want to distingush the forms by different submit-button names:
<input type="submit" name="save-form1" value="Submit" />
// in PHP:
// $_POST["save-form1"] will contain "Submit"
<input type="submit" name="save-form2" value="Submit" />
// in PHP:
// $_POST["save-form2"] will contain "Submit"
EDIT:
During the comment-dialog between the OP and myself the following seems to be a possible solution:
class My_Form_Base extends Zend_Form
{
private static $_instanceCounter = 0;
public function __construct($options = null)
{
parent:: __construct($options);
self::$_instanceCounter++;
$this->addElement('hidden', 'form-id',
sprintf('form-%s-instance-%d', $this->_getFormType(), self::$_instanceCounter);
}
protected _getFormType()
{
return get_class($this);
}
}
class My_Form_Type1 extends My_Form_Base
{
public function init()
{
// more form initialization
}
}
class My_Form_Type2 extends My_Form_Base
{
public function init()
{
// more form initialization
}
}
some errors in you code, shoudl be something like this:
class Application_Form_Idee_Base extends Zend_Form
{
private static $_instanceCounter = 0;
public function __construct($options = null)
{
parent::__construct($options);
self::$_instanceCounter++;
$this->addElement('hidden', 'form-id', array(
'value' => sprintf('form-%s-instance-%s', $this->_getFormType(), self::$_instanceCounter))
);
}
protected function _getFormType()
{
return get_class($this);
}
}
Related
I have a list shown in my view which is populated from my database and it uses pagination. Works fine so far. What I want to do now is to give the user the possibility to jump to a specific page via input into a text field.
My controller method would look like this, as my imagination goes:
#Controller
public class OrderController {
private static final int INITIAL_PAGE_SIZE = 15;
private int currentPage = 1;
#Autowired
private OrderService service;
#GetMapping("/dispo/orderViewList/{pageNumber}")
private String showSpecifiedPage(#RequestParam("pageNumber") Integer page, Model model) {
Page<LoadOrders> pagedList = service.findAll(page -1, INITIAL_PAGE_SIZE);
List<LoadOrder> orderList = service.createLoadOrderPage(pagedList);
model.addAttribute("page", orderList);
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", pagedList.getTotalPages());
return "/dispo/orderViewList";
}
My idea is now since I have a model attribute named "page" to change this attribute to the page number I'd like to show and send this as a get request to the controller method. And this is the code for the view:
<form action="#" th:action="#{/dispo/orderViewList/{page}}" method="get">
Direkt zu Seite: <input type="text" th:field ="*{page}" size ="4"> <input type="submit">
</form>
The result is just what I wanted and looks like this:
But the controller is never called. In fact the controller for the standard list is called:
#GetMapping("/dispo/orderViewList")
private String showOrderList(#RequestParam("page") Optional<Integer> page, Model model) {
page.ifPresent(p -> currentPage = p);
Page<LoadOrders> pagedList = service.findAll(currentPage - 1, INITIAL_PAGE_SIZE);
List<LoadOrder> orderList = service.createLoadOrderPage(pagedList);
model.addAttribute("page", orderList);
model.addAttribute("currentPage", currentPage);
model.addAttribute("totalPages", pagedList.getTotalPages());
return "/dispo/orderViewList";
}
So what can I do to tell the controller to use the method with the page parameter?
I am just a beginner in reactjs. I feel so good about using it, but I have been stuck for a while on a concept that I wanna implement, that would solve me whole lot of other issues.
Concept
I want to create a form component that can have dynamic children passed to it. It won't be a specific form component like LoginForm, ContactForm etc. Rather it would just be Form.
Approach 1
class LoginPage extends Rect.Component {
constructor(props) {
super(props)
this.submit = this.submit.bind(this);
this.validate = this.validate.bind(this);
this.reset = this.reset.bind(this);
}
submit(...args) {
this.refs.form.submit(args);
}
validate(...args) {
this.refs.form.validate(args);
}
reset(...args) {
this.refs.form.reset(args);
}
render() {
return (
<LoginPage>
<Form ref="form" onSubmit={this.submit}>
<Input value="email" pattern="/email_pattern/" onValidate={this.validate} />
<Input value="password" pattern="/password_pattern/" onValidate={this.validate} />
<Button value="submit" action={this.submit} />
<Button value="reset" action={this.reset} />
</Form>
</LoginPage>
}
}
Input onChange calls the validate function that just passes on the args to the Form's validate function. For the Form to know if all it's children's are validated. I pass isValid and targetInputComponent as args to the form.
Button Submit onClick calls the submit function likewise and LoginPage (acts as middleware) passes the call to the Form component. Form check it's state for inValid inputs etc.
Button Reset onClick call is passed to the Form component likewise. But how do the form handle this reset functionality? Input's value is controlled by LoginPage. Form can't change the input's value.
Aproach 2
What I did was add the input's data and validity to the LoginPage state. Now both Form and Inputs just call the Login Page to update it's state. Form and Inputs components are using this state as prop.
class LoginPage extends React.Component {
constructor(props) {
super(props)
this.state = {
formSchema: this.initSchema()
}
this.validateField = this.validateField.bind(this);
this.submitForm = this.submitForm.bind(this);
}
initSchema() {
const formSchema = {
email: {
isValid: false,
value: ''
},
password: {
isValid: false,
value: ''
},
password2: {
isValid: false,
value: ''
}
}
return formSchema;
}
validateField(dataObj, targetComponent) {
const formSchema = Object.assign(this.state.formSchema, dataObj);
this.setState({ formSchema })
}
submitForm(isSuccess) {
console.log(isSuccess);
console.log('Form Submit: ', this.state.formSchema);
throw new Error('Submition Error');
}
reset() {
// Loop through each object in formSchema and set it's value to empty, inputs will validate themselves automatically.
}
render() {
return <div>
<Form ref="formLogin" className="auth-form" onSubmit={this.submitForm} formSchema={this.state.formSchema}>
<h1>
Switch Accounts
</h1>
<Input type="email" name="email" onValidate={this.validateField} value={this.state.formSchema.email.value}
isValid={this.state.formSchema.email.isValid}/>
<Input type="password" name="password" onValidate={this.validateField} value={this.state.formSchema.password.value}
isValid={this.state.formSchema.password.isValid}/>
<Button value="Submit" type="submit" />
</Form>
</div>
}
}
Problem
This approach is making the LoginPage Component quite messy. How will the LoginPage component will handle the forms if I have more than 1 form on the page? There will be even more features to LoginPage like Lists, Grid, Modals etc. This LoginPage shouldn't Handle these situations. Form should be responsible for all the inputs, submition, etc functionality. This form component should be generic to all types of forms. I don't want to create feature forms like LoginForm, ContactForm, etc.
The solution to this issue will aid me a lot in whole lot of other components.
Your approach 2 is the standard way of handling this problem.
Why wouldn't you create a separate <LoginForm>? Doing so can abstract the fields and validation away from other unrelated functionalities on your page.
If later you need a <ContactForm> or any other type of form, it will have different fields and different validation logic, meaning you'll need to build it out regardless.
Short of using something like redux, you're on the right track.
There are numerous ways to make ‘generic’ forms. But in my opinion it is best to keep the forms seperatly.
The reason why I say this, is because one way or another, you still have to implement various validation condition for most fields, such as e-mailaddress or what ever you will use.
I think the best approach is to make the components individual. For example: make a TextField component that handles input stuff like validation. Maybe a Button component for submit and callbacks.
So my advise: keep the forms seperatie. No need to overthink and lose useful time in trying to make things ‘pretty’.
Goodluck!
In case the title is not so clear:
I have a form and two submit buttons( or I can use one submit button and the other one could be just a button or an anchor tag) and want each one to submit my form to a different action...
any help is so much appreciated
You could give the second submit button a HTML name, then check to see if that name is set in the POST statement.
<input name="back" type="submit" value="Go Back">
<input name="next" type="submit" value="Continue">
You'd probably need to use jQuery to accomplish that. When you construct your form, leave out the method altogether. Then, give your two buttons and id:
<button id="submit-1">Submit 1</button>
<button id="submit-2">Submit 2</button>
Then, use jQuery.post or jQuery.ajax to submit your form data.
See these articles for more info:
http://api.jquery.com/jQuery.post/
http://api.jquery.com/jQuery.ajax/
It might be easiest to "flash" the data.
In your routes:
Route::post('/test', 'TestController#postTest');
Route::get('/test', 'TestController#getTest');
Route::any('/testSubmit1Action', function()
{
var_dump(Input::old());
});
And then your TestController:
class TestController extends BaseController {
public function postTest()
{
// Refer to getTest() below for how these buttons are named.
// We can check for the existence of a certain button and process
if(Input::has('submit1'))
{
// Redirect to different route / URI
Input::flash();
return Redirect::to('/testSubmit1Action');
// Alternatively, you could process action 1 here
}
if(Input::has('submit2'))
{
// Process action 2
}
}
public function getTest()
{
// I recommend putting this in a view / blade template
// eg... return View::make('foo.bar');
echo Form::open();
echo Form::submit('Submit Action 1', array('name' => 'submit1'));
echo Form::submit('Submit Action 2', array('name' => 'submit2'));
echo Form::close();
}
}
EDIT: Okay, I've stripped this down to the bare minimum.
The below code is how I would set up what I'm trying to accomplish in straight html/php.
If the form has been submitted and the verification of fields does not pass, a text field appears, otherwise, if the form has NOT been submitted, a dropdown is offered.
html/php:
<form method="post" action="">
<div class="state">
<?php
if(!$_POST['submit']){
// show the select list of states.
echo '<select name="state">
<option>list of all states</option>
</select>';
}else{
// show text input box
echo '<input type="text" value="'.$_POST['select'].'" name="state" />';
}
?>
</div>
<input type="submit" name="submit" value="submit" />
But I have no clue how I would set this up with the ZendFramework Forms Class, or how to tap into it to even begin to do this.
You really should not do this kind of stuff (I mean write plain-text form) if you're using Zend Framework. You should use the built-in methods.
First of all, enable the Form and create a form. Then use this very-easy-to-understand code. Note that I've not tried if it works 100% but this is 100% the logic you need.
Form class
class Application_Form_YourFormName extends Zend_Form
{
public function init()
{
$this->setMethod(self::METHOD_POST);
$this->setAction('THE-URL-WHERE-THIS-FORM-IS-MANAGED');
$Element = new Zend_Form_Element_Text('state');
$Element->setLabel('State:');
$Element->addValidators(array(/*DON'T KNOW WHAT KIND OF VALIDATION YOU NEED*/));
$Element->addFilters(array(new Zend_Filter_StringTrim(),
new Zend_Filter_HtmlEntities(array('quotestyle' => ENT_QUOTES))));
$Element->setRequired();
$this->addElement($Element);
unset($Element);
$this->addElement('reset', 'Reset');
$this->addElement('submit', 'Submit');
}
public function stateNotPresent()
{
$this->removeElement('state');
// Note that getStates() is an hypotetical method of an
// hypotetical Application_Model_State where you can retrieve an
// array containing the list of the state you have. This array is
// needed to fill the Select list.
$States = Application_Model_State::getStates();
$Element = new Zend_Form_Element_Select('statelist');
$Element->setLabel('State:');
$Element->setMultiOptions($States);
$Element->addValidator(new Zend_Validate_InArray($States));
$Element->setRequired();
$Element->setOrder($this->count() - 2);
$this->addElement($Element);
unset($Element);
}
}
Controller class
public function name-of-the-action-you-needAction()
{
$Form = new Application_Form_YourFormName();
if ($this->_request->isPost())
{
if ($Form->isValid($this->_request->getPost()))
{
// Do things. A good text has been entered
}
else
{
$Form->stateNotPresent();
if ($Form->isValid($this->_request->getPost()))
{
// Do things. A good selection has been entered.
}
else
{
// echo the edited form (the one with the dropdown list)
$this->view->Form = $Form;
}
}
}
// The first time the page is requested.
// The page with the text box will be printed
else
$this->view->Form = $Form;
}
VIEW-OF-THE-ACTION.phtml
if ($this->Form != null)
echo $this->Form;
I hope you'll appreciate the effort I made to let you understand.
I would like to use ZendX_Jquery autocomplete in a partial, which is in my layout.
How can I do that :
My layout :
<div class="prefix_11 grid_5" id="header_search_engine">
<?php echo $this->partial("/common/_search_engine.phtml"); ?>
</div>
An action :
public function autocompleteAction($search='') {
$this->view->autocompleteElement = new ZendX_JQuery_Form_Element_AutoComplete('ac');
$this->view->autocompleteElement->setJQueryParam('source', '/searchengine/getsearch');
$this->view->autocompleteElement->setJQueryParam('minLength',
$this->configApplication->autocomplete->max_cars);
}
How can I use it in the partial, in the layout ?
How can i send the autocompleteElement in the partial view ?,
Thanks to help.
Fabrice
#fabrice
I had the same problem using autocomplete with my layout and I have solved it with the following:
Use placeholder for my searchBox
Create a Zend_Controller_Plugin that extends Zend_Controller_Plugin_Abstract
in predispatch execute method renderUiWidgetElement of autocomplete element.
set the placeholder with the form
Example:
class myLibrary_Controller_Plugin_SearchBox extends Zend_Controller_Plugin_Abstract
{
public function preDispatch()
{
$this->searchBox();
}
public function searchBox()
{
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->initView();
$view = $viewRenderer->view;
$searchForm = new Application_Form_JQueryForm();
$searchForm->acProduct->renderUiWidgetElement();
$view->placeholder('searchBox')->set($searchForm);
}
}
The key is to launch method renderUiWidgetElement();. Without it, the layout will not add the neccesary javascript to the autocomplete element. I got this information from here: http://cientouno.be/blog/categorie/zend-framework
Thanks a lot to cientouno!
Thank you, but, I used the ActionStack for display on every page. And do, I use a form.
public function autocompleteAction() {
$formAutoComplete = new Frontoffice_Form_Autocomplete();
$this->view->autocompleteElement = $formAutoComplete;
$this->_helper->viewRenderer->setResponseSegment('autocomplete');
}
and, in the layout :
<div class="prefix_10 grid_6" id="header_search_engine">
<?php echo $this->partial("/common/_search_engine.phtml");
echo $this->layout()->autocomplete;
?>
</div>
You can send the autocompleteElement in the partial view with this code.
<div class="prefix_11 grid_5" id="header_search_engine">
<?php echo $this->partial("/common/_search_engine.phtml", array('autocompleteElement ' => $this->autocompleteElement); ?>
</div>