• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Multi-step form process + validation

#1
[eluser]Crucial[/eluser]
On an application I'm working on, I use a lot of form "wizards," or forms that have multiple steps to them. I'm using the validation class as well.

I'm trying to come up with the best way to go through a multi-step form like this, but am running into some problems.

The first step will show no errors because nothing's been posted, but every step after will also show the validation errors on the top of the page because there's still $_POST data avaiable from the previous form.

I can clear the $_POST data out and store it in flashdata, but that removes the validation process and you can just continue on through the forms without ever giving an error.

I know the way I have this setup is wrong, but have been banging my head against the wall on this and need a fresh set of eyes.

I don't want the URL to change either, it's always going to the same place.

If you need to see the code I have I'll post.

#2
[eluser]thinkigniter[/eluser]
This may help!
Code:
<?php
class Form extends Controller{
    
    function form()
    {
        parent::Controller();
        $this->load->library('email');
        $this->load->helper('form');
        $this->load->helper('url');
        $this->load->library('validation');
    }


    function process($ID)
    {
        $rules['Name'] = "trim|required|xss_clean";
        $rules['Email'] = "trim|required|valid_email|xss_clean";
        $rules['Subject'] = "trim|required|xss_clean";
        $rules['Message'] = 'trim|required|min_length[5]|max_length[500]|xss_clean';
        
        $this->validation->set_rules($rules);    
        
        $field['Name'] = "'Your Name'";
        $field['Email'] = "'Your Email Address'";
        $field['Message'] = "'Your Message'";
        $field['Subject'] = "'Subject of your email'";

        $this->validation->set_fields($field);    
                
        if( $this->validation->run() == FALSE )
        {    
            $this->load->view('Form');
            
        }else{
        
            $this->_store();
        }        

    }
    
    function _store()
    {
        $name = $this->input->post('Name',true);
        $email = $this->input->post('Email',true);
        $message = $this->input->post('Message',true);
        $subject = $this->input->post('Subject',true);                        
        $insert_info = "INSERT INTO TABLE('Name','Email','Message','Subject')VALUES($name,$email,$message,$subject)";    
        $query = $this->db->query($insert_info);
    }


    function _remap($ID)
    {
        $this->process($ID);
    }
    

}
?>

Ok let me explain.

[_remap]
First I use the _remap function as an entry point and start the process function.

[The Process function]
Sets 'rules' and 'Validation' for the form and then '$this->validation->run() == FALSE' tries to validate the form and if it returns FALSE loads the form(view) again.

If it returns true it starts the _store function and stores the information to the Database.

[The View]
Code:
<label >Subject of your email</label>
&lt;input type="text" class="input" value="&lt;?php echo $this-&gt;validation->Subject;?&gt;"
id="Subject" name="Subject" title="Subject of your email">
    <div>&lt;?php echo $this->validation->Subject_error; ?&gt;</div>

The Form(view) is a standard form with php tags interspersed for things like validation error messages etc.

The forms action is
Code:
echo form_open('Form');

I hope this helps clear the brain fog.
sending the information back to the controller to process again, and again, and again until they get it right...

#3
[eluser]Crucial[/eluser]
Hm. I don't think that will work. I have forms with like 4-5 steps, so we're talking 4-5 different views here, all using the same URL and taking $_POST data. Basically, it's like having 4-5 different forms, all with different input fields and rules, that all have to pass back to the same "controller" and validate for each section before moving on to the next form.

I'm putting controller in quotes because these plugins are actually being stored in the plugin directory, but I'm treating them as controllers in there since they're handling validation and loading views.

I have to limit this to one controller because it's a plugin, it has to be modular so I can add/remove plugins. They're all in one directory so the application can look in this folder and auto-enable anything in there.

Maybe that's confusing. Ok, I have this one page that takes you to a feed creation wizard. You can select from a variety of feed types (standard RSS feed, iTunes podcast, custom XML feeds for things like Flash slideshows, etc.). These are listed in a radio group, and the choices are limited to what's in the plugin directory.

This form works, of course, and I'm using _remap and a route to send the selected radio request to a plugin.php controller (in the controller) directory. This is taking the "short" plugin name (e.g. rss) that's passed in the routing section, and redirecting it to the appropriate plugin_pi.php file in the plugins directory:

Code:
$route['feeds/create/([a-z]+)'] = "plugins/$1";

The plugins.php controller has this in it:

Code:
&lt;?
class Plugins extends Controller {
    public function __construct() {
        parent::__construct();
    }
    
    public function _remap($plugin) {
        $this->load->plugin($plugin);
    }
}
?&gt;

Just redirecting for now. Each plugin has a file in the plugins directory, and then views, which are in a self-named sub-directory in the views section, e.g.:

Code:
/views/plugins/plugin-name/

I can get the first step of this form to work. It has no $_POST data beforehand and will validate itself and move on. The second page automatically thinks $_POST data has been sent and sends an error. I can clear the $_POST data and either store it in session data, or re-output it in hidden input fields.

The problem comes with the next step. The next step usually comes up with just a blank page, or will redirect back to the first step.

I don't know, I've tried this so many different ways and just can't get it to work. I think my head's still in a fog Undecided

#4
[eluser]flojon[/eluser]
I use something like this to handle "multi-step form"
Code:
class Form extends Controller
{
    var $rules;
    var $fields;
    var $pages;
    
    function Form()
    {
        parent::Controller();

        $this->pages = array(1=>'form1', 2=>'form2', 3=>'form3', 4=>'form4');

        $this->rules[1]['field1'] = "trim|required";
        $this->rules[1]['field2'] = "trim|required";
        ...

        $this->fields[1]['field1'] = 'Field 1';
        $this->fields[1]['field2'] = 'Field 2';
        ...
        
        $this->rules[2]['field1'] = "trim|required";
        $this->rules[2]['field2'] = "trim|required";
        ...

        $this->fields[2]['field1'] = "Field 1";
        $this->fields[2]['field2'] = "Field 2";
        ...
    }

    function index()
    {
        $this->form(1);
    }

    function form($page)
    {
        ...

        $prev = ($page > 1) ? $page - 1 : 1;

        $this->validation->set_rules($this->rules[$prev]);
        $this->validation->set_fields($this->fields[$prev]);

        if ($this->validation->run() === FALSE)
        {
            $this->_show_page($prev);
            return;
        }
        else if ($page == 4) // last page is valid
        {
            // insert into database or whatever...
        }
        else
        {
            // store relevant field to the session...
        }
        ...

        if (!empty($this->fields[$page]))
            $this->validation->set_fields($this->fields[$page]);
        $this->load->view($this->pages[$page]);
    }
}

Then I use this to open the forms
Code:
&lt;?=form_open('form/form/2');?&gt;
...
&lt;?=form_open('form/form/3');?&gt;
...
&lt;?=form_open('form/form/4');?&gt;
...

#5
[eluser]Crucial[/eluser]
Something like that might work. The only problem, I would have to modifiy that controller everytime a plugin was added. I can't touch core files, all of this has to be self-contained in the plugin file. But it does give me an idea, thanks!

#6
[eluser]Crucial[/eluser]
By the way, where is this function: _show_page

#7
[eluser]flojon[/eluser]
I didn't see your second post so didn't know you wanted to do a plugin. I'm not sure I understand what you are trying to do...

[quote author="Crucial" date="1214353666"]By the way, where is this function: _show_page[/quote]

Ahh.. It's a local function.. That basically does this, after setting up the local view variables in $data...
Code:
if (!empty($this->fields[$page]))
    $this->validation->set_fields($this->fields[$page]);
$this->load->view($this->pages[$page], $data);

#8
[eluser]Crucial[/eluser]
Well it's not a plugin the sense of how CI defines a plugin.

I have an application that allows you to install plugins/extensions for creating various feed types (RSS, iTunes, podcast, custom, etc.). So that's what I mean by plugins.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.