How to fix radio button validation in jQuery plugin?

I am using a jQuery plugin called Stepy , which is based on FormToWizard so that users can fill out a 10-step form. Stepy integrates with the jQuery Validation plugin.

I ran into a problem if there are several radio buttons in the form, they cause errors and do not allow the user to continue. This happens only after the first switch (the first radio button checks the penalty) and only when there are steps after the switch (if the switch is in the last step, it works fine).

FireBug displays "a is undefined". In addition, this only happens when the Validation plugin is activated ("validate: true").

Looking through the Stepy and jQuery Validate code, I cannot understand why this is happening.

I have a working example: http://jsfiddle.net/5Rd7A/3/

Any ideas?

JavaScript:

$(function() { $('#custom').stepy({ backLabel: 'Backward', block: true, errorImage: true, nextLabel: 'Forward', titleClick: true, validate: true }); }); 

HTML:

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <body> <form id="custom" name="custom"> <fieldset title="Thread 1"> <legend>description one</legend> <label>Question A:</label> <input type="text" id="question_a" name="question_a" class="required"> <label>Question B:</label> <input type="text" id="question_b" name="question_b"> </fieldset> <fieldset title="Thread 2"> <legend>description two</legend> <label>Question C:</label> <input type="text" id="question_c" name="question_c" class="required"> <label>Question D:</label> <input id="answer_d1" type="radio" name="question_d" class="required"> Answer D1 <input id="answer_d2" type="radio" name="question_d" class="required"> Answer D2 </fieldset> <fieldset title="Thread 3"> <legend>description three</legend> <label>Question E:</label> <input type="text" id="question_e" name="question_e" class="required"> <label>Question F:</label> <input id="answer_f1" type="radio" name="question_f" class="required"> Answer F1 <input id="answer_f2" type="radio" name="question_f" class="required"> Answer F2 </fieldset> <fieldset title="Thread 4"> <legend>description four</legend> <label>Question G:</label> <input type="text" id="question_g" name="question_g" class="required"> <label>Question H:</label> <input type="text" id="question_h" name="question_h" class="required"> </fieldset> <input type="submit" class="finish" value="Finish!"> </form><br> </body> </html> 

stepy.js

 ;(function($) { var methods = { init: function(options) { return this.each(function() { var opt = $.extend({}, $.fn.stepy.defaults, options), $this = $(this).data('options', opt), id = $this.attr('id'); if (id === undefined) { id = 'stepy-' + $this.index(); $this.attr('id', id); } var $titlesWrapper = $('<ul/>', { id: id + '-titles', 'class': 'stepy-titles' }); if (opt.titleTarget) { $(opt.titleTarget).html($titlesWrapper); } else { $titlesWrapper.insertBefore($this); } if (opt.validate) { $this.append('<div class="stepy-error"/>'); } var $steps = $this.children('fieldset'), $step = undefined, $legend = undefined, description = '', title = ''; $steps.each(function(index) { $step = $(this); $step .addClass('step') .attr('id', id + '-step-' + index) .append('<p id="' + id + '-buttons-' + index + '" class="' + id + '-buttons"/>'); $legend = $step.children('legend'); if (!opt.legend) { $legend.hide(); } description = ''; if (opt.description) { if ($legend.length) { description = '<span>' + $legend.html() + '</span>'; } else { $.error(id + ': the legend element of the step ' + (index + 1) + ' is required to set the description!'); } } title = $step.attr('title'); title = (title != '') ? '<div>' + title + '</div>': '--'; $titlesWrapper.append('<li id="' + id + '-title-' + index + '">' + title + description + '</li>'); if (index == 0) { if ($steps.length > 1) { methods.createNextButton.call($this, index); } } else { methods.createBackButton.call($this, index); $step.hide(); if (index < $steps.length - 1) { methods.createNextButton.call($this, index); } } }); var $titles = $titlesWrapper.children(); $titles.first().addClass('current-step'); var $finish = $this.children('.finish'); if (opt.finishButton) { if ($finish.length) { var isForm = $this.is('form'), onSubmit = undefined; if (opt.finish && isForm) { onSubmit = $this.attr('onsubmit'); $this.attr('onsubmit', 'return false;'); } $finish.click(function(evt) { if (opt.finish && !methods.execute.call($this, opt.finish, $steps.length - 1)) { evt.preventDefault(); } else { if (isForm) { if (onSubmit) { $this.attr('onsubmit', onSubmit); } else { $this.removeAttr('onsubmit'); } var isSubmit = $finish.attr('type') == 'submit'; if (!isSubmit && (!opt.validate || methods.validate.call($this, $steps.length - 1))) { $this.submit(); } } } }); $finish.appendTo($this.find('p:last')); } else { $.error(id + ': element with class name "finish" missing!'); } } if (opt.titleClick) { $titles.click(function() { var array = $titles.filter('.current-step').attr('id').split('-'), // TODO: try keep the number in an attribute. current = parseInt(array[array.length - 1], 10), clicked = $(this).index(); if (clicked > current) { if (opt.next && !methods.execute.call($this, opt.next, clicked)) { return false; } } else if (clicked < current) { if (opt.back && !methods.execute.call($this, opt.back, clicked)) { return false; } } if (clicked != current) { methods.step.call($this, (clicked) + 1); } }); } else { $titles.css('cursor', 'default'); } $steps.delegate('input[type="text"], input[type="password"]', 'keypress', function(evt) { var key = (evt.keyCode ? evt.keyCode : evt.which); if (key == 13) { evt.preventDefault(); var $buttons = $(this).parent().children('.' + id + '-buttons'); if ($buttons.length) { var $next = $buttons.children('.button right-aligned'); if ($next.length) { $next.click(); } else { var $finish = $buttons.children('.finish'); if ($finish.length) { $finish.click(); } } } } }); $steps.first().find(':input:visible:enabled').first().select().focus(); }); }, createBackButton: function(index) { var $this = this, id = this.attr('id'), opt = this.data('options'); $('<a/>', { id: id + '-back-' + index, href: 'javascript:void(0);', 'class': 'button left-aligned', html: opt.backLabel }).click(function() { if (!opt.back || methods.execute.call($this, opt.back, index - 1)) { methods.step.call($this, (index - 1) + 1); } }).appendTo($('#' + id + '-buttons-' + index)); }, createNextButton: function(index) { var $this = this, id = this.attr('id'), opt = this.data('options'); $('<a/>', { id: id + '-next-' + index, href: 'javascript:void(0);', 'class': 'button right-aligned', html: opt.nextLabel }).click(function() { if (!opt.next || methods.execute.call($this, opt.next, index + 1)) { methods.step.call($this, (index + 1) + 1); } }).appendTo($('#' + id + '-buttons-' + index)); }, execute: function(callback, index) { var isValid = callback.call(this, index + 1); return isValid || isValid === undefined; }, step: function(index) { index--; var $steps = this.children('fieldset'); if (index > $steps.length - 1) { index = $steps.length - 1; } var opt = this.data('options'); max = index; if (opt.validate) { var isValid = true; for (var i = 0; i < index; i++) { isValid &= methods.validate.call(this, i); if (opt.block && !isValid) { max = i; break; } } } $steps.hide().eq(max).show(); var $titles = $('#' + this.attr('id') + '-titles').children(); $titles.removeClass('current-step').eq(max).addClass('current-step'); if (this.is('form')) { var $fields = undefined; if (max == index) { $fields = $steps.eq(max).find(':input:enabled:visible'); } else { $fields = $steps.eq(max).find('.error').select().focus(); } $fields.first().select().focus(); } if (opt.select) { opt.select.call(this, max + 1); } return this; }, validate: function(index) { if (!this.is('form')) { return true; } var $step = this.children('fieldset').eq(index), isValid = true, $title = $('#' + this.attr('id') + '-titles').children().eq(index), opt = this.data('options'), $this = this; $($step.find(':input:enabled').get().reverse()).each(function() { var fieldIsValid = $this.validate().element($(this)); if (fieldIsValid === undefined) { fieldIsValid = true; } isValid &= fieldIsValid; if (isValid) { if (opt.errorImage) { $title.removeClass('error-image'); } } else { if (opt.errorImage) { $title.addClass('error-image'); } $this.validate().focusInvalid(); } }); return isValid; } }; $.fn.stepy = function(method) { if (methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === 'object' || !method) { return methods.init.apply(this, arguments); } else { $.error('Method ' + method + ' does not exist!'); } }; $.fn.stepy.defaults = { back: undefined, backLabel: '&lt; Back', block: false, description: true, errorImage: false, finish: undefined, finishButton: true, legend: true, next: undefined, nextLabel: 'Next &gt;', titleClick: false, titleTarget: undefined, validate: false, select: undefined }; })(jQuery); 
+4
source share
2 answers

Hello Michael and graphic,

This is a problem inside jQuery Validation 1.9, which by default ignores : hidden fields as a new function, but returns undefined. Then undefined is used along the code and is interrupted when it is used. We have many questions about returning undefined, and this time tried to avoid hacking jQuery Stepy and fix it [1] in jQuery Validation 1.9.

Regardless of this bug fix, we must undo the hidden fields of the ignore (jQuery Validation) option because the titleClick (jQuery Stepy) option also checks for hidden steps, since you can skip steps without presenting them.

You can use the previous version [2] without this error or use the fixed version [3], which is not yet official.

[1] https://github.com/jzaefferer/jquery-validation/pull/263
[2] http://ajax.aspnetcdn.com/ajax/jquery.validate/1.8/jquery.validate.js
[3] github.com/wbotelhos/jquery-validation

+4
source

I do not know, but by switching the order of questions, the error remains on the second set of radio stations. Thus, it seems that your code is in order, and it is either Stepy or Validator (or the connection between them) that are at fault.

http://jsfiddle.net/yBEsM/

EDIT

It seems that the error is triggered by entering the 4th set of fields, and not because of the third.

EDIT

... and accepting all the "necessary" s still raises an error, so I guess the problem is with Stepy.

http://jsfiddle.net/4KEsg/

EDIT

... although the FALSE stepy VALIDATE parameter also solves the problem.

EDIT

With confirmation enabled, one switch is enough: http://jsfiddle.net/5n5BA/1/

+1
source

Source: https://habr.com/ru/post/1383089/


All Articles