Here is my code example im currently working on. (i needed an exmaple of an autocomplete input for only airports) this is forked from someone on codepen, so credit on their behalf.
What it currently does?
The code curently autocompletes the airport code based on the city you input into the field. This is the expected behaviour and is fine.
What i am currently trying to achieve ?
I am now trying to add a second input (id name of autocomplete2) field to behave the exact same. So i can simple add 2 seperate airports, 1 in each input.
I have tried adding adding the following var bc = $('#autocomplete2') and using var bc thorugh the code but i am getting lost when it comes to the bottom of the code
function search(e) {
if (e.which === 38 || e.which === 13 || e.which === 40) {
return;
}
if (ac.val().length > 0) {
results = _.take(fuse.search(ac.val()), 7);
numResults = results.length;
var divs = results.map(function(r, i) {
return '<div class="autocomplete-result" data-index="'+ i +'">'
+ '<div><b>'+ r.iata +'</b> - '+ r.name +'</div>'
+ '<div class="autocomplete-location">'+ r.city +', '+ r.country +'</div>'
+ '</div>';
});
selectedIndex = -1;
list.html(divs.join(''))
.attr('data-highlight', selectedIndex);
} else {
numResults = 0;
list.empty();
}
}
I have reverted my changes and gone back to a single input for the time being.
https://codepen.io/anon/pen/vrvgKQ?editors=0010
EDIT
https://codepen.io/eyecandy91/pen/JZwrqy?editors=0010
Changing to a class allows me to use multiple inputs but now theres a issues with the dropdown when there is double inputs & double inputs on each class. Codepend updated.
Take a look at this pen, I believe it should be working the way you want it: https://codepen.io/anon/pen/vrvZmv?editors=0011
var options = {
shouldSort: true,
threshold: 0.4,
maxPatternLength: 32,
keys: [{
name: 'iata',
weight: 0.5
},
{
name: 'name',
weight: 0.3
},
{
name: 'city',
weight: 0.2
}]
};
var fuse = new Fuse(airports, options);
$('.autocomplete').each(function() {
var ac = $(this);
ac.on('click', function(e) {
e.stopPropagation();
})
.on('focus keyup', search)
.on('keydown', onKeyDown);
var wrap = $('<div>')
.addClass('autocomplete-wrapper')
.insertBefore(ac)
.append(ac);
var list = $('<div>')
.addClass('autocomplete-results')
.on('click', '.autocomplete-result', function(e) {
e.preventDefault();
e.stopPropagation();
selectIndex($(this).data('index'), ac);
})
.appendTo(wrap);
});
$(document)
.on('mouseover', '.autocomplete-result', function(e) {
var index = parseInt($(this).data('index'), 10);
if (!isNaN(index)) {
$(this).attr('data-highlight', index);
}
})
.on('click', clearResults);
function clearResults() {
results = [];
numResults = 0;
$('.autocomplete-results').empty();
}
function selectIndex(index, autoinput) {
if (results.length >= index + 1) {
autoinput.val(results[index].iata);
clearResults();
}
}
var results = [];
var numResults = 0;
var selectedIndex = -1;
function search(e) {
if (e.which === 38 || e.which === 13 || e.which === 40) {
return;
}
var ac = $(e.target);
var list = ac.next();
if (ac.val().length > 0) {
results = _.take(fuse.search(ac.val()), 7);
numResults = results.length;
var divs = results.map(function(r, i) {
return '<div class="autocomplete-result" data-index="'+ i +'">'
+ '<div><b>'+ r.iata +'</b> - '+ r.name +'</div>'
+ '<div class="autocomplete-location">'+ r.city +', '+ r.country +'</div>'
+ '</div>';
});
selectedIndex = -1;
list.html(divs.join(''))
.attr('data-highlight', selectedIndex);
} else {
numResults = 0;
list.empty();
}
}
function onKeyDown(e) {
var ac = $(e.currentTarget);
var list = ac.next();
switch(e.which) {
case 38: // up
selectedIndex--;
if (selectedIndex <= -1) {
selectedIndex = -1;
}
list.attr('data-highlight', selectedIndex);
break;
case 13: // enter
selectIndex(selectedIndex, ac);
break;
case 9: // enter
selectIndex(selectedIndex, ac);
e.stopPropagation();
return;
case 40: // down
selectedIndex++;
if (selectedIndex >= numResults) {
selectedIndex = numResults-1;
}
list.attr('data-highlight', selectedIndex);
break;
default: return; // exit this handler for other keys
}
e.stopPropagation();
e.preventDefault(); // prevent the default action (scroll / move caret)
}
I put the autocomplete inputs through a loop to create the "dropdown"-container for each one and then changed most of the functions so that they would work for multiple inputs.
There's probably room for improvement and cleaning up, but hopefully this will get you in the right direction.
Edit: Found and fixed bug in onKeyDown-function
Related
I have edited this puzzle as I want but I need to show a message after completing the crossword puzzle. Is there a way to do that? Any kind comments warmly welcome.
Here's is the GitHub link- https://github.com/jweisbeck/Crossword
Here mainly activePosition and activeClueIndex are the primary vars that set the UI whenever there's an interaction. all worked as x, y coordinates. is there any way I can add that message?
Here is the checking winning function
/*
- Checks current entry input group value against answer
- If not complete, auto-selects next input for user
*/
checkAnswer: function(e) {
var valToCheck, currVal;
util.getActivePositionFromClassGroup($(e.target));
valToCheck = puzz.data[activePosition].answer.toLowerCase();
currVal = $('.position-' + activePosition + ' input')
.map(function() {
return $(this)
.val()
.toLowerCase();
})
.get()
.join('');
//console.log(currVal + " " + valToCheck);
if(valToCheck === currVal){
$('.active')
.addClass('done')
.removeClass('active');
$('.clues-active').addClass('clue-done');
solved.push(valToCheck);
solvedToggle = true;
return;
}
currOri === 'across' ? nav.nextPrevNav(e, 39) : nav.nextPrevNav(e, 40);
//z++;
//console.log(z);
//console.log('checkAnswer() solvedToggle: '+solvedToggle);
}
}; // end puzInit object
Here is the full code
var puzz = {}; // put data array in object literal to namespace it into safety
puzz.data = entryData;
// append clues markup after puzzle wrapper div
// This should be moved into a configuration object
this.after('<div id="puzzle-clues"><h2>Across</h2><ol id="across"></ol><h2>Down</h2><ol id="down"></ol></div>');
// initialize some variables
var tbl = ['<table id="puzzle">'],
puzzEl = this,
clues = $('#puzzle-clues'),
clueLiEls,
coords,
entryCount = puzz.data.length,
entries = [],
rows = [],
cols = [],
solved = [],
tabindex,
$actives,
activePosition = 0,
activeClueIndex = 0,
currOri,
targetInput,
mode = 'interacting',
solvedToggle = false,
z = 0;
var puzInit = {
init: function() {
currOri = 'across'; // app's init orientation could move to config object
// Reorder the problems array ascending by POSITION
puzz.data.sort(function(a,b) {
return a.position - b.position;
});
// Set keyup handlers for the 'entry' inputs that will be added presently
puzzEl.delegate('input', 'keyup', function(e){
mode = 'interacting';
// need to figure out orientation up front, before we attempt to highlight an entry
switch(e.which) {
case 39:
case 37:
currOri = 'across';
break;
case 38:
case 40:
currOri = 'down';
break;
default:
break;
}
if ( e.keyCode === 9) {
return false;
} else if (
e.keyCode === 37 ||
e.keyCode === 38 ||
e.keyCode === 39 ||
e.keyCode === 40 ||
e.keyCode === 8 ||
e.keyCode === 46 ) {
if (e.keyCode === 8 || e.keyCode === 46) {
currOri === 'across' ? nav.nextPrevNav(e, 37) : nav.nextPrevNav(e, 38);
} else {
nav.nextPrevNav(e);
}
e.preventDefault();
return false;
} else {
console.log('input keyup: '+solvedToggle);
puzInit.checkAnswer(e);
}
e.preventDefault();
return false;
});
// tab navigation handler setup
puzzEl.delegate('input', 'keydown', function(e) {
if ( e.keyCode === 9) {
mode = "setting ui";
if (solvedToggle) solvedToggle = false;
//puzInit.checkAnswer(e)
nav.updateByEntry(e);
} else {
return true;
}
e.preventDefault();
});
// tab navigation handler setup
puzzEl.delegate('input', 'click', function(e) {
mode = "setting ui";
if (solvedToggle) solvedToggle = false;
console.log('input click: '+solvedToggle);
nav.updateByEntry(e);
e.preventDefault();
});
// click/tab clues 'navigation' handler setup
clues.delegate('li', 'click', function(e) {
mode = 'setting ui';
if (!e.keyCode) {
nav.updateByNav(e);
}
e.preventDefault();
});
// highlight the letter in selected 'light' - better ux than making user highlight letter with second action
puzzEl.delegate('#puzzle', 'click', function(e) {
$(e.target).focus();
$(e.target).select();`+`
});
// DELETE FOR BG
puzInit.calcCoords();
// Puzzle clues added to DOM in calcCoords(), so now immediately put mouse focus on first clue
clueLiEls = $('#puzzle-clues li');
$('#' + currOri + ' li' ).eq(0).addClass('clues-active').focus();
// DELETE FOR BG
puzInit.buildTable();
puzInit.buildEntries();
},
/*
- Given beginning coordinates, calculate all coordinates for entries, puts them into entries array
- Builds clue markup and puts screen focus on the first one
*/
calcCoords: function() {
/*
Calculate all puzzle entry coordinates, put into entries array
*/
for (var i = 0, p = entryCount; i < p; ++i) {
// set up array of coordinates for each problem
entries.push(i);
entries[i] = [];
for (var x=0, j = puzz.data[i].answer.length; x < j; ++x) {
entries[i].push(x);
coords = puzz.data[i].orientation === 'across' ? "" + puzz.data[i].startx++ + "," + puzz.data[i].starty + "" : "" + puzz.data[i].startx + "," + puzz.data[i].starty++ + "" ;
entries[i][x] = coords;
}
// while we're in here, add clues to DOM!
$('#' + puzz.data[i].orientation).append('<li tabindex="1" data-position="' + i + '">' + puzz.data[i].clue + '</li>');
}
// Calculate rows/cols by finding max coords of each entry, then picking the highest
for (var i = 0, p = entryCount; i < p; ++i) {
for (var x=0; x < entries[i].length; x++) {
cols.push(entries[i][x].split(',')[0]);
rows.push(entries[i][x].split(',')[1]);
};
}
rows = Math.max.apply(Math, rows) + "";
cols = Math.max.apply(Math, cols) + "";
},
/*
Build the table markup
- adds [data-coords] to each <td> cell
*/
buildTable: function() {
for (var i=1; i <= rows; ++i) {
tbl.push("<tr>");
for (var x=1; x <= cols; ++x) {
tbl.push('<td data-coords="' + x + ',' + i + '"></td>');
};
tbl.push("</tr>");
};
tbl.push("</table>");
puzzEl.append(tbl.join(''));
},
/*
Builds entries into table
- Adds entry class(es) to <td> cells
- Adds tabindexes to <inputs>
*/
buildEntries: function() {
var puzzCells = $('#puzzle td'),
light,
$groupedLights,
hasOffset = false,
positionOffset = entryCount - puzz.data[puzz.data.length-1].position; // diff. between total ENTRIES and highest POSITIONS
for (var x=1, p = entryCount; x <= p; ++x) {
var letters = puzz.data[x-1].answer.split('');
for (var i=0; i < entries[x-1].length; ++i) {
light = $(puzzCells +'[data-coords="' + entries[x-1][i] + '"]');
// check if POSITION property of the entry on current go-round is same as previous.
// If so, it means there's an across & down entry for the position.
// Therefore you need to subtract the offset when applying the entry class.
if(x > 1 ){
if (puzz.data[x-1].position === puzz.data[x-2].position) {
hasOffset = true;
};
}
if($(light).empty()){
$(light)
.addClass('entry-' + (hasOffset ? x - positionOffset : x) + ' position-' + (x-1) )
.append('<input maxlength="1" val="" type="text" tabindex="-1" />');
}
};
};
// Put entry number in first 'light' of each entry, skipping it if already present
for (var i=1, p = entryCount; i < p; ++i) {
$groupedLights = $('.entry-' + i);
if(!$('.entry-' + i +':eq(0) span').length){
$groupedLights.eq(0)
.append('<span>' + puzz.data[i].position + '</span>');
}
}
util.highlightEntry();
util.highlightClue();
$('.active').eq(0).focus();
$('.active').eq(0).select();
},
/*
- Checks current entry input group value against answer
- If not complete, auto-selects next input for user
*/
checkAnswer: function(e) {
var valToCheck, currVal;
util.getActivePositionFromClassGroup($(e.target));
valToCheck = puzz.data[activePosition].answer.toLowerCase();
currVal = $('.position-' + activePosition + ' input')
.map(function() {
return $(this)
.val()
.toLowerCase();
})
.get()
.join('');
//console.log(currVal + " " + valToCheck);
if(valToCheck === currVal){
$('.active')
.addClass('done')
.removeClass('active');
$('.clues-active').addClass('clue-done');
solved.push(valToCheck);
solvedToggle = true;
return;
}
currOri === 'across' ? nav.nextPrevNav(e, 39) : nav.nextPrevNav(e, 40);
//z++;
//console.log(z);
//console.log('checkAnswer() solvedToggle: '+solvedToggle);
}
}; // end puzInit object
var nav = {
nextPrevNav: function(e, override) {
var len = $actives.length,
struck = override ? override : e.which,
el = $(e.target),
p = el.parent(),
ps = el.parents(),
selector;
util.getActivePositionFromClassGroup(el);
util.highlightEntry();
util.highlightClue();
$('.current').removeClass('current');
selector = '.position-' + activePosition + ' input';
//console.log('nextPrevNav activePosition & struck: '+ activePosition + ' '+struck);
// move input focus/select to 'next' input
switch(struck) {
case 39:
p
.next()
.find('input')
.addClass('current')
.select();
break;
case 37:
p
.prev()
.find('input')
.addClass('current')
.select();
break;
case 40:
ps
.next('tr')
.find(selector)
.addClass('current')
.select();
break;
case 38:
ps
.prev('tr')
.find(selector)
.addClass('current')
.select();
break;
default:
break;
}
},
updateByNav: function(e) {
var target;
$('.clues-active').removeClass('clues-active');
$('.active').removeClass('active');
$('.current').removeClass('current');
currIndex = 0;
target = e.target;
activePosition = $(e.target).data('position');
util.highlightEntry();
util.highlightClue();
$('.active').eq(0).focus();
$('.active').eq(0).select();
$('.active').eq(0).addClass('current');
// store orientation for 'smart' auto-selecting next input
currOri = $('.clues-active').parent('ol').prop('id');
activeClueIndex = $(clueLiEls).index(e.target);
//console.log('updateByNav() activeClueIndex: '+activeClueIndex);
},
// Sets activePosition var and adds active class to current entry
updateByEntry: function(e, next) {
var classes, next, clue, e1Ori, e2Ori, e1Cell, e2Cell;
if(e.keyCode === 9 || next){
// handle tabbing through problems, which keys off clues and requires different handling
activeClueIndex = activeClueIndex === clueLiEls.length-1 ? 0 : ++activeClueIndex;
$('.clues-active').removeClass('.clues-active');
next = $(clueLiEls[activeClueIndex]);
currOri = next.parent().prop('id');
activePosition = $(next).data('position');
// skips over already-solved problems
util.getSkips(activeClueIndex);
activePosition = $(clueLiEls[activeClueIndex]).data('position');
} else {
activeClueIndex = activeClueIndex === clueLiEls.length-1 ? 0 : ++activeClueIndex;
util.getActivePositionFromClassGroup(e.target);
clue = $(clueLiEls + '[data-position=' + activePosition + ']');
activeClueIndex = $(clueLiEls).index(clue);
currOri = clue.parent().prop('id');
}
util.highlightEntry();
util.highlightClue();
//$actives.eq(0).addClass('current');
//console.log('nav.updateByEntry() reports activePosition as: '+activePosition);
}
}; // end nav object
var util = {
highlightEntry: function() {
// this routine needs to be smarter because it doesn't need to fire every time, only
// when activePosition changes
$actives = $('.active');
$actives.removeClass('active');
$actives = $('.position-' + activePosition + ' input').addClass('active');
$actives.eq(0).focus();
$actives.eq(0).select();
},
highlightClue: function() {
var clue;
$('.clues-active').removeClass('clues-active');
$(clueLiEls + '[data-position=' + activePosition + ']').addClass('clues-active');
if (mode === 'interacting') {
clue = $(clueLiEls + '[data-position=' + activePosition + ']');
activeClueIndex = $(clueLiEls).index(clue);
};
},
getClasses: function(light, type) {
if (!light.length) return false;
var classes = $(light).prop('class').split(' '),
classLen = classes.length,
positions = [];
// pluck out just the position classes
for(var i=0; i < classLen; ++i){
if (!classes[i].indexOf(type) ) {
positions.push(classes[i]);
}
}
return positions;
},
getActivePositionFromClassGroup: function(el){
classes = util.getClasses($(el).parent(), 'position');
if(classes.length > 1){
// get orientation for each reported position
e1Ori = $(clueLiEls + '[data-position=' + classes[0].split('-')[1] + ']').parent().prop('id');
e2Ori = $(clueLiEls + '[data-position=' + classes[1].split('-')[1] + ']').parent().prop('id');
// test if clicked input is first in series. If so, and it intersects with
// entry of opposite orientation, switch to select this one instead
e1Cell = $('.position-' + classes[0].split('-')[1] + ' input').index(el);
e2Cell = $('.position-' + classes[1].split('-')[1] + ' input').index(el);
if(mode === "setting ui"){
currOri = e1Cell === 0 ? e1Ori : e2Ori; // change orientation if cell clicked was first in a entry of opposite direction
}
if(e1Ori === currOri){
activePosition = classes[0].split('-')[1];
} else if(e2Ori === currOri){
activePosition = classes[1].split('-')[1];
}
} else {
activePosition = classes[0].split('-')[1];
}
console.log('getActivePositionFromClassGroup activePosition: '+activePosition);
},
checkSolved: function(valToCheck) {
for (var i=0, s=solved.length; i < s; i++) {
if(valToCheck === solved[i]){
return true;
}
}
},
getSkips: function(position) {
if ($(clueLiEls[position]).hasClass('clue-done')){
activeClueIndex = position === clueLiEls.length-1 ? 0 : ++activeClueIndex;
util.getSkips(activeClueIndex);
} else {
return false;
}
}
}; // end util object
puzInit.init();
}
This is fun to solve. Did you mean show message when all question has answered? If yes, You can simply create a variable that saving every word that has answered. Then, inside function checkAnswer(), check if total word answered same as data entry.
I made that custom code here https://codeshare.io/G81rmE
I have a simple JQuery/JS Hangman game and I've spent alot of time making it work and I've run into one issue that messes up my logic and running of the game - when the player enters repeated chars (either right or wrong).
The way I've made the game work, starting with empty arrays I'm pushing into, I thought that I could create a function to only push unique chars into the array function
unique(array) {
var result = [];
$.each(array, function(i, e) {
if ($.inArray(e, result) == -1) result.push(e);
});
return result;
}
var uniqueRightGuesses = unique(rightGuesses);
var uniqueWrongGuesses = unique(wrongGuesses);
But this doesn't work because w/the inner workings of my game, the repeated input chars are still getting displayed & messing up the way winning & loosing is input (even though I'm calculating winning w/the sum of an additional array I've created to take care of a letter that repeats multiple times in a word). I've tried alot of various things at various parts of the game/in various functions and I've figured out that the easiest way to take care of this issue would be to somehow prevent the player from inputing a char if they've already input in the course of the game, in this function:
$(".form-control").keypress(function(event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == 13) {
var space = $(this).val().toLowerCase();
play(space);
$(this).val('');
endGame();
return false;
}
});
I've searched online for a way to do this, I've found jQuery.unique() but I don't think that it'd work here as it's only on DOM objects in an array (& I just want the input to not register/not be allowed if the player has already entered that letter, if it's right or wrong guess- if I take care of this problem at this spot in the game, I won't have to mess w/my arrays or the variables I'm displaying but I don't know how to simply do this.
If anyone has any suggestions or knows if this is even possible, I'd really appreciate it- I've found alot online about restricting special chars & numbers in this way but nothing about ones that have already been entered & I don't know if this is even possible (this is the first time I've ever even used .keypress() so I'm sort of new to it. Any suggestions would be much appreciated. Thanks!
Here's my entire game code:
var wordBank = ["modernism", "situationalist", "sartre", "camus", "hegel", "lacan", "barthes", "baudrillard", "foucault", "debord", "baudrillard"];
var word = [];
var answer = [];
var wrongGuesses = [];
var rightGuesses = [];
var right = [];
var images = [gallows, head, body, armL, handL, armR, handR, legL, footL, legR, footR];
var y = 0;
var i = 1;
$(document).ready(function() {
function randomWord() {
var random = Math.floor(Math.random() * wordBank.length);
var toString = wordBank[random];
console.log(toString);
word = toString.split("");
console.log(word);
}
randomWord();
function wordSpaces() {
for (var i = 0; i < word.length; i++) {
$(".word-spaces > tbody > tr").append('<td data-idx=i>' + word[i] + '</td>')
}
}
wordSpaces();
function play(space) {
//indexOf()==inArray()
var rightCount = 0;
var lIndex = jQuery.inArray(space, word);
console.log(lIndex);
if (lIndex == -1) {
wrongGuesses.push(space);
var wrong = wrongGuesses.length;
console.log('wrong ' + wrong);
$('.wrongLetters tbody tr td:nth-of-type(' + wrong + ')').text(space);
// $(this).css("background-color", "#ff4500").fadeIn(300).delay(800).fadeOut(300);
$(images[i - 1]).hide();
$(images[i]).show();
i++;
$("html").css("background-color", "#ff4500").fadeIn(300).delay(300).fadeOut(300).fadeIn(100);
console.log(word);
} else {
var totalRight = 0;
console.log(word + "word");
console.log(space + "space");
function getInstances(word, space) {
var indexes = [],
w;
for (w = 0; w < word.length; w++)
if (word[w] === space)
indexes.push(w);
return indexes;
}
console.log(word + "word");
console.log(space + "space");
var indexes = getInstances(word, space);
console.log("indexes", indexes);
indexes.forEach(function(index) {
// answer[index] = space;
rightCount++
});
console.log(rightCount + "rightcount");
console.log("answer", answer);
// rightGuesses.push(space);
console.log(rightGuesses);
// var right = rightGuesses.length;
indexes.forEach(function(index) {
$(".word-spaces tbody tr td:nth-of-type(" + (index + 1) + ")").css('color', 'black');
});
rightGuesses.push(space);
right.push(rightCount);
console.log(right + "right");
// rightGuesses.push(space);
// totalRight = totalRight + rightCount;
// totalRight++;
// console.log(totalRight + 'totalRight');
}
}
console.log(right + "right");
$(".form-control").keypress(function(event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == 13) {
var space = $(this).val().toLowerCase();
play(space);
$(this).val('');
endGame();
return false;
}
});
function endGame() {
var sumRight = right.reduce(add, 0);
function add(a, b) {
return a + b;
}
if (sumRight == word.length) {
$(images[i]).hide();
$("#victory").show();
$("body").css("background-color", "#8AFBFF");
$(".form-control").prop('disabled', true);
$("body").animate({
backgroundColor: "#0C0D86"
}, 2000);
$("body").animate({
backgroundColor: "transparent"
}, 2000);
} else if (wrongGuesses.length >= 10) {
$("body").css("background-color", "#ff4500");
$(".form-control").prop('disabled', true);
$("body").animate({
backgroundColor: "#000000"
}, 2000);
$("body").animate({
backgroundColor: "transparent"
}, 2000);
}
}
});
Use Array.indexOf(). No need for jQuery.
Do a check to see if the key pressed is contained in the wrongGuess or rightGuess array and if it is alert the user.
$(".form-control").keypress(function(event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == 13) {
var space = $(this).val().toLowerCase();
if (!(wrongGuess.indexOf(space) > -1 || rightGuess.indexOf(space) > -1)) {
play(space);
$(this).val('');
endGame();
return false;
}
else
window.alert("You already guessed this letter.");
}
});
I have a text box, I want to get the deleted character when I press a backspace or delete key.
I have a key up event handler and i am capturing if the key is backspace. Now inside this I need to perform some tasks based on the key deleted. Please help.
After making a little tweak for the getCursorPosition function in this thread, you can get the characters deleted by tracking the current cursor selection.
The code handles the following conditions:
Type and then backspace at the end.
Move cursor in the middle of the text and delete/backspace.
Select a piece of text and then delete/backspace.
$.fn.getCursorPosition = function() {
var el = $(this).get(0);
var pos = 0;
var posEnd = 0;
if('selectionStart' in el) {
pos = el.selectionStart;
posEnd = el.selectionEnd;
} else if('selection' in document) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
posEnd = Sel.text.length;
}
// return both selection start and end;
return [pos, posEnd];
};
$('#text').keydown(function (e) {
var position = $(this).getCursorPosition();
var deleted = '';
var val = $(this).val();
if (e.which == 8) {
if (position[0] == position[1]) {
if (position[0] == 0)
deleted = '';
else
deleted = val.substr(position[0] - 1, 1);
}
else {
deleted = val.substring(position[0], position[1]);
}
}
else if (e.which == 46) {
var val = $(this).val();
if (position[0] == position[1]) {
if (position[0] === val.length)
deleted = '';
else
deleted = val.substr(position[0], 1);
}
else {
deleted = val.substring(position[0], position[1]);
}
}
// Now you can test the deleted character(s) here
});
And here is Live Demo
You could use the keydown event handler instead so that the last character to be deleted is still available:
$('textarea').on('keydown',function(e) {
var deleteKeyCode = 8,
value = $(this).val(),
length = value.length,
lastChar = value.substring(length-1, length);
if (e.which === deleteKeyCode) {
alert(lastChar);
}
});
Live Demo
$('input').keydown(function(e){
$(this).data('prevVal', $(this).val());
}).keyup(function(e){
if(e.keyCode === 8) {//delete
var ele = $(this);
var val = ele.data('prevVal');
var newVal = ele.val();
var removedChar = val.substring(val.length-1);
alert(removedChar);
}
});
Something really odd going on here, and I have gone round in circles trying to figure out what is going on...I have a couple of input boxes, with onchange events firing for them, the event being loaded with a JS function that takes the value ( name of another item ) and actions the function accordingly. Only thing is, when the value of the string arrives at the other function, it has somehow been assigned a numeric value, specifically that of the input box.
My php that helps build the form:
$filterfield = '"p_delweek"';
print "<span class='filter'>Del Week<input class='menulink spin-button' id='weekno' type='text' value='".$weekno."' onKeyUp='doFilter($filterfield)' onChange='doFilter($filterfield)' data-filtered='0'/><input type='button' value='Clear' onClick='doUnfilter()'></span>";
$filterfield = '"p_seedweek"';
print "<span class='filter'>Sow Week<input class='menulink spin-button' id='sowweekno' type='text' value='".$weekno."' onKeyUp='doFilter($filterfield)' onChange='doFilter($filterfield)' data-filtered='0'/><input type='button' value='Clear' onClick='doUnfilter()'></span>";
Resulting HTML in source:
<span class="filter">Del Week<input style="width: 50px; height: 22px;" class="menulink spin-button smartspinner" id="weekno" value="26" onkeyup='doFilter("p_delweek")' onchange='doFilter("p_delweek")' data-filtered="0" type="text"><input value="Clear" onclick="doUnfilter()" type="button"></span><span class="filter">Sow Week<input style="width: 50px; height: 22px;" class="menulink spin-button smartspinner" id="sowweekno" value="26" onkeyup='doFilter("p_seedweek")' onchange='doFilter("p_seedweek")' data-filtered="0" type="text"><input value="Clear" onclick="doUnfilter()" type="button"></span>
Javascript function that is called:
function doFilter(filterfield) {
console.log("DoFilter:"+filterfield);
var filterInfo=[
{
fieldName : filterfield,
logic : "equal",
value : Sigma.Util.getValue("weekno")
}
]
// the next lines action the filtering
var grid=Sigma.$grid("myGrid1");
console.log("filterinfo="+filterInfo);
var rowNOs=grid.applyFilter(filterInfo);
}
It all goes fine until we get to the console.log("DoFilter:"+filterfield) , which results in DoFilter:25; 25 happens to be the value of the input box.
How is it grabbing that value? How to pass the real one?
TBH — I'm not sure if I got what you're after. However, if you must call a function inline (I recommend that you don’t), you can pass a reference to the input field as parameter and make it available in the methods’s body:
<input onchange="doFilter('p_delweek', this)" type="text">
function doFilter(filterfield, field) {
console.log(filterfield);
// field is a reference to the input field, hence
console.log(field.value);
// will print the current value for this field
}
This is not the answer, this file is the problem:
(function($) {
$.fn.extend({
spinit: function(options) {
var settings = $.extend({ min: 0, max: 100, initValue: 0, callback: doFilter, stepInc: 1, pageInc: 10, width: 50, height: 15, btnWidth: 10, mask: '' }, options);
return this.each(function() {
var UP = 38;
var DOWN = 40;
var PAGEUP = 33;
var PAGEDOWN = 34;
var mouseCaptured = false;
var mouseIn = false;
var interval;
var direction = 'none';
var isPgeInc = false;
var value = Math.max(settings.initValue, settings.min);
var el = $(this).val(value).css('width', (settings.width) + 'px').css('height', settings.height + 'px').addClass('smartspinner');
raiseCallback(value);
if (settings.mask != '') el.val(settings.mask);
$.fn.reset = function(val) {
if (isNaN(val)) val = 0;
value = Math.max(val, settings.min);
$(this).val(value);
raiseCallback(value);
};
function setDirection(dir) {
direction = dir;
isPgeInc = false;
switch (dir) {
case 'up':
setClass('up');
break;
case 'down':
setClass('down');
break;
case 'pup':
isPgeInc = true;
setClass('up');
break;
case 'pdown':
isPgeInc = true;
setClass('down');
break;
case 'none':
setClass('');
break;
}
}
el.focusin(function() {
el.val(value);
});
el.click(function(e) {
mouseCaptured = true;
isPgeInc = false;
clearInterval(interval);
onValueChange();
});
el.mouseenter(function(e) {
el.val(value);
});
el.mousemove(function(e) {
if (e.pageX > (el.offset().left + settings.width) - settings.btnWidth - 4) {
if (e.pageY < el.offset().top + settings.height / 2)
setDirection('up');
else
setDirection('down');
}
else
setDirection('none');
});
el.mousedown(function(e) {
isPgeInc = false;
clearInterval(interval);
interval = setTimeout(onValueChange, 250);
});
el.mouseup(function(e) {
mouseCaptured = false;
isPgeInc = false;
clearInterval(interval);
});
el.mouseleave(function(e) {
setDirection('none');
if (settings.mask != '') el.val(settings.mask);
}); el.keydown(function(e) {
switch (e.which) {
case UP:
setDirection('up');
onValueChange();
break; // Arrow Up
case DOWN:
setDirection('down');
onValueChange();
break; // Arrow Down
case PAGEUP:
setDirection('pup');
onValueChange();
break; // Page Up
case PAGEDOWN:
setDirection('pdown');
onValueChange();
break; // Page Down
default:
setDirection('none');
break;
}
});
el.keyup(function(e) {
setDirection('none');
});
el.keypress(function(e) {
if (el.val() == settings.mask) el.val(value);
var sText = getSelectedText();
if (sText != '') {
sText = el.val().replace(sText, '');
el.val(sText);
}
if (e.which >= 48 && e.which <= 57) {
var temp = parseFloat(el.val() + (e.which - 48));
if (temp >= settings.min && temp <= settings.max) {
value = temp;
raiseCallback(value);
}
else {
e.preventDefault();
}
}
});
el.blur(function() {
if (settings.mask == '') {
if (el.val() == '')
el.val(settings.min);
}
else {
el.val(settings.mask);
}
});
el.bind("mousewheel", function(e) {
if (e.wheelDelta >= 120) {
setDirection('down');
onValueChange();
}
else if (e.wheelDelta <= -120) {
setDirection('up');
onValueChange();
}
e.preventDefault();
});
if (this.addEventListener) {
this.addEventListener('DOMMouseScroll', function(e) {
if (e.detail > 0) {
setDirection('down');
onValueChange();
}
else if (e.detail < 0) {
setDirection('up');
onValueChange();
}
e.preventDefault();
}, false);
}
function raiseCallback(val) {
if (settings.callback != null) settings.callback(val);
}
function getSelectedText() {
var startPos = el.get(0).selectionStart;
var endPos = el.get(0).selectionEnd;
var doc = document.selection;
if (doc && doc.createRange().text.length != 0) {
return doc.createRange().text;
} else if (!doc && el.val().substring(startPos, endPos).length != 0) {
return el.val().substring(startPos, endPos);
}
return '';
}
function setValue(a, b) {
if (a >= settings.min && a <= settings.max) {
value = b;
} el.val(value);
}
function onValueChange() {
if (direction == 'up') {
value += settings.stepInc;
if (value > settings.max) value = settings.max;
setValue(parseFloat(el.val()), value);
}
if (direction == 'down') {
value -= settings.stepInc;
if (value < settings.min) value = settings.min;
setValue(parseFloat(el.val()), value);
}
if (direction == 'pup') {
value += settings.pageInc;
if (value > settings.max) value = settings.max;
setValue(parseFloat(el.val()), value);
}
if (direction == 'pdown') {
value -= settings.pageInc;
if (value < settings.min) value = settings.min;
setValue(parseFloat(el.val()), value);
}
raiseCallback(value);
}
function setClass(name) {
el.removeClass('up').removeClass('down');
if (name != '') el.addClass(name);
}
});
}
});
})(jQuery);
Why and where does this alter the passing value of a function attached to the < INPUT > ?
At the url http://www.candyundies.com/template_non_product.php, I am using an autocomplete script on the search box for suggestions. I have tested and is working in current versions of Chrome, Safari, Opera, Firefox and IE 8. However, I noticed in IE 8, it is throwing an Object expected error after the first letter is typed in the search box but the script continues to work flawlessly. I'm sure it is a syntax error or something small I have overlooked but I cannot seem to find the problem. Any help would be much appreciated.
Contents of autocomplete.js:
// global variables
var acListTotal = 0;
var acListCurrent = -1;
var acDelay = 100;
var acURL = null;
var acSearchId = null;
var acResultsId = null;
var acSearchField = null;
var acResultsDiv = null;
function setAutoComplete(field_id, results_id, get_url) {
// initialize vars
acSearchId = "#" + field_id;
acResultsId = "#" + results_id;
acURL = get_url;
// create the results div
$("#auto").append('<div id="' + results_id + '"></div>');
// register mostly used vars
acSearchField = $(acSearchId);
acResultsDiv = $(acResultsId);
// on blur listener
acSearchField.blur(function(){ setTimeout("clearAutoComplete()", 100) });
// on key up listener
acSearchField.keyup(function (e) {
// get keyCode (window.event is for IE)
var keyCode = e.keyCode || window.event.keyCode;
var lastVal = acSearchField.val();
// check an treat up and down arrows
if(updownArrow(keyCode)){
return;
}
// check for an ENTER or ESC
if(keyCode == 13 || keyCode == 27){
clearAutoComplete();
return;
}
// if is text, call with delay
setTimeout(function () {autoComplete(lastVal)}, acDelay);
});
}
// treat the auto-complete action (delayed function)
function autoComplete(lastValue) {
// get the field value
var part = acSearchField.val();
// if it's empty clear the resuts box and return
if(part == ''){
clearAutoComplete();
return;
}
// if it's equal the value from the time of the call, allow
if(lastValue != part){
return;
}
// get remote data as JSON
$.getJSON(acURL + part, function(json){
// get the total of results
var ansLength = acListTotal = json.length;
// if there are results populate the results div
if(ansLength > 0){
var newData = '';
// create a div for each result
for(i=0; i < ansLength; i++) {
newData += '<div class="unselected">' + json[i] + '</div>';
}
// update the results div
acResultsDiv.html(newData);
acResultsDiv.css("display","block");
// for all divs in results
var divs = $(acResultsId + " > div");
// on mouse over clean previous selected and set a new one
divs.mouseover( function() {
divs.each(function(){ this.className = "unselected"; });
this.className = "selected";
});
// on click copy the result text to the search field and hide
divs.click( function() {
acSearchField.val(this.childNodes[0].nodeValue);
clearAutoComplete();
});
} else {
clearAutoComplete();
}
});
}
// clear auto complete box
function clearAutoComplete() {
acResultsDiv.html('');
acResultsDiv.css("display","none");
}
// treat up and down key strokes defining the next selected element
function updownArrow(keyCode) {
if(keyCode == 40 || keyCode == 38){
if(keyCode == 38){ // keyUp
if(acListCurrent == 0 || acListCurrent == -1){
acListCurrent = acListTotal-1;
}else{
acListCurrent--;
}
} else { // keyDown
if(acListCurrent == acListTotal-1){
acListCurrent = 0;
}else {
acListCurrent++;
}
}
// loop through each result div applying the correct style
acResultsDiv.children().each(function(i){
if(i == acListCurrent){
acSearchField.val(this.childNodes[0].nodeValue);
this.className = "selected";
} else {
this.className = "unselected";
}
});
return true;
} else {
// reset
acListCurrent = -1;
return false;
}
}
Issue resolved. See comment by ocanal.