Hey guys i am using Jquery validation plugin ,
I have to create a form which has dynamic generated fields like input boxes, select box and checkbox so it works perfectly on other elements of my form but not works for dynamic generated checkboxes
Check out the snapshot below
for this my jquery validate code is
var educationFormValidator = $("#educationForm").validate({
rules:function(){
var primaryEducationRules = new Object();
$('.is_primary').each(function() {
primaryEducationRules[this.name] = {
require_from_group: [1, ".is_primary"],
required:true
};
});
console.log(primaryEducationRules);
return primaryEducationRules;
},
messages:function(){
var messages = new Object();
$('.is_primary').each(function() {
messages[this.name] = { required: 'Please select relevant qualification' };
});
console.log(messages);
return messages;
},
submitHandler: function(form) {
form.submit();
},
invalidHandler: function() {
console.log( educationFormValidator.numberOfInvalids() + " field(s) are invalid" );
}
});
javascript function which generates dynamic check boxes
function addEducation (educationCount) {
var educationDiv = '<div class="inputRow_'+educationCount+'"><hr><br>';
educationDiv += addInstituteNameDiv (educationCount);
educationDiv += addBatchYears (educationCount);
educationDiv += addCourseType (educationCount);
educationDiv += addDegreeTypeDiv (educationCount);
educationDiv += addAddDegreeButton (educationCount);
educationDiv += '</div>';
$('.multiple-education').append(educationDiv);
//addYearsInOption(educationCount);
if(educationCount!=1){
$('#deleteDegreeBtn_'+(parseInt(educationCount)-1)).css("display","block");
$('#deleteDegreeBtn_'+educationCount).css("display","block");
}
$('#addDegreeBtn_'+ (parseInt(educationCount)-1)).css("display","none");
}
function addInstituteNameDiv (educationCount) {
var instituteNameDiv = '<div class="form-group" id="instituteName'+educationCount+'">';
instituteNameDiv += '<label style="padding-left:0;" class="col-md-2 col-sm-2 control-label" for="textinput">Institute</label>';
instituteNameDiv += '<div class="col-md-6 col-sm-6">';
instituteNameDiv += '<input name="From['+educationCount+'][otherInstitute]" class="form-control input-md" type="text" required id="instituteName_'+educationCount+'">';
instituteNameDiv += '</div>';
instituteNameDiv += '<!--<div class="col-md-1 col-sm-2"><span name="reset_'+educationCount+'" id="reset_institute_'+educationCount+'" class="suggestion-reset greentxt mt7 pull-left">Edit</span></div>-->';
instituteNameDiv += '<div class="checkbox col-md-3 col-sm-2 pdl0 col-xs-12 edu-message">';
instituteNameDiv += '<label style="padding-left:0;" for="checkboxes-0">';
instituteNameDiv += '<input class="is_primary" name="From['+educationCount+'][is_primary]" id="is_primary_'+educationCount+'" value="1" type="checkbox" onclick="setImportantEducation('+educationCount+')">';
instituteNameDiv += '<span name="primary_edu_'+educationCount+'" id="primary_edu_'+educationCount+'">This is my most relevant / important educational qualification</span>';
instituteNameDiv += '</label>';
instituteNameDiv += '</div>';
instituteNameDiv += '</div>';
return instituteNameDiv;
}
All fields are mandatory in form if it is generated but user have to select at least 1 relevant education out of many educations fields
for the help i have read this link too
you aren't calling addInstituteNameDiv() in your script. Also, addInstituteNameDiv() should appear before the validater call.
Try
jQuery.validator.addMethod("isprimary", function (value, element) {
return $('.is_primary:checked').length == 1;
}, "Please select 1");
$.validator.addClassRules("is_primary", {
isprimary: true
});
var educationFormValidator = $("#educationForm").validate({
submitHandler: function (form) {
form.submit();
},
invalidHandler: function () {
console.log(educationFormValidator.numberOfInvalids() + " field(s) are invalid");
},
errorPlacement: function (label, element) {
if (element.hasClass('is_primary')) {
element.parent().append(label)
} else {
label.insertAfter(element);
}
}
});
Demo: Fiddle
The accepted answer works, however, it contains some unnecessary code.
Eliminate .addClassRules():
You do not need the .addClassRules() method for simply applying a custom rule using a class. The .addClassRules() method is intended for creating a "compound" rule, which is not the case here.
If, for whatever reason, you wanted to create a custom rule, the custom rule can be applied directly as a class. There is no need for .addClassRules().
<input class="my_custom_rule" ...
DEMO: http://jsfiddle.net/m52ga6ex/12/
Related
This is my JavaScript code:
var data = data.Data;
var html = "";
for(var i = 0; i<data.length;i++){
html = html +'<div class="form-group">'+
'<label class="control-label col-lg-2">Hasil Rapat</label>'+
'<div class="col-lg-10">'+
'<textarea rows="20" id="rapat" class="form-control rapat" name="hasil_rpt">'+data[i].hasil_rpt+'</textarea>'+
'</div>'+
'</div>'
}
I have included the id on the textarea:
<textarea rows="20" id="rapat" class="form-control rapat" name="hasil_rpt">'+data[i].hasil_rpt+'</textarea>
And I also already use:
CKEDITOR.replace('rapat');
The first red flag I see is that CKEditor isn't going to know how to use your logic. I'm not sure which version of CKEditor you're using as things have drastically changed in v5. But, I think what you need to do is this:
var data = data.Data;
var html = "";
for(var i = 0; i<data.length;i++) {
var id = 'editorId_' + i;
html = html +'<div class="form-group">'+
'<label class="control-label col-lg-2">Hasil Rapat</label>'+
'<div class="col-lg-10">'+
'<textarea rows="20" id="'+ id + '" class="form-control rapat" name="hasil_rpt">'+data[i].hasil_rpt+'</textarea>'+
'</div>'+
'</div>';
CKEDITOR.replace(id);
}
I'm not sure where you are calling CKEDITOR.replace from, but it should be either within the for loop or in a separate loop after you have completed the loop that adds your html to the DOM. The reason why your code isn't working is because you end up with multiple id's and id's are supposed to be unique. CKEDITOR is tripping over that more than likely.
EDIT
The above code isn't going to work since CKEDITOR needs your element reference to be present (and rendered) within the DOM. Once that element is ready, you can then call CKEDITOR.replace. A similar flow to this might work:
var data = data.Data;
var parentElement = ''; // <-- Get the reference to your container element here
for(var i = 0; i<data.length;i++) {
var id = 'editorId_' + i;
var html +'<div class="form-group">'+
'<label class="control-label col-lg-2">Hasil Rapat</label>'+
'<div class="col-lg-10">'+
'<textarea rows="20" id="'+ id + '" class="form-control rapat" name="hasil_rpt">'+data[i].hasil_rpt+'</textarea>'+
'</div>'+
'</div>';
parentElement.appendChild(html);
CKEDITOR.replace(id);
}
Picture above shows snippets of Furnitures table. The user will key-in their desired reference number in ReferenceNum field. The problem is, the data itself have slash(/). Everytime the user try to submit the value, my url became MyWebsite.com/Furniture/PriceList/Ref/3/Case2, thus the website couldnt find the website.
View
<div class="form-group row">
<label class="control-label col-md-2">Reference Number</label>
<div class="col-md-8">
<input type="text" class="form-control" id="RefNum" />
</div>
<div class="col-md-2">
<input class="btn btn-success" id="getReference" value="Find"/>
</div>
</div>
<p id="rData">
</p>
JS
<script type="text/jscript">
$('#getReference').click(function () {
$.getJSON('/Furniture/PriceList/' + $('#RefNum').val(), function (data) {
var items = '<table><tr><th>Name</th><th>Reference Number</th></tr>';
$.each(data, function (i, lists) {
items += "<tr><td>" + lists.ItemName + "</td><td>" + lists.ReferenceNum + "</td></tr>";
});
items += "</table>";
$('#rData').html(items);
});
})
Controller
public JsonResult PriceList(string id)
{
var result = db.Furnitures.Where(x => x.ReferenceNum == id);
return Json(result, JsonRequestBehavior.AllowGet);
}
You can add the result as a query string value, rather than a route value
$('#getReference').click(function () {
$.getJSON('/Furniture/PriceList?id=' + $('#RefNum').val(), function (data) {
or
$('#getReference').click(function () {
$.getJSON('#Url.Action("PriceList", "Furniture")', { id: $('#RefNum').val() }, function (data) {
You can use %2F to escape slash(/) character in URL.
So updated JS code will be:
<script type="text/jscript">
$('#getReference').click(function () {
$.getJSON('/Furniture/PriceList/' + $('#RefNum').val().replace(/\//g,'%2F'), function (data) { //<--- Fix
var items = '<table><tr><th>Name</th><th>Reference Number</th></tr>';
$.each(data, function (i, lists) {
items += "<tr><td>" + lists.ItemName + "</td><td>" + lists.ReferenceNum + "</td></tr>";
});
items += "</table>";
$('#rData').html(items);
});
})
I have a couple of inputs like so:
<input name="education[1][yearbegin]" type="date" class="form-control">
<input name="education[2][yearbegin]" type="date" class="form-control">
The data is sent to my server to be verified, and if it's invalid it sends back data like so:
{
"education.0.institution":["The education.0.institution field is required."],
"education.0.degree":["The education.0.degree field is required."]
}
I don't always get more than 1 back, sometimes it could be many I am trying to loop over to append an error to the input like so:
var errors = $.parseJSON(data.responseText);
alertHtml += '<ul>';
$.each(errors, function (key, value) {
$('.form-control[name=' + key + ']').closest('.form-group').addClass('has-error');
alertHtml += '<li>' + value + '</li>';
});
alertHtml += "</ul>";
This doesn't work though, because it's trying to find the input name of:
education.1.yearbegin
Rather than
education[1]yearbegin
My inputs won't always be arrayed, but the ones that are don't append How can I append the error message to the input by changing the javascript? The json is being sent back by Laravel's array validation
It's unfortunate that the server accepts the names in one form but sends them back in another.
If we assume that dot syntax should always be converted to brackets syntax, it's fairly straightforward to update the keys:
var updated = key.split(".");
if (updated.length == 1) {
updated = updated[0];
} else {
updated = updated[0] + "[" + updated.slice(1).join("][") + "]";
}
For multi-part keys, that inserts [ before the second and ][ in-between the second and third, third and fourth, etc.; and adds ] at the end.
Example:
var errors = [
{"education.1.yearbegin":["The education.1.yearbegin field is required."]},
{"education.2.yearbegin":["The education.2.yearbegin field is required."]}
];
errors.forEach(function(error) {
Object.keys(error).forEach(function(key) {
var updated = key.split(".");
if (updated.length == 1) {
updated = updated[0];
} else {
updated = updated[0] + "[" + updated.slice(1).join("][") + "]";
}
console.log("Original: " + key + ", updated: " + updated);
});
});
If you're also struggling with showing all of the errors in the array next to the form control, you just loop through them. You're receiving an object where the property names in the object are the form control names, and the values are arrays of error messages. So we
Loop through the property names of that object, and for each property name:
Mark the relevant control, and
Loop through that entry's array of errors to append them to alertHtml.
Something long these lines:
var errors = {
"education.1.yearbegin":["The education.1.yearbegin field is required."],
"education.2.yearbegin":["The education.2.yearbegin field is required."]
};
function fixKey(key) {
var updated = key.split(".");
if (updated.length == 1) {
updated = updated[0];
} else {
updated = updated[0] + "[" + updated.slice(1).join("][") + "]";
}
return updated;
}
var alertHtml = '<ul>';
// #1: Loop through the object's property names
Object.keys(errors).forEach(function(key) {
// #2: Mark the control, using the corrected name
$('.form-control[name="' + fixKey(key) + '"]').closest('.form-group').addClass('has-error');
// #3: Loop through the errors
errors[key].forEach(function(msg) {
alertHtml += '<li>' + msg + '</li>';
});
});
alertHtml += "</ul>";
$(document.body).append(alertHtml);
.has-error {
border: 1px solid red;
}
<div class="form-group">
<input name="education[1][yearbegin]" type="date" class="form-control">
</div>
<div class="form-group">
<input name="education[2][yearbegin]" type="date" class="form-control">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The first issue with the name:
I would just change the name to something that's a bit easier to read rather then having it like:
name="education[1][yearbegin]"
Maybe have it like:
name="EducationYearBegin1"
For the second issue:
You could check if the property is an array, so like this:
if (value instanceof Array) {
value.forEach(function (item) {
alertHtml += '<li>' + item + '</li>';
})
} else {
alertHtml += '<li>' + value + '</li>';
}
Maybe something like that?
The foreach would cover you if you ever had multiple errors in your array too.
You can use String#replace to convert education.1.yearbegin to be education[1][yearbegin]
See fixName function in this code.
function fixName(name) {
var newName = name.replace(/\.\d\./, function ($1) {
return "[" + $1.replace(/\./g, "") + "]"
}).replace(/\].+/, function ($1) {
return $1.replace(/\]/, "][") + "]"
});
return newName;
}
var errors = [{"education.1.yearbegin":["The education.1.yearbegin field is required."]},
{"education.2.yearbegin":["The education.2.yearbegin field is required."]}]; //$.parseJSON(data.responseText);
var alertHtml = document.querySelector("#alert");
alertHtml.innerHTML += '<ul>';
$.each(errors, function (key, obj) {
var realKey = fixName(Object.keys(obj)[0]);
$('.form-control[name="'+ realKey +'"]').addClass('has-error');
alertHtml.innerHTML += '<li>' + obj[Object.keys(obj)[0]][0] + '</li>';
});
alertHtml.innerHTML += "</ul>";
.has-error {
color: red;
}
li {
color: green
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input name="education[1][yearbegin]" type="date" class="form-control">
<input name="education[2][yearbegin]" type="date" class="form-control">
<div id="alert"></div>
Currently the date and year is being verified but I would like to add a checkbox to the list.
Form code:
var html = '';
html += '<div class="ac-overlay"></div>';
html += '<div class="ac-container">';
html += '<h2>' + settings.title + '</h2>';
html += '<p>' + copy.replace('[21]','<strong>'+settings.minAge+'</strong>'); + '</p>';
html += '<div class="errors"></div>';
html += '<div class="fields"><select class="month">';for(var i=0;i<months.length;i++){
html += '<option value="'+i+'">'+months[i]+'</option>'}
html += '</select>';
html += '<input class="day" maxlength="2" placeholder="01" />';
html += '<input class="year" maxlength="4" placeholder="2016"/>';
html +="<br><br>";
html +='<p><input class="smoker" type="checkbox"/>Please verify that you are a smoker.</p>';
html +="<br>";
html += '<button>Submit</button></div></div>';
Validation script:
validate : function(){
_this.errors = [];
if (/^([0-9]|[12]\d|3[0-1])$/.test(_this.day) === false) {
_this.errors.push('Day is invalid or empty');
};
if (/^(19|20)\d{2}$/.test(_this.year) === false) {
_this.errors.push('Year is invalid or empty');
};
_this.clearErrors();
_this.displayErrors();
return _this.errors.length < 1;
},
I played around a bit with the following code but something is missing:
if ("Not sure what to enter here to validate the checkbox.".test(_this.smoker) === false) {
_this.errors.push('You have not selected if you are a smoker');
};
Was a bit of a work around but ended up changing the Checkbox to enable and disable the verify button.
$(document).ready(function(){
$('#isAgeSelected').change(function(){
if(this.checked)
$('#autoUpdate').fadeIn('slow');
else
$('#autoUpdate').fadeOut('slow');
});
});
html +="<br><br>";
html += '<p><input type="checkbox" id="isAgeSelected"/> Please verify the date above is correct.';
html += '<div id="autoUpdate" class="autoUpdate" style="display:none"><button>Submit</button></div>';
html += '</div></div>';
See how it works here: http://jsfiddle.net/3WEVr/1135/
I need to build a search form with Select2 but I have problems getting it to work right.
The user enters the search term into the field which populates suggestions via AJAX. A click on the suggestions brings him to the page. Otherwise he needs to click on the submit button / or press enter, to get to the extended search. The last point (click on the submit button) doesn't work.
<form action="/search" method="get" class="form-search" id="global_search_form">
<div class="input">
<input type="text" name="q" class="search-query" id="global_search" placeholder="Enter search term ...">
<button type="submit" class="btn">Search</button>
</div>
</form>
<script type="text/javascript">
jQuery("#global_search").select2({
placeholder: "Enter search term ...",
minimumInputLength: 2,
multiple: 1,
containerCssClass: 'search-query',
ajax: {
url: 'remoteGlobalSearch',
dataType: 'jsonp',
quietMillis: 100,
data: function (term, page) {
return {
q: term,
per_page: 10,
page: page
};
},
results: function (data, page) {
var more = (page * 10) < data.total;
return {
results: data.items,
more: more
};
}
},
formatResult: itemFormatResult,
formatSelection: itemFormatSelection,
escapeMarkup: function (m) {
return m;
}
});
function itemFormatResult(item) {
var markup = '<table class="item-result"><tr>';
if (item.image !== undefined) {
markup += '<td class="item-image"><img src="' + item.image + '" /></td>';
}
markup += '<td class="item-info"><div class="item-type">' + item.type_string + '</div>';
markup += '<div class="item-title">' + item.title + '</div>';
markup += '<div class="item-description">' + item.description + '</div>';
markup += '</td></tr></table>';
return markup;
}
function itemFormatSelection(item) {
location.href = item.url;
}
</script>
Cheers
I think there is a compatibility issue with button, type=submit and how various browsers interpret it.
Have you tried to use
<input type="submit" value="Search">
instead of the button tag?
Or, if you really need to use the button tag, then I would recommend having something as:
<button type="button" class="btn" onclick="this.form.submit()">Search</button>
Did this solve your problem?
Cheers!