Multi step/page form in PHP & CodeIgniter

13.6k views Asked by At

I'm trying to build a multi step/page form in PHP and CodeIgniter and I was wondering if any of you could help me.

How can I have a multi step form in CI that updates rather than inserts again when you return to the previous step with the back button? How can I have a form that doesn't have those back button POST form resend messages?

Edit: without JS if possible

Thanks!

5

There are 5 answers

2
naivists On BEST ANSWER

Create a unique ID which you use in all steps of your wizard. Save that ID to the database upon the initial saving of your form. Forward this ID to the next steps using a input type="hidden".
When saving a step, first try to match the ID and, if you find it int the database, perform an update instead of an insert.

To avoid the "do you want to resend post data", perform each wizard step in two CodeIgniter controller actions:

  • SaveStep5(POST: form instance ID + other "wizards step 5" inputs): looks up the form instance ID in the database and performs insert/update commands; redirects to LoadStep6 and passes the form instance ID in a GET parameter;
  • LoadStep6(GET: form instance ID); looks up the form instance in the database, if the instance is not found: error handling if the instance is found, renders the input form for "step 6"
0
Munim On

If you want to avoid those messages which warn the user about resending posts, and you also want to have multiple proper pages rather than just different steps in javascript, you can put the answers in the URL as GET parameters.. so after the first form submission, you will get form2.php? in the URL.. you can add those answers as hidden variables in form2 and so on.
It is not a very elegant solution though. I'd recommend you to use javascript: add a custom handler for form submission and submit form content via ajax, and then load the next form on ajax complete.
Also, like the other person answered, on the server end, you will need a unique ID which fetches/updates the submission data in the database.

0
arnorhs On

I like the approach of waiting on the database update until all steps have been completed. You could store all the data in the intermediate steps in a session. I suppose you could even save the model object you're using (if you're using one) in a session and after all steps have been completed you can do the database insert.

1
bpeterson76 On

Here's my answer from another question. It gives you forward/backward ability without the chance to lose data, instantly jumps between pages, is EASY to code, needs no sessions, and is framework-independent (can be used in any situation):

I develop a product for the Psychology market that does 250 question psychological based testing. To make a test that isn't completely overwhelming, I break the form up into 25 question segments while outputting it in a loop via div tags with a sequential ID appended (ie. div1, div2, div3) Each div is set to display:none but the first.

I then provide the user with a button that toggles the current div + 1 (ie if on div 1, it would do a $(#div2).show() etc. Back buttons do the opposite.

The important part is that the form covers ALL divs. Then its just a matter of swapping out the forward/back button at the end with a submit button.

Voila! Yes, low-tech. But FAST....and no chance to EVER lose values going forward or backward.

So, a rough truncated example:

<form>
  <div id="div1">
     First 25 Questions
     <input type="button">shows next div</input>
  </div>
  <div id="div2" style="display:none">
    Second 25 Questions
    <input type="submit">Submit Form</input>
  </div>
</form>
0
NULL pointer On

I have a model to store my wizard data with a variable for each field on the form:

class Class_signup_data extends CI_Model {
const table_name="signups_in_progress";
public $market_segment; // there is a field named 'market_segment' in the wizard view

... ...

I have one controller to handle the whole process, with parameters for the session_id and the stage of the process we are at:

    class Signup extends CI_Controller {
    public function in_progress($session_id=NULL,$stage=1) {
        $this->index($session_id,$stage);
    }
    public function index($session_id=NULL,$stage=1) {
    if ($session_id===NULL) $session_id=$this->session->userdata('session_id');
...
...

In this controller I have a switch for which stage we are at - it looks for a 'Prev' button first:

switch ($stage) {
        case 2:
            if ($this->input->post('prev')) { // if they click Previuous, the validations DON'T need to be met:
                $signup_data->save_to_db(array_merge(array('ip'=>$_SERVER['REMOTE_ADDR'],'session_id'=>$session_id,'signup_stage' => '1',
                    'signup_complete' =>'0'),$this->input->post()),$this->db,$session_id);
                $this->load->helper('url');
                redirect("/signup/in_progress/".$session_id."/1");

And later in the switch I use CI's Validations to display a form and process 'Next' if it was clicked or it is just being called with /signup/in_progress/session/2:

    $this->form_validation->set_rules("your rules");
if ($this->form_validation->run() == FALSE) {
    $this->load->view('signupStage2',array('signup_data'=>$signup_data));
} else {
    $signup_data->save(array_merge(array('ip'=>$_SERVER['REMOTE_ADDR'],'session_id'=>$session_id,'signup_stage' => '3',
    'signup_complete' =>'0'),$this->input->post()),$this->db,$session_id);
    $this->load->helper('url');
    redirect("/signup/in_progress/".$session_id."/3");
};

At the bottom of each view (eg 'signupStage2.php') I have the prev and next buttons:

    <span class="align-left"><p><input type="submit" name="prev" class="big-button"
value="<- Prev" /><input type="submit" name="next" class="big-button"
value="Next ->" /></p></span>