Glitch in my autocomplete to show jquery validation error? - javascript

Hope this question is usefull.
In my autocomplete success I make my input hidden value 1 to avoid
jquery validation and append the current customer name to the
particular input field and all are working fine.
My glitch is if supposed user manually delete the value of input field
which have current customer name, I want to show jquery validation
error. But how can I show that??. Because In my autocomplete success I
made the hidden value 1. So its failed to show the error and I cant check that in keyup or keydown function, Beacuse using that input id I already written the autocomplete.
$(document).ready(function() {
$("#apendexistingCustomer").autocomplete({
autoFocus: true,
source: '{{ url("/getexistingcustomer") }}',
minLength: 2,
select: function(event, ui) {
event.preventDefault();
if (ui.item.label == 'This customer is not in our records.') {
$('#apendexistingCustomer').val('');
$('#existcustomers').val('');
$('#create').valid();
swal("This customer is not in our records.", "", "warning");
} else {
$('#apendexistingCustomer').val(ui.item.label);
$('#existcustomers').val(ui.item.key);
$('#create').valid();
getCustomerDet(ui.item.key);
}
},
focus: function(event, ui) {
selectFirst: true;
event.preventDefault();
},
open: function(event, ui) {
$(this).autocomplete("widget")
.appendTo("#results").css({
'position': 'static',
'width': '100%'
});
$('.ui-autocomplete').css('z-index', '9999999');
$('.ui-autocomplete').addClass('srchuser-dropdown');
}
}).data("ui-autocomplete")._renderItem = function(ul, item) {
return $("<li style='height:60px;'><span class='srchuser-downname'>" + item.label + "</span></li>").data("ui-autocomplete-item", item).appendTo(ul);
};
});
this is my function to fetch customer details using autocomplete
protected function getexistingcustomer() {
if (Request::ajax()) {
$data = Request::all();
$searchVal = $data['term'];
if ($searchVal != '') {
$searchResult = customers::searchCustomerAutoComplete(trim($searchVal));
}
$finalArr = array();
if (!empty($searchResult)) {
foreach($searchResult as $vk => $sf) {
$finalArr[$vk]['label'] = $sf['firstname'].
''.$sf['lastname'];
$finalArr[$vk]['key'] = 1;
}
} else {
$finalArr[0]['label'] = 'This customer is not in our records.';
}
print json_encode($finalArr);
exit;
}
}
customer Input field
<div class="row" id="selectcusDiv">
<div class="col-12 col-sm-6 col-md-4">
<div class="form-group">
<label><sub>*</sub>Customers</label>
<div class="select-container">
<input type="text" id="apendexistingCustomer" name="apendexistingCustomer" class="form-control fieldcls">
<input type="hidden" id="existcustomers" name="existcustomers" value="" class="form-control fieldcls">
</div>
</div>
</div>
</div>
Jquery Validation
$('#create').validate({
ignore: [],
rules: {
existcustomers: 'required'
},
messages: {
existcustomers: 'please enter'
}
});

In your javascript add a change listener to the autocomplete element, and check for an empty value. If the value is empty, set the "avoid validation" flag hidden input to 0, then use a required validation rule on that element.
$("#apendexistingCustomer").on("change", function(){
if($(this).val() == ""){
$("#validateFlag").val(0)
}
});

Related

jQuery UI AutoComplete - How to handle multiple values ,when user removes a value in between the selected values

This is What I have :
I have a text box input element as below for loading cities autoloaded and a hidden field to list its ids:
<label class="col-sm-2 control-label" for="city_disp"> City</label>
<div class="col-sm-5">
<div class="input-group">
<input type="hidden" class="hidden_value" name="city" id="city" value="" />
<input type="text" name="city_disp" placeholder="City"
id="city_disp" data-request_type="cities" value=""
class="form-control autocomplete-input-field" autocomplete="off" />
</div>
</div>
jQuery UI AutoComplete which I use, the data array comes from Ajax response :
function split( val ) {
return val.split( /,\s*/ );
}
function extractLast( term ) {
return split( term ).pop();
}
$(".autocomplete-input-field").autocomplete({
source: function (request, response) {
$this = this.element;
var term = extractLast(request.term);
$.ajax({
url: myHome+'/my_ajax',
dataType: "json",
type: "POST",
data: {
term: term,
action_type: "getdata"
},
success: function (data) {
response(data);
}
});
},
minLength: 2,
select: function (event, ui) {
var tempval = $(this).val() ;
var terms = split( this.value );
var split_string = split(
$(this).closest('div').find('.hidden_value').val() );
split_string.pop();
terms.pop();
terms.push( ui.item.label );
split_string.push( ui.item.value );
terms.push( "" );
split_string.push( "" );
var labels = terms.join( ", " );
var new_vals = split_string.join( "," );
$(this).val(labels);
$(this).closest('div').find('.hidden_value').val(new_vals);
return false;
},
focus: function (event, ui) {
event.preventDefault();
}
});
Output I am getting currently:
Currently,autocomplete is working fine when I type atleast 2 characters in the text box name="city_disp" . If user selects 3 values from the autocomplete cities list: 'New York,Washington,London' and the ids corresponding to these cities '45,56,78' gets appended to the hidden html input field name="city".
Modification which I am trying to implement :
Suppose if user selects 'New York,Washington,London' and its id gets '45,56,78' gets appended to the hidden html input field name="city". and the user removes a Washington from the selected values . Then the hidden value must also change accordingly to '45,78'. Also when a user omits Washington to some absurd characters like 'dasdsad' ,then how to handle such situations with this jQuery UI AutoComplete?
There is not a good way to do this with two unique lists of text. there becomes no relationship between the two except for the positioning. When the User removes and item from List A, how do you identify in List B the change, and align the lists.
Consider moving the selected items to a new User interface with the ID attached.
Example: https://jsfiddle.net/Twisty/m3vfk0hg/
HTML
<label class="col-sm-2 control-label" for="city_disp"> City</label>
<div class="col-sm-5">
<div class="input-group">
<input type="hidden" class="hidden_value" name="city" id="city" />
<input type="text" name="city_disp" placeholder="City" id="city_disp" data-request_type="cities" class="form-control autocomplete-input-field" autocomplete="off" />
</div>
<div class="selected"></div>
</div>
Mostly the same HTML, yet now we have a section to display the Selected items, after they have been selected.
CSS
.selected {
margin: 3px;
}
.selected-item {
border: 1px solid #00f;
border-radius: 6px;
padding: 3px;
background: #ccf;
margin: 3px;
}
.selected-item .btn-close {
margin-left: 6px;
}
Giving us some Style.
JavaScript
$(function() {
var myAutoData = [{
label: "New York",
value: "45"
}, {
label: "Washington",
value: "56"
},
{
label: "London",
value: "78"
}
];
function newItem(it) {
var item = $("<span>", {
class: "selected-item",
"data-id": it.value
}).html(it.label);
$("<span>", {
class: "btn-close"
}).appendTo(item);
if ($("#city").val().length > 0) {
$("#city").val($("#city").val() + "," + it.value);
} else {
$("#city").val(it.value);
}
return item;
}
$(".autocomplete-input-field").autocomplete({
source: function(request, response) {
var term = request.term;
$.ajax({
url: "/echo/json/",
dataType: "json",
type: "POST",
data: {
json: JSON.stringify(myAutoData),
term: term
},
success: function(data) {
response(data);
}
});
},
minLength: 2,
select: function(event, ui) {
$(this).parent().parent().find(".selected").append(newItem(ui.item));
$(this).val("");
return false;
},
focus: function(event, ui) {
event.preventDefault();
}
});
$(".selected").on("click", ".btn-close", function() {
var id = $(this).parent().data("id");
$(this).parent().remove();
var sel = $("#city").val().split(",");
sel = sel.splice(sel.indexOf(id), 1);
$("#city").val(sel.join(","));
});
});
The example uses the JSFiddle options to Echo back JSON data Posted to it. You will want to use your own url and data. I also setup some basinc exmaple items based on your post.
When the User types in a option, wash, they get options they can select. When they click on a selection a new item is created.
<span class="selected-item" data-id="56">Washington<span class="btn-close"></span></span>
This element is appended to the .selected element. This help prevent the user from entering dasdsad, this would return no results, and they cannot select anything.
If the User decides to remove a previously selected item, they click the x and it is removed. Behind the scene, as they make selections, the value of #city is updated to a list of IDs, 56,45. When the User removes an item, the list is updated, and that entry is removed. This is done by converting the list into an Array and using Splice to remove the matching element.

Hide/Show an element automatically( not using a keyup() or click ) when an input field is entered/selected a value

I have an <input> tag in my form that takes a value from Bootstrap Datepicker.
<div class="wrapper">
<div class="form-group">
<label>Select Date</label>
<div class="input-group">
<input name="date_info" type="text" class="form-control datepick validate_date" placeholder="Date" readonly>
</div>
<small class="validate_date_error">This field is mandatory!</small>
<small class="validate_date_success">This is Fine!</small>
</div>
<button class="next">Next</button>
</div>
I'm trying to achieve a functionality as in, On click of .next button, if date is not selected or is empty, I'm displaying .validate_date_error.
If date is selected, without a click or [Enter] key, I want to show .validate_date_success.
Following is my JS
$(function() {
$('.datepick').datepicker({
autoclose: true,
format: 'dd-mm-yyyy'
});
});
$(".next").click( function() {
var check_date = $(".validate_date").val();
if( check_date === "" ){
$(this).parent().find('.validate_date_error').show();
}else {
$(this).parent().find('.validate_date_error').hide();
$(this).parent().find('.validate_date_success').show();
}
});
If anyone could solve this for me, it'll be of gret help.
I have updated my code here JS Fiddle
On selecting a value from datepicker, you can use the onchange event,
$('input[name=date]').change(function() {
var check_date = $(".validate_date").val();
$('.validate_date_error').hide();
if(check_date === ""){
$('.validate_date_success').hide();
}else{
$('.validate_date_success').show();
}
});
Hope this solves your problem.
You should use the function change given by JQuery. This function is called everytime the value in an input changed, so it is perfect for you.
You could do something like this, first of all set an id in your input something like that :
<input id="date" name="date_info" type="text" class="form-control datepick validate_date" placeholder="Date" readonly>
then in you js file add the change method :
$('#date').change(function () {
if($(this).val() !== '') //If a date had been picked
{
//show success message
}
else
{
//show error message
}
})
Of course this is the basic, you can improve the condition to fit as much as you want.
Here is your fiddle http://jsfiddle.net/zNbUT/750/
Hope it helps you
How about this, using the .on(event, callback) method
$(function() {
$('.datepick').datepicker({
autoclose: true,
format: 'dd-mm-yyyy'
});
});
$("input[name='date']").on('change', function (e) {
if (e.target.value) {
$('.validate_date_error').hide();
$('.validate_date_success').show();
} else {
$('.validate_date_error').show();
}
})
$(".next").click( function() {
var check_date = $(".validate_date").val();
if( check_date === "" ){
$(this).parent().find('.validate_date_error').show();
}else {
$(this).parent().find('.validate_date_error').hide();
$(this).parent().find('.validate_date_success').show();
}
});

to add a custom rule in validator to check <ul> has element

I want to check whether my <ul> has children or not while submitting a form.
Here is my html below:
<form>
/*other input elements*/
<div class="attributes-added">
<ul name = "attributesAddedList">
// by default no element is present
</ul>
<input type = "submit" value = "save"> </div>
</form>
As you can see the provided ul has children (<li>) by default. User need to add them dynamically which is not an issue.
But what i need is when i submit the form it should check whether the ul has children or not in the jQuery validator using custom function.
I have tried the validator like below but no fruitful outcome yet.
$("#templateForm").validate({
rules: {
attributesAddedList:{
addedCategory: $(".attributes-added ul").has("li").length
}
},
message: {
attributesAddedList:{
addedCategory: "the message"
}
}
});
Now for custom function
$.validator.addMethod("addedCategory", function(value, element, len) {
if(len < 0){
return false;
}
}, "choose a category");
Any help?
I used a hidden input to add a rule,
but i would suggest using the submit handler instead, but this way you can use the .valid() method, instead of having to wait for a submission of the form,
hope this helps
jQuery.validator.addMethod("hasAttributes", function(value, element) {
console.log('bla');
return $("ul > li").length > 0
})
console.log($("#templateForm").validate({
ignore: "",
rules: {
attr: {hasAttributes: true}
},
submitHandler: function (form) { // for demo
alert(this.valid()); // for demo
return false; // for demo
},
invalidHandler: function(event, validator) { alert('oops, no attributes'); }
}));
$("#templateForm").valid()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.15.0/jquery.validate.min.js"></script>
<form id="templateForm">
/*other input elements*/
<div class="attributes-added">
<input type="hidden" id="attr" name="attr">
<ul name = "attributesAddedList">
// by default no element is present
</ul>
<input type = "submit" value = "save"> </div>
</form>

Problems with validate jquery function

I was trying to make a validation in my form with jquery, but it does not work the way it was supposed to and I have no idea why.
I have this function to make the validation:
function newLogin () {
var username = $("#popup-login-email").val();
var password = $("#popup-login-password").val();
if (username == "" || password.length<5){
$(document).ready(function () {
$("#popup-login-form").validate({ // initialize the plugin
rules: {
email: {
required: true,
email: true
},
password: {
required: true,
minlength: 5
}
},
});
});
return false;
}
else{
Parse.User.logIn(username, password, {
success:function(user){
console.log("login successfull");
if(checkEmail()){
console.log(checkEmail());
document.location.href = "Temas.html";
}
},
error: function(user, error){
console.log(error.message);
displayErrorDiv();
}
})
}
}
And i got this form
<form id = "popup-login-form">
<input type="email" name="email" placeholder="Email" id = "popup-login-email" class="popup-input first"/>
<div id="error-message-email" class="error">
</div>
<input type="password" name="password" placeholder = "Password" id="popup-login-password" class="popup-input"/>
<div id="error-message-password" class="error">
</div>
<button class="popup-button" id="popup-cancel">Cancel</button>
<button type="submit" class="popup-button" id="popup-submit">Login</button>
<div class="error-message-login" class="error">
</div>
</form>
And the weird part is that just does not work in my page. Here it works, for example: http://jsfiddle.net/xs5vrrso/
There is no problem with the code which you shared in jsfiddle but the above code you are using $(document).ready({function()}) inside a function which is of no use. Now the problem is that the method newLogin is not called on dom ready and thus this issue occurs.
Better keep the function call inside $(document).ready({function() newLogin() }) . Now you can also use submitHandler in validate to merge the if else conditions.
i make one example to you
jsfiddler example
$(document).ready(function () {
$("#popup-login-form").validate({ // initialize the plugin
rules: {
email: {
required: true,
email: true
},
password: {
required: true,
minlength: 5
}
},
});
//event listening onSubmit
$('form').submit(function(event){
var returnForm = true;
var username = $("#popup-login-email").val();
var password = $("#popup-login-password").val();
//Make your validation here
if (username == "" || password.length<5){
returnForm = false;
}
return returnForm; //Submit if variable is true
});
});
With jQuery when i get the
"TypeError: $(...).validate is not a function"
I change
$(..).validate
for
jQuery(..).validate
You have to include this validate file after jquery file.
<script src="http://cdn.jsdelivr.net/jquery.validation/1.14.0/jquery.validate.js"></script>
Do not wrap the code under the if condition with $(document).ready(). Change the code to :
if (username == "" || password.length < 5){
$("#popup-login-form").validate({ // initialize the plugin
/*remaining code here*/
});
}
Also it is a good habit to trim the spaces around any input that you accept from the users. For e.g in your case please do the following:
var username = $.trim($("#popup-login-email").val());
var password = $.trim($("#popup-login-password").val());
/* $.trim() would remove the whitespace from the beginning and end of a string.*/

jquery validate with a character counter plugin

I have a page that has fields that are validated using jquery-validate plugin, and wanted to include a twitter like character counter on the fields to see how many chars are left
Here is my demo
http://jsfiddle.net/4k1vokgv/1/
$(document).ready(function() {
$(".counter").characterCounter({
counterCssClass: 'text-counter',
limit: 1000,
counterFormat: 'Characters Remaining: %1',
});
var validatorStrat = $("#strategyForm").validate({
rules:{
exampleInputEmail1: {
required: true,
},
ZB_note: {
required: true,
maxlength: 140,
},
ZC_note: {
required: true,
maxlength: 140,
},
},
submitHandler: function(form) {}
});
});
Both character counters work fine until
the issue, when jquery-validate fires a validation error (required, maxlength, etc), the character counter then stops working on any element that has an error.
I do not believe this is an issue with the character counter plugin itself. I think the error generation that jquery validate does somehow causes this.
Anyways, included the full snippet below, any help is greatly appreciated
/**
* Character Counter v1.0
* ======================
*
* Character Counter is a simple, Twitter style character counter.
*
* https://github.com/dtisgodsson/jquery-character-counter
*
* #author Darren Taylor
* #author Email: shout#darrenonthe.net
* #author Twitter: darrentaytay
* #author Website: http://darrenonthe.net
*
*/
(function($) {
$.fn.characterCounter = function(options){
var defaults = {
exceeded: false,
limit: 150,
counterWrapper: 'span',
counterCssClass: 'help-block',
counterFormat: '%1',
counterExceededCssClass: 'exceeded',
onExceed: function(count) {},
onDeceed: function(count) {},
customFields: {},
};
var options = $.extend(defaults, options);
return this.each(function() {
$(this).after(generateCounter());
bindEvents(this);
checkCount(this);
});
function customFields(params)
{
var html='';
for (var i in params)
{
html += ' ' + i + '="' + params[i] + '"';
}
return html;
}
function generateCounter()
{
var classString = options.counterCssClass;
if(options.customFields.class)
{
classString += " " + options.customFields.class;
delete options.customFields['class'];
}
return '<'+ options.counterWrapper +customFields(options.customFields)+' class="' + classString + '"></'+ options.counterWrapper +'>';
}
function renderText(count)
{
return options.counterFormat.replace(/%1/, count);
}
function checkCount(element)
{
var characterCount = $(element).val().length;
var remaining = options.limit - characterCount;
if( remaining < 0 )
{
$(element).next("." + options.counterCssClass).addClass(options.counterExceededCssClass);
options.exceeded = true;
options.onExceed(characterCount);
}
else
{
if(options.exceeded) {
$(element).next("." + options.counterCssClass).removeClass(options.counterExceededCssClass);
options.onDeceed(characterCount);
options.exceeded = false;
}
}
$(element).next("." + options.counterCssClass).html(renderText(remaining));
};
function bindEvents(element)
{
$(element)
.bind("keyup", function () {
checkCount(element);
})
.bind("paste", function () {
var self = this;
setTimeout(function () { checkCount(self); }, 0);
});
}
};
})(jQuery);
$.validator.setDefaults({
errorElement: "span",
errorClass: "help-block",
// validClass: 'stay',
highlight: function (element, errorClass, validClass) {
$(element).addClass(errorClass); //.removeClass(errorClass);
$(element).closest('.form-group').removeClass('has-success').addClass('has-error');
},
unhighlight: function (element, errorClass, validClass) {
$(element).removeClass(errorClass); //.addClass(validClass);
$(element).closest('.form-group').removeClass('has-error').addClass('has-success');
},
errorPlacement: function(error, element) {
if(element.parent('.input-group').length) {
error.insertAfter(element.parent());
} else if (element.hasClass('select2')) {
error.insertAfter(element.next('span'));
} else {
error.insertAfter(element);
}
}
});
$(document).ready(function() {
$(".counter").characterCounter({
counterCssClass: 'text-counter',
limit: 140,
counterFormat: 'Characters Remaining: %1',
});
var validatorStrat = $("#strategyForm").validate({
rules:{
exampleInputEmail1: {
required: true,
},
ZB_note: {
required: true,
maxlength: 1000,
},
ZC_note: {
required: true,
maxlength: 1000,
},
},
submitHandler: function(form) {}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="http://cdn.jsdelivr.net/jquery.validation/1.14.0/jquery.validate.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<form role="form" id="strategyForm">
<div class="form-group">
<label for="exampleInputEmail1" class="control-label">Email address</label>
<input type="email" class="form-control" name="exampleInputEmail1" placeholder="Enter email" />
</div>
<div class="form-group">
<label class="control-label">What amount is to be solicited and when?</label>
<textarea class="form-control counter" rows="1" id="ZB_note" name="ZB_note" ></textarea>
</div>
<div class="form-group">
<label class="control-label">Who will be involved in the soliciation?</label>
<textarea class="form-control counter" rows="1" id="ZC_note" name="ZC_note" ></textarea>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
I have made a code pen with exactly this functionality here.
Codepen
I will also add and discuss the code here, it really is not that hard.
$( document ).ready(function() {
$('#text').on('keypress', function(e) {
var count = $(this).val().length;
if(count != 0) {
count += 1;
} else {
count = count;
}
$('#characterCount').text(count);
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="col m-2">
<textarea id="text" rows="4" cols="50"></textarea>
</div>
<div class="col m-2">
<textarea id="characterCount" rows="4" cols="50"></textarea>
</div>
</div>
The document.ready function insures the function loads when the DOM is ready. You then have a function that fires whenever a key is pressed on the text area. You then have the count variable that is set to the length of the value of the current text ID. You then set the count to plus one, because it is zero index. You then represent the value on the other text area.
Problem is due to where the error element is being inserted compared to the traverse you use to set the counter text.
In your counter plugin you are looking for next() to set the count display using the following:
$(element).next("." + options.counterCssClass).html(renderText(remaining));
That is based on structure being:
<inputElement/>
<counterDisplay/>
But the validator errorPlacment is doing:
<inputElement/>
<validatorError/>
<counterDisplay/>
So now the plugin next(classSelector) returns no matches
You could simply use nextAll() instead of next() in plugin...or change the errorPlacement to something like :
error.parent().append(element);
Demo using nextAll() in plugin
Finding the reason (Problem)
I believe I've found the problem.
When the a field doesn't pass the validation rules it shows an error.
The error is being append to the DOM as:
This field is required.
When I removed it using the console the counter worked.
That made my wonder - maybe the checkCount function still works but the "output" (the span counter) doesn't.
So on line 72, I added:
console.log(characterCount);
Duplicated that scenario again - and it indeed printed the count.
So the problem is that from some reason - when the " error" appears it conflicts with the " text counter". Please notice, that after start writing again - it seems that the " error" is gone - but the truth is that it still in the DOM, it's just hidden using CSS.
<span id="ZB_note-error" class="help-block" style="display: none;"></span>
Then, I added the following code on Line 92:
console.debug( options.counterCssClass );
console.debug( $(element).next("." + options.counterCssClass).html());
Guess what was the output.
For the first debug line: text-counter (that's good)
For the second debug line: undefined (not good)
How to solve it?
Solution 1: You're using the next() function wrongly.
Description: Get the immediately following sibling of each element in
the set of matched elements. If a selector is provided, it retrieves
the next sibling only if it matches that selector.
When the " error" element is being added, the text-counter field is no longer apply to the next() rule. Consider change it with something like: .parent().find('.text-counter') in case each field+text-counter have a common parent.
Solution 2: When a user starts typing, remove the " error" element from the DOM.

Categories