jQuery: focusout triggering before onclick for Ajax suggestion - javascript

I have a webpage I'm building where I need to be able to select 1-9 members via a dropdown, which then provides that many input fields to enter their name. Each name field has a "suggestion" div below it where an ajax-fed member list is populated. Each item in that list has an "onclick='setMember(a, b, c)'" field associated with it. Once the input field loses focus we then validate (using ajax) that the input username returns exactly 1 database entry and set the field to that entry's text and an associated hidden memberId field to that one entry's id.
The problem is: when I click on the member name in the suggestion box the lose focus triggers and it attempts to validate a name which has multiple matches, thereby clearing it out. I do want it to clear on invalid, but I don't want it to clear before the onclick of the suggestion box name.
Example:
In the example above Paul Smith would populate fine if there was only one name in the suggestion list when it lost focus, but if I tried clicking on Raphael's name in the suggestion area (that is: clicking the grey div) it would wipe out the input field first.
Here is the javascript, trimmed for brevity:
function memberList() {
var count = document.getElementById('numMembers').value;
var current = document.getElementById('listMembers').childNodes.length;
if(count >= current) {
for(var i=current; i<=count; i++) {
var memberForm = document.createElement('div');
memberForm.setAttribute('id', 'member'+i);
var memberInput = document.createElement('input');
memberInput.setAttribute('name', 'memberName'+i);
memberInput.setAttribute('id', 'memberName'+i);
memberInput.setAttribute('type', 'text');
memberInput.setAttribute('class', 'ajax-member-load');
memberInput.setAttribute('value', '');
memberForm.appendChild(memberInput);
// two other fields (the ones next to the member name) removed for brevity
document.getElementById('listMembers').appendChild(memberForm);
}
}
else if(count < current) {
for(var i=(current-1); i>count; i--) {
document.getElementById('listMembers').removeChild(document.getElementById('listMembers').lastChild);
}
}
jQuery('.ajax-member-load').each(function() {
var num = this.id.replace( /^\D+/g, '');
// Update suggestion list on key release
jQuery(this).keyup(function(event) {
update(num);
});
// Check for only one suggestion and either populate it or clear it
jQuery(this).focusout(function(event) {
var number = this.id.replace( /^\D+/g, '');
memberCheck(number);
jQuery('#member'+number+'suggestions').html("");
});
});
}
// Looks up suggestions according to the partially input member name
function update(memberNumber) {
// AJAX code here, removed for brevity
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
document.getElementById('member'+memberNumber+'suggestions').innerHTML = self.xmlHttpReq.responseText;
}
}
}
// Looks up the member by name, via ajax
// if exactly 1 match, it fills in the name and id
// otherwise the name comes back blank and the id is 0
function memberCheck(number) {
// AJAX code here, removed for brevity
if (self.xmlHttpReq.readyState == 4) {
var jsonResponse = JSON.parse(self.xmlHttpReq.responseText);
jQuery("#member"+number+"id").val(jsonResponse.id);
jQuery('#memberName'+number).val(jsonResponse.name);
}
}
}
function setMember(memberId, name, listNumber) {
jQuery("#memberName"+listNumber).val(name);
jQuery("#member"+listNumber+"id").val(memberId);
jQuery("#member"+listNumber+"suggestions").html("");
}
// Generate members form
memberList();
The suggestion divs (which are now being deleted before their onclicks and trigger) simply look like this:
<div onclick='setMember(123, "Raphael Jordan", 2)'>Raphael Jordan</div>
<div onclick='setMember(450, "Chris Raptson", 2)'>Chris Raptson</div>
Does anyone have any clue how I can solve this priority problem? I'm sure I can't be the first one with this issue, but I can't figure out what to search for to find similar questions.
Thank you!

If you use mousedown instead of click on the suggestions binding, it will occur before the blur of the input. JSFiddle.
<input type="text" />
Click
$('input').on('blur', function(e) {
console.log(e);
});
$('a').on('mousedown', function(e) {
console.log(e);
});
Or more specifically to your case:
<div onmousedown='setMember(123, "Raphael Jordan", 2)'>Raphael Jordan</div>

using onmousedown instead of onclick will call focusout event but in onmousedown event handler you can use event.preventDefault() to avoid loosing focus. This will be useful for password fields where you dont want to loose focus on input field on click of Eye icon to show/hide password

Related

restrict the user from typing a new name and allow only to select from existing list

I'm working on autocomplete textbox feature of angularjs. I want the user only to select name from the existing autocomplete list instead of typing a new name. Eg.,When user types 'Al' autocomplete list shows the matching list and user can select one name from the existing list instead of typing a new name.How to restrict user from submitting a new name which is not present in the existing list.
Demo : http://plnkr.co/edit/AdmtP1b6K9kQorMHmt7t?p=preview
Code Sample:
$scope.countryList = ["Afghanistan","Albania","Algeria","Andorra","Angola","Anguilla","Antigua & Barbuda","Argentina","Armenia","Aruba","Australia","Austria","Azerbaijan","Bahamas","Bahrain","Bangladesh","Barbados","Belarus","Belgium","Belize","Benin","Bermuda","Bhutan","Bolivia","Bosnia & Herzegovina","Botswana","Brazil","British Virgin Islands","Brunei"];
$scope.validateField = function(){
alert("Clicked on submit , validte field");
}
$scope.complete=function(string){
var output=[];
angular.forEach($scope.countryList,function(country){
if(country.toLowerCase().indexOf(string.toLowerCase())>=0){
output.push(country);
}
});
$scope.filterCountry=output;
}
$scope.fillTextbox=function(string){
$scope.country=string;
$scope.filterCountry=null;
}
Any inputs would be helpful.
You can disable submit button and also highlight the border of the input field red, telling user to select name from drop down list.
First you need to update your complete() function. Use an else if statement that will check if the value is from the list or not, if not then you can implement your desired logic in that else if statement.
This method is flexible and easy to customize your error generation messages. You can show and hide the div that has the error message or you can apply css style on input-field using ng-style or ng-class. Right now I'll show you how to disable or enable button. Here is the updated code snippet:
$scope.complete = function(string) {
var output = [];
angular.forEach($scope.countryList, function(country) {
if (country.toLowerCase().indexOf(string.toLowerCase()) >= 0) {
output.push(country);
$scope.enableDisable = false;
} else if (country.toLowerCase().indexOf(string.toLowerCase()) < 0) {
$scope.enableDisable = true;
}
});
$scope.filterCountry = output;
}
And the In the html section you just need to add ng-disabled attribute and set its value.
<input type="submit" value="submit" ng-disabled="enableDisable" ng-click="validateField()">
So, you can do whatever you want in that else if statement to get the desire error message.
Take a look at this plunkr.
you can check for the validity of input using something like below and monitoring the value using ng-change
$scope.checkInput = function(){
$scope.validInput = $scope.countryList.indexOf($scope.country) > -1;
}

Doing mutual exclusive checkbox of two buttons with siblings()

I am trying to get two buttons groups with checkboxes mutually exclusive.
Here's my current result on this JS Fiddle
As you can see, there are four divs (with id="UserVsComputer", id="User1VsUser2", id="PlayableHits" and id="button-new-game").
I want the two first <div> ( UserVsComputer and User1VsUser2 ) to be mutually exclusive when we click on the checkbox of concerning <input> (i.e corresponding to the right <div>).
In JavaScript part, I did:
// Select the clicked checkbox for game type
$('input.game').on('click',function(){
setGameType();
});
function setGameType() {
// Get state of the first clicked element
var element = $('#UserVsComputer input.game');
var checkBoxState = element.prop('checked');
// Set !checkBoxState for the sibling checkbox, i.e the other
element.siblings().find('input.game').prop('checked',!checkBoxState);
updateGameType();
}
function updateGameType() {
// Set type of game
if ($('#UserVsComputer input').prop('checked'))
gameType = 'UserVsComputer';
else
gameType = 'User1VsUser2';
}
I don't want the <div id="PlayableHits" class="checkbox"> to be concerned by this mutual exclusion on two first checkboxes.
For example, below a capture showing that I can set the two first checkbox to true without making them exclusive:
What might be wrong here?
Try the following - it uses the target of the click event to ascertain which checkbox was checked:
// Select the clicked checkbox for game type
$('input.game').on('click',function(e){
setGameType(e.target);
});
function setGameType(cb) {
var container = $(cb).parent().parent();
var checkBox = $(cb);
var checkBoxState = checkBox.prop('checked');
// Set !checkBoxState for the sibling checkbox, i.e the other
container.siblings().find('input.game').prop('checked', !checkBoxState);
updateGameType();
}
function updateGameType() {
// Set type of game
if ($('#UserVsComputer input').prop('checked')) {
gameType = 'UserVsComputer';
} else {
gameType = 'User1VsUser2';
}
}
There are other bits which could use some attention (the hardcoded .parent().parent() isn't pretty but works in this case..

Jquery Chosen plugin. Select multiple of the same option

I'm using the chosen plugin to build multiple select input fields. See an example here: http://harvesthq.github.io/chosen/#multiple-select
The default behavior disables an option if it has already been selected. In the example above, if you were to select "Afghanistan", it would be greyed out in the drop-down menu, thus disallowing you from selecting it a second time.
I need to be able to select the same option more than once. Is there any setting in the plugin or manual override I can add that will allow for this?
I created a version of chosen that allows you to select the same item multiple times, and even sends those multiple entries to the server as POST variables. Here's how you can do it (fairly easily, I think):
(Tip: Use a search function in chosen.jquery.js to find these lines)
Change:
this.is_multiple = this.form_field.multiple;
To:
this.is_multiple = this.form_field.multiple;
this.allows_duplicates = this.options.allow_duplicates;
Change:
classes.push("result-selected");
To:
if (this.allows_duplicates) {
classes.push("active-result");
} else {
classes.push("result-selected");
}
Change:
this.form_field.options[item.options_index].selected = true;
To:
if (this.allows_duplicates && this.form_field.options[item.options_index].selected == true) {
$('<input>').attr({type:'hidden',name:this.form_field.name,value:this.form_field.options[item.options_index].value}).appendTo($(this.form_field).parent());
} else {
this.form_field.options[item.options_index].selected = true;
}
Then, when calling chosen(), make sure to include the allows_duplicates option:
$("mySelect").chosen({allow_duplicates: true})
For a workaround, use the below code on each selection (in select event) or while popup opened:
$(".chosen-results .result-selected").addClass("active-result").removeClass("result-selected");
The above code removes the result-selected class and added the active-result class on the li items. So each selected item is considered as the active result, now you can select that item again.
#adam's Answer is working very well but doesn't cover the situation that someone wants to delete some options.
So to have this functionality, alongside with Adam's tweaks you need to add this code too at:
Chosen.prototype.result_deselect = function (pos) {
var result_data;
result_data = this.results_data[pos];
// If config duplicates is enabled
if (this.allows_duplicates) {
//find fields name
var $nameField = $(this.form_field).attr('name');
// search for hidden input with same name and value of the one we are trying to delete
var $duplicateVals = $('input[type="hidden"][name="' + $nameField + '"][value="' + this.form_field.options[result_data.options_index].value + '"]');
//if we find one. we delete it and stop the rest of the function
if ($duplicateVals.length > 0) {
$duplicateVals[0].remove();
return true;
}
}
....

Getting siblings value with javascript

I create a textarea and a button on a loop based on a certain condition:
while($row_c= mysqli_fetch_array($result_comments))
{
//some code goes here
<textarea type="text" id="pm_text" name="text"></textarea><br>
<button name="send_comment" id="post_comment" class="button" onClick="post_pm_comment()">Post</button>
}
Now in my function "post_pm_comment" I would like to access the text written in the textarea when the post button is clicked.
I tried this, but it only gives me the text of the first textarea and button created:
function post_pm_comment(thidid, pm_id, path, pm,getter)
{
var pm_text = document.getElementById("pm_text").value;
}
What should I do?
Thank you
Your code is outputting an invalid DOM structure, because id values must be unique on the page. You cannot have the same id on more than one element. Remove the id values entirely, you don't need them.
Having done that, the minimal-changes answer is to pass this into your handler:
onClick="post_pm_comment(this)"
...and then in your handler, do the navigation:
function post_pm_comment(postButton)
{
var pm_text;
var textarea = postButton.previousSibling;
while (textarea && textarea.nodeName.toUpperCase() !== "TEXTAREA") {
textarea = textarea.previousSibling;
}
if (textarea) {
pm_text = textarea.value; // Or you may want .innerHTML instead
// Do something with it
}
}
Live Example | Source

JavaScript textfield validation: sending focus back

I am using JQuery and JavaScript for an input form for time values, and I can't make JavaScript to provide the intended reaction to incorrect input format.
What do I do wrong...?
I have a set of 3 text inputs with class "azeit" (and under these a number of others of class "projekt"). All are used to input time values. As soon as the user exits the field I validate the format, do a calculation with it and display the result of this in a field with id "summe1". This works. If the format is incorrect, I display an alert and what I want to do is return the focus to the field after emptying it. However, the focus never gets returned (although it will get emptied all right). This is it:
var kalkuliere_azeit = function(e) {
var anf = $("#anfang");
var ende = $("#ende");
var pause = $("#pause");
var dauer_in_min = 0;
var ungueltiges = null;
if (nonempty(anf.val(), ende.val()), pause.val()))
{
if (!is_valid_date(make_date(anf.val()))){
ungueltiges = anf;
};
if (!is_valid_date(make_date(ende.val()))){
ungueltiges = ende;
};
if (!is_valid_date(make_date(pause.val()))){
ungueltiges = pause;
};
if (ungueltiges)
{
alert("invalid time"); //This is where I am stuck
ungueltiges.val("");
ungueltiges.focus();
}
else {
dauer_in_min = hourstring_to_min(ende.val())
- hourstring_to_min(anf.val())
- hourstring_to_min(pause.val());
$("#summe1").text(min_to_hhmm(dauer_in_min));
};
};
};
....
$(document).ready(function() {
$(".projekt").change( kalkuliere_summe);
$(".azeit").focusout(kalkuliere_azeit);
});
The fields with the class "projekt" are below those with the class "azeit" so they'll get the focus when the user leaves the third field of class "azeit".
I apologize for supplying incomplete source code. I hope someone can see what's wrong.
One point I'd like to mention is that I tried binding the handler to onblur and onfocus as well. When I bind it to onfocus the focus does get reset to the field, but the last field the user enters will not update the field $("#summe1") correctly (because this would need focusing another field of the same class).
Im not sure whats wrong with your code but one way of doing it would be to put the focus into a function.
So ...
function focusIt()
{
var mytext = document.getElementById("divId");
mytext.val("");
mytext.focus();
}
And call it from the if/else statement ...
if (ungueltiges)
{
alert("invalid time");
focusIt()
}

Categories

Resources