Hi folks,

Great work on the multipage functionality!

I have a bold request, page validation per multipage. At the moment somebody can go trough all the pages and press save. When there are multiple pages with required fields the user is transported to one of the pages with a required field and drupal lists all the missing fields. The problem is that people then have to look trough the other pages for the other missing fields, which aren't highlighted red anymore.
I think the best way to solve this is to validate the fields that are in the current page when somebody presses next.
What do you guys think?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

arbel’s picture

+1 on this.

I also get a strange result when having errors.

the multipage seems to revert to some default and I see the page with "step 1 of 3" when it was disabled in the field group settings.

Idan

bryancasler’s picture

I'm wondering if you could somehow tap into the work done here...
http://drupal.org/project/clientside_validation
http://drupal.org/project/field_validation

dready2011’s picture

Subscribe.
The multipage functionality is awesome, but it would really be great if it would be possible to make a validation occur every time the user clicks next .

gillarf’s picture

I'm very interested in this - even any suggestions for a workaround in the short term.

pixelsweatshop’s picture

Maybe we can tap into this module that was just released http://drupal.org/project/mforms

gillarf’s picture

i managed this in the end by using the clientside validation module (http://drupal.org/project/clientside_validation), and adding my own javascript calls to the jquery plugin within the multipage.js file in Fieldgroup module. Not ideal I know, but it got the job done.

eme’s picture

@gillarf : Would be great if you post your code here so that everybody can benefit from your work and maybe integrate it into one module or the other. Thx.

deepakbs’s picture

Hi,
I have a similar situation but a bit more complex.
I have a Multipage group with Multipages in it. I use the contributed Field Group module to achieve this in Drupal 7.
I need to validate a particular field on click of the Next button.
If the validation fails i need to store the current page fields into the database and redirect the user to a different page
else continue with the next page.
Can someone please tell me how to implement this feature using the Field Group module.
Thx.

gillarf’s picture

@eme sorry, I haven't been on here in a while.

Ok, well firstly, i'm not a great coder, you should be warned. The below approach worked for me, but its a bit scruffy.

Enabling clientside validation module does most of the work, it includes the jquery validation library and i think it posts the error messages.

In fieldgroup module, I edited the multipage.js file and edited the nextpage function.

Inspect the wrapper for the field group to check which one using if or switch statements and then add some extra jquery validation rules (you don't have to add extra rules, but you can if you want to.)


    if (this.wrapper.hasClass('group-personal')) {
    	
    	//rules for address fields
    

    	$("#edit-field-email-address-und-0-email").rules("add", {minlength: 1, required:true, email: true, messages: {
   required: "Please add an email", email: "Please enter a valid email address"} });
   
 

And then for the fields that I wanted to check I triggered the jquery validation like so:

if (!$("#user-register-form").validate().element("#edit-field-email-address-und-0-email")){
    		validated=0;
		}

    	if (!$("#user-register-form").validate().element("#edit-field-forename-und-0-value")){
    		validated=0;
		}

'validated' is just a flag to indicate the clientside validation failed, which is checked at the bottom of the function. it either passes or scrolls to the error messages:

    if (validated==1){
    this.wrapper.next().data('multipageControl').focus();
    }
    else{

    $('html, body').animate({scrollTop:0}, 'slow');
    	
    }

Hope you find this useful - I had to do this for a specific requirement, but i'm sure it could be generalised.

Thanks @animelion for pointing me in the right direction

deepakbs’s picture

Thanks @gillarf, I am sure this solution would work for my scenario.
I have a doubt though,
if we modify the multipage.js directly, wouldn't we lose our changes in the event of any upgrades to the field_group module in future?
Can you please let us know if you have discovered a way to implement the above said logic without losing the changes in the event of an upgrade?
Thx
Deepak

gillarf’s picture

@deepakbs

Yes you are right it would - this was just a quick simple way for me to solve my problem.

I'm sure someone cleverer than me could develop this into the fieldgroup module.

miik4’s picture

Howdy, I was struggling with this issue too and found a way not to put code in multipage.js

1. Create own module and add

function MY_MODULE_form_alter(&$form, $form_state, $form_id) {
	if ($form_id == "FORM_ID") {
		$path = drupal_get_path('module', 'MY_MODULE');
		drupal_add_js($path . '/validations.js');	
	}
}

2. Create validations.js file to the MY_MODULE folder and put this there

(function ($) {
	
        // override nextPage function
	Drupal.multipageControl.prototype.nextPage = function() {
	
            // Group check here, otherwise every pages required fields invoke error.
            if (this.wrapper.hasClass('GROUP-NAME')) {
	       $('input.required').each(function(index) { 
			$(this).rules("add", 
				{ required:true, messages: { required: "field is required."} }
			);		
		});
    
	  	validated = 1;
  	
		$('input.required').each(function(index) {
                        // You might want $("#YOUR-FORM-ID") here instead of just form.
	  		if (!$("form").validate().element(this))
		  		validated = 0;
  		});
        }
  	
	  	if (validated == 1) 
		    this.wrapper.next().data('multipageControl').focus();
	    else
		    $('html, body').animate({scrollTop:0}, 'slow'); 
		    
	} 
})(jQuery);

This actually checks all fields in your form that are required. Not perfect but worked for me :)

gillarf’s picture

Yes of course - much neater. it hadn't occurred to me to override the function.

deepakbs’s picture

@kermaleivos thanks a lot..your solution also worked ...
@gillarf thanks for your time and support..

Stalski’s picture

Status: Active » Needs work

@ kermaleivos Cool. Fact is that input.required won't everything.
1) Is it possible to create a patch?
2) Can you take other elements in consideration? (select, textarea, input.file ... )

Stalski’s picture

I'd like to merge another issue with this one as it is about validation (E.g. required fields).

Quote of #1613454: Multi-page required fields:

One thing I noticed, and it is preventing me from going further for the moment, is that multi-page forms do not appear to check to see if all required fields have been completed before moving on to the next page.
I created a 4 page form that included several required fields. But there doesn't appear to be anything preventing me from going all the way to the end of the form and not filling in any of the required fields. So if a user were to miss a required field he would have to back-track through all the pages to find the missed field.
Is there currently a way to prevent going to the next page until all required fields have been filled in? If not then adding that functionality would make this a truly awesome module.

mrfelton’s picture

Status: Needs work » Needs review

Here is a more generalized version. Someone else please take this and roll into a patch for field_group... I'm run out of time.


(function ($) {

  // Override nextPage function
  Drupal.multipageControl.prototype.nextPage = function() {
    var form = this.wrapper.closest('form');
    if (this.wrapper.hasClass('multipage-pane')) {
      validated = 1;
      $('input.required', this.wrapper).each(function(index) {
        if (!form.validate().element(this)) {
          validated = 0;
        }
      });
    }
    if (validated == 1) {
      this.wrapper.next().data('multipageControl').focus();
    }
    else {
      $('html, body').animate({scrollTop:0}, 'slow');
    }
  }

})(jQuery);

mloigeret’s picture

Does anybody have an idea on how to make this work with radio buttons and checkboxes?

mloigeret’s picture

I went around this issue (radio buttons) by adding this

if (!$("input[name='RADIO-FIELD-NAME']:checked").val()) {
$("#RADIO-FIELD-ID").css('border','solid 2px red');
validated=0;
}
else
$("#RADIO-FIELD-ID").css('border','0px');

I couldn't figure out how to make the validation with rules on radio and checkboxes. It's not super clean but it works!

glarsch’s picture

I'm very glad I stumbled upon this thread as I was looking for this functionality to complete our job application site.

I'm wondering if someone would be able to help me out. I'm using the code from #12 on our site, however it's not working for me. I'm by no means a coder, but I have been messing with Drupal for a few years.

The form I'm looking at is here (adding an application): https://hr.unityhospice.org/jobs/1003-registered-nurse

You can login with test/test in order to "Apply".

Thanks

gillarf’s picture

The error is when validations.js tries to use the Drupal.multipageControl function, which is in the multipage.js file.

I think its to do with you using the modal window, which is in an iframe - it looks like can't access the multipage.js file.

Have you tried it without a modal window?

glarsch’s picture

FileSize
50.51 KB

I disabled and uninstalled the modal forms module and also took away permission to use the administration overlay for authenticated users (I wasn't sure if that would cause issues). I cleared all the caches as well.

I now get the attached firebug error. Any ideas?

***Edit. It seems I fubar'd the whole thing. The JS file was loading before, but now no luck. No idea why.

gillarf’s picture

Well that error implies your code wasn't quite right, but at least it was getting that far.

It now looks like your module is not loading the validation.js file. Has the form ID changed?

I'm pretty sure this is the problem - have you checked that the FORM-ID you set here is set to the right ID? It is likely to be different now you are not using the modal form.

if ($form_id == "FORM_ID")

michlis’s picture

jQuery code provided by mrfelton in #17 works correct, at least if you only need to validate INPUT elements, otherwise make adjustments in this selector:

$('input.required', this.wrapper).each(function(index) {

Keep in mind that you also need client Clientside Validation for this to work and one of it's submodules enabled! I used Clientside Validation Form.

Stalski’s picture

Status: Needs review » Closed (works as designed)

So in fact, this patch is fine and it requires you to use the clientside validation module.

In my opinion, javascript functions are there to override so this is easy to do and it's the best way to achieve custom behavior. I don't think fieldgroup needs to do anything on this matter, since it would need assume too much and take an approach that is even worse.

So I am closing this issue, correct me if I am wrong.

gillarf’s picture

well, i think its a bug for the multipage fieldgroup - i don't think it works properly without this functionality.

Would it help to make the multipage fieldgroup a separate module with a dependency on fieldgroup and clientside validation modules?

Stalski’s picture

Hi gillarf,
It certainly is a good proposition. Let's say a month after I included this, I already knew it was a bad idea to incorporate this in fieldgroup itself.

And now I am scared that's too late (due to difficult upgrade path). It's very difficult to let other people know that they need a new module while upgrading.

gillarf’s picture

What do other modules do when they decouple functionality into separate modules? It seems like it would be a common situation.

TelFiRE’s picture

What about just making it a separate module but include it in the module? Like some modules I get have several components and out of the box you don't have to enable them all.

sinasalek’s picture

Thanks @mrfelton , nice solution.
Here is a more generic one with support for input, select and textarea

(function ($) {

  // Override nextPage function
  Drupal.multipageControl.prototype.nextPage = function() {
    var form = this.wrapper.closest('form');
    if (this.wrapper.hasClass('multipage-pane')) {
      validated = 1;
      $('input.required, select.required, textarea.required', this.wrapper).each(function(index) {
        if (!form.validate().element(this)) {
          validated = 0;
        }
      });
    }
    if (validated == 1) {
      this.wrapper.next().data('multipageControl').focus();
    }
    else {
      $('html, body').animate({scrollTop:0}, 'slow');
    }
  }

})(jQuery);
Juryiel’s picture

I haven't been able to get this to work, help would be appreciated.

I installed Clientside Validation and Clientside Validation Forms

I created and enabled a module with this code:

multipage_per_page_validation.module

<?php
function multipage_per_page_validation_form_alter(&$form, $form_state, $form_id) {
        if ($form_id == "FORM_ID") {
                $path = drupal_get_path('module', 'multipage_per_page_validation');
                drupal_add_js($path . '/validations.js');
        }
}

?>

And validations.js in the multipage_per_page_validation directory

(function ($) {

  // Override nextPage function
  Drupal.multipageControl.prototype.nextPage = function() {
    var form = this.wrapper.closest('form');
    if (this.wrapper.hasClass('multipage-pane')) {
      validated = 1;
      $('input.required, select.required, textarea.required', this.wrapper).each(function(index) {
        if (!form.validate().element(this)) {
          validated = 0;
        }
      });
    }
    if (validated == 1) {
      this.wrapper.next().data('multipageControl').focus();
    }
    else {
      $('html, body').animate({scrollTop:0}, 'slow');
    }
  }

})(jQuery);

Anything obviously wrong?

Note: I also tried replacing FORM_ID with the string in the id attribute in the
tag and it still didn't work.

pixelsweatshop’s picture

No need to write anything custom to get this done. Just use http://drupal.org/project/field_group_ajaxified_multipage

Juryiel’s picture

If you put this in your validations.js it works with checkboxes:

      $('.form-type-checkboxes .require-one', this.wrapper).each(function(index) {
        if (!form.validate().element(this)) {
                validated = 0;
        }
      });

This assumes that the div class and checkbox class match the classes above in the jQuery selector. Also, your checkbox keys cannot have spaces in them, or else you will get multiple validation errors, one for each checkbox that has a space in the key. You can use underscores for the keys, but can still use spaces in the labels so they look like this checkbox_with_spaces|checkbox with spaces. This will only return one validation error if validation fails.

You can do something similar with radio buttons like:

     $('.form-type-radios .form-radio', this.wrapper).each(function(index) {
        if (!form.validate().element(this)) {
                validated = 0;
        }
      });

but I haven't tested it to be sure if this specific code works, but something along these lines will. Also the 'no spaces' rule probably applies.

-enzo-’s picture

Status: Closed (works as designed) » Needs review
FileSize
2.61 KB
24.86 KB

Hello Guys

I tested the module http://drupal.org/project/field_group_ajaxified_multipage but doesn't work properly.

I took the code posted at http://drupal.org/node/1340082#comment-6160826 and include extra validations for radio buttons and checkboxes to create a new patch.

You can see the results in the following image.

Please test the patch for multipage forms to validate and request to the maintainer to include in next release.

astanley86’s picture

Tested patch by -enzo- and it is working!

The patch is dependent on http://drupal.org/project/clientside_validation module.

It did not show validation error for a blank Name field (http://drupal.org/project/name) or for Entity Reference (term reference view).

Original validation text (when trying to save new node on last step):

Name is required.
Shirt Style field is required.
Choose your shirt color field is required.
Size field is required.
Quantity field is required.

and the validation text after applied patch (when trying to go to the next step):

Size field is required.
Quantity field is required.
Error message Shirt field is required.

donaldwbabcock’s picture

I took the custom module approach, but used the Javascript from the patch.

It works to a point. If you are using the Conditional Fields module you need to make sure that you are configuring "required" as a condition, as opposed to on a field settings basis.

The fail safe would be to rewrite the JS code to test for "required" status as well as "visibility". This becomes complicated because for different field types the "display:none;" style attribute is a varying number of parent elements above the element that carries the "required" class.

An effective JS solution would allow compatibility with the conditional fields "required" dichotomy on a "per page" basis.

If I have a spare moment, I will endeavor to expand the JS accordingly, any input anyone wants to add would be appreciated.

Great thread.

donaldwbabcock’s picture

After further testing, using the condition of required via conditional fields creates it's own problems with the per page. More to follow when I have more time to look into it.

donaldwbabcock’s picture

If anyone is following this thread, I wanted to post my progress.My current working solution was a re-write of the jquery selectors.

Instead of authenticating "all" inputs, selects, etc as the prior version of the script does, I have limited it to only those which are ":visible" get the "validate()" applied.

Additionally I wrote js that changes the way the error is cleared. This was necessary as with Conditional Fields you can hide fields on a single mutlipage by changing another fields value. IE you change a select list, and the "errored" field disappears, the error for the field needs to disappear as well.

Additionally I wrote in some code related to "skipping" a multipage if there were no visible fields on the page. This is not related to multipage validation, but is implemented in the "nextPage", "previousPage" functions, and so made it into the code.

I will clean up my code (with and with out page skipping) and post it here, when I get a free moment.

katannshaw’s picture

@donaldwbabcock....: Thanks for your work on this. Is there any news on your progress?

Status: Needs review » Needs work

The last submitted patch, field_group-validation_per_multipage-1340082-34.patch, failed testing.

j3ll3nl’s picture

Issue summary: View changes

Is there any progress on this issue? I need this functionallity so i am going to recreate a working patch when nobody does.

j3ll3nl’s picture

The last submitted patch, 34: field_group-validation_per_multipage-1340082-34.patch, failed testing.

jan.dobbelaere@hp.com’s picture

The last submitted patch, 34: field_group-validation_per_multipage-1340082-34.patch, failed testing.

dariogcode’s picture

I implemented a solutions rewriting the prototype function in a custom module:


(function ($) {
  Drupal.multipageControl.prototype.nextPage = function() {
    if ($('select, input, textarea', this.wrapper).valid()) {
      this.wrapper.next().data('multipageControl').focus();
    }
    $('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top);
  }
})(jQuery);

For the final page, the "submit" button take care because clientside validation settings.

I tried to use selector for specific fields like .form-text, .form-select, but for some reason that didn't work.

johnhanley’s picture

I really wanted to use multipage to create surveys with ECK, but this is not practical without reliable clientside validation.

I am therefore stuck with Webforms for now.

sistro’s picture

Still no solution after 4 years?!

sistro’s picture

For those who need to lock page navigation untill the field is filled and validated I suggest to try Multistep Nodeform https://www.drupal.org/project/msnf instead of field group.

And also I suggest field group developers to provide a system for validation for the multipage or multistep similar to this of the module above... please!

Stalski’s picture

As clientside validation is rather custom, field_group project will not take this into the core project. There is a module taking care of multipage fieldgroups with another approach, see https://www.drupal.org/project/field_group_ajaxified_multipage

As maintainer of Field group I can only add that I made a mistake by creating this multipage inside field group (since we decided in the beginning of fieldgroup that the only goal of the module was to group fields).

So this is most probably never going to happen for D7 nor D8. There are alternatives which are actively maintained.

nils.destoop’s picture

Fieldgroup is idd never gonna add clientside validation on his side. On d8 the multipage was even removed. If people want the multipage in d8, they are welcome to create an extra contrib for it.
The only reason why this topic is still open, is because of the custom code that could be tested when someone is searching documentation for this.

sistro’s picture

Thanks for your answers Stalski and zupperman.

Now things are more clear and I can stop search a valid solution to get per page validation for field group module.

to Stalski: I've read about Field Group Ajaxifield Multipage and I tried to implement a solution with the two modules, but I think that, at least at least in my case and with the latest versions of the two modules, them are incompatible. I had some errors in rendering the page. I did not take "notes" so I can't help you to investigate about it.

Richard15’s picture

I solved in this way:
I added this code (then deleted), to multipage.js to find "who" this.wrapper was:

nextPage: function () {
alert($(this.wrapper).prop("class"));
this.wrapper.next().data('multipageControl').focus();

then I unbinded the Drupal.multipageControl.prototype.nextPage to my next button:

<strong>$(".GROUP_NAME").find("input[type='button']:.multipage-link-next").unbind()</strong>

and finally, after my validation, I added this function to my next button:

$(".GROUP_NAME").find("input[type='button']:.multipage-link-next").on("click", function() {
if (validation)...
else
    $("MULTIPAGE_DIV").next().data('multipageControl').focus();

I hope it could help someone...

historysa’s picture

Modified #46

Added focus to respond to inline errors (defaults to top)

(function ($) {
  Drupal.multipageControl.prototype.nextPage = function() {  

    if ($('select, input, textarea', this.wrapper).valid()) {
      this.wrapper.next().data('multipageControl').focus();
      $('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top);   
    }else{
      $("select.error:first, input.error:first, textarea.error:first").focus(); 
    }    
    
  }  
})(jQuery); 
firewaller’s picture

+1