There must be a better way - change search as user input changes - javascript

I have a search filter that hides s as the user enters text into a form input. I need it to be dynamic, so that as the user changes their input, the filter refreshes. I accomplished this by having the filter clear on every keyup, but that causes the filter to be delayed and to flash when a word is typed quickly into the filter. You can see what I mean here:
http://cambridgefellows.com/directory-of-fellows/
Here is my jquery:
$(document).ready(function() {
$('input[name=searchFilterInput]').val('');
$('input[name=searchFilterInput]').keyup(function() {
var searchFilterVal = $('input[name=searchFilterInput]').val();
searchFilterVal = searchFilterVal.replace(/ /g, '-');
searchFilterVal = searchFilterVal.toLowerCase();
$('tr.hide').fadeIn('slow').removeClass('hide');
if(searchFilterVal == '') {
$('tr.hide').fadeIn('slow').removeClass('hide');
} else {
$('tr.fellows').each(function() {
var pattern = $(this).attr('class'); // the pattern to be matched
var match = pattern.match(searchFilterVal);//If pattern matches it returns the match
if(!match) {
$(this).fadeOut('normal').addClass('hide');
} else {
}
});
}
});
$('#searchForm').bind("keyup keypress", function(e) {
var code = e.keyCode || e.which;
if (code == 13) {
e.preventDefault();
return false;
}
});
});
I think there must be an easier way to handle this so that the filter dynamically updates as the user enter or alters their search text. Can someone more experienced than me look at this an enlighten me to the obvious thing that I'm overlooking? Thank you so much for your help.

Looks like you need a setTimeout and clearTimeout.
var timer;
$('input[name=searchFilterInput]').keyup(function() {
clearTimeout(timer);
timer = setTimeout(function() {
var searchFilterVal = $('input[name=searchFilterInput]').val();
searchFilterVal = searchFilterVal.replace(/ /g, '-');
searchFilterVal = searchFilterVal.toLowerCase();
$('tr.hide').fadeIn('slow').removeClass('hide');
if(searchFilterVal == '') {
$('tr.hide').fadeIn('slow').removeClass('hide');
} else {
$('tr.fellows').each(function() {
var pattern = $(this).attr('class'); // the pattern to be matched
var match = pattern.match(searchFilterVal);//If pattern matches it returns the match
if(!match) {
$(this).fadeOut('normal').addClass('hide');
} else {
}
});
}
}, 300);
});
That way whenever a user hits the next key, the timeout will be cleared from the previous keypress and the code will only execute for the current keypress.
Reduce the milliseconds if you feel it's not updating fast enough.

Related

Limit consecutive characters on keypress with javascript

i wrote this code for an information booth at a park, it works on html5 and javascript
function myFunction() {
var name = document.getElementById('name').value;
var nameFilter = /^(?!.*([A-Za-z0-9])\1{2})(?=.*[a-z])(?=.*\d)[A-Za-z0-9]+$/g;
if(nameFilter.test(name)) {
$('#name').keydown(function (e) {
if (e.keyCode == 8 || e.keyCode == 46) {
$(this).unbind(e).keypress();
}
else {
e.preventDefault();
//return false;
}
});
}
};
it is supposed to prevent more than one consecutive characters (the booth keyboard is kinda broken and on key press it puts like 3 to 5 times the pressed key)
so far i've accomplished to limit it to two characters, but then thanks to preventDefault() it does nothing, i used an unbind to restore it but still i've accomplished nothing and i need help with this, whether it be by this mean of any other
This version accounts for capitalizing letters with the shift key
var nameElement = $('#name');
var wasShiftKeyPressed;
var nameAfterFirstKeyDown;
nameElement.keydown(function(e) {
wasShiftKeyPressed = e.shiftKey;
setTimeout(function() {
nameAfterFirstKeyDown = nameAfterFirstKeyDown ? nameAfterFirstKeyDown : nameElement.val();
});
})
nameElement.keyup(function() {
if (wasShiftKeyPressed) {
wasShiftKeyPressed = false;
nameAfterFirstKeyDown = nameElement.val(); //Otherwise capitalization only works for first letter
}
else {
nameElement.val(nameAfterFirstKeyDown);
nameAfterFirstKeyDown = "";
}
});

Reset timeout on event with RxJS

I'm experimenting with RxJS (with the JQuery extension) and I'm trying to solve the following use case:
Given that I have two buttons (A & B) I'd like to print a message if a certain "secret combination" is clicked within a given timeframe. For example the "secret combination" could be to click "ABBABA" within 5 seconds. If the combination is not entered within 5 seconds a timeout message should be displayed. This is what I currently have:
var secretCombination = "ABBABA";
var buttonA = $("#button-a").clickAsObservable().map(function () { return "A"; });
var buttonB = $("#button-b").clickAsObservable().map(function () { return "B"; });
var bothButtons = Rx.Observable.merge(buttonA, buttonB);
var outputDiv = $("#output");
bothButtons.do(function (buttonName) {
outputDiv.append(buttonName);
}).bufferWithTimeOrCount(5000, 6).map(function (combination) {
return combination.reduce(function (combination, buttonName) {
return combination + buttonName;
}, "");
}).map(function (combination) {
return combination === secretCombination;
}).subscribe(function (successfulCombination) {
if (successfulCombination) {
outputDiv.html("Combination unlocked!");
} else {
outputDiv.html("You're not fast enough, try again!");
}
});
While this works fairly well it's not exactly what I want. I need the bufferWithTimeOrCount to be reset when button A is pressed for the first time in a new timeframe. What I'm looking for is that as soon as the secret combination is pressed (ABBABA) I'd like "Combination unlocked!" to be shown (I don't want to wait for the time window to be expired).
Throttle is the typical operator for the delaying with reactive resetting effect you want.
Here's how you can use throttle in combination with scan to gather the combination inputted before the 5 seconds of silence:
var evaluationStream = bothButtons
.merge(bothButtons.throttle(5000).map(function(){return "reset";})) // (2) and (3)
.scan(function(acc, x) { // (1)
if (x === "reset") return "";
var newAcc = acc + x;
if (newAcc.length > secretCombination.length) {
return newAcc.substr(newAcc.length - secretCombination.length);
}
else {
return newAcc;
}
})
.map(function(combination) {
return combination === secretCombination;
});
var wrongStream = evaluationStream
.throttle(5000)
.filter(function(result) { return result === false; });
var correctStream = evaluationStream
.filter(function(result) { return result === true; });
wrongStream.subscribe(function() {
outputDiv.html("Too slow or wrong!");
});
correctStream.subscribe(function() {
outputDiv.html("Combination unlocked!");
});
(1) We scan to concatenate the input characters. (2) Throttle waits for 5 seconds of event silence and emits the last event before that silence. In other words, it's similar to delay, except it resets the inner timer when a new event is seen on the source Observable. We need to reset the scan's concatenation (1), so we just map the same throttled Observable to "reset" flags (3), which the scan will interpret as clearing the accumulator (acc).
And here's a JSFiddle.

jQuery: Check if hash contains

I'm looking to try and check if the hash in the url contains a certain value before proceeding, I have a function that works like so:
$(window).load(function () {
var hash = window.location.hash,
number = $(hash).index(),
width = 403,
final = width * number;
setTimeout(function () {
$('.news-inner-wrap').animate({
'marginLeft': "-=" + final + "px"
});
}, 1000);
});
So if the hash is www.website.com/#news-item-03 it will slide the user horizontally along to the 3rd news story, this works great!. I only want this function to fire though if the hash contains news-item obviously the number after each will change, but if the hash begins with news-item then I want the function above to be fired, I'm not even sure it this is at all possible, any suggestions would be greatly appreciated!
No need for jQuery, this should work nicely
if (window.location.hash) {
if (window.location.hash.indexOf('news-item') == 1) { // not 0 because # is first character of window.location.hash
// it's at the start
}
else if (window.location.hash.indexOf('news-item') != -1) {
// it's there, but not at the start
}
else {
// not there
}
}
Use a regular expression:
var matches = hash.match(/^#news-item-([0-9]+)$/);
if (matches) {
var number = matches[1];
// Rest of your code
}

How to get my loop to start from the beginning after error detected

I am trying to get my loop to restart when it comes across an user input error. I need it to restart at the very beginning and not just the last question.
So below when it says validImput = false this is where I am trying to get it to restart.
{
var validInput = true;
var start = confirm('Add item to shoping cart');
if (start == true) {
// ask first question
var orderProductCodeArr = parseInt(prompt('Enter input: '), 10);
if (isNaN(orderProductCodeArr)) {
alert("input is not a valid number");
validImput = false
} else if (orderProductCodeArr < 0 || orderProductCodeArr >= PRODUCT_LIST.length) {
alert("code does not match any item");
validInput = false;
}
// ask second question
else if(validInput == true) {
var item = PRODUCT_LIST[orderProductCodeArr];
alert("item is: " + item);
}
// get quantity input
var quanityArr = parseInt (prompt('Enter quality amount'),10);
if (isNaN(quanityArr)) {
alert("input is not a valid number");
validInput = false;
}
} else {
document.writeln('still to come')
}
}
The usual method of starting something over is some sort of loop construct, often using while like this:
while (true) {
// your loop code here
// you can use break; to break out of the while loop
// anywhere to stop repeating
// you can use continue; to jump to the next iteration immediately
}
Or, sometimes you use a loop condition like this:
var doAgain = true;
while (doAgain) {
// within the loop, you set doAgain to false when you are done
// and don't want to repeat the loop again
}
try
function test()
{
for(var s=0;s<5;s++)
{
try
{
//body of the for loop
}catch(e){s=0;}
}
}

catch key and trigger function using jQuery or plain js

I have a textarea inside a form:
<textearea id="message"></textarea>
While typing, whenever a user types the character # inside the textarea, I want to trigger a function for every character typed afterwards and till the user hits enter or space bar.
How is this possible using jQuery or plain JS ?
You can use this :
var myCallback = function () {
//put your code here
}
(function (callback) {
var jMessage = $('#message'),
callbackCallable = false,
keycodeEnter = 13,
keycodeSpace = 32;
jMessage.keyup(function (e) {
var lastLetter = jMessage.val().slice(-1);
if (lastLetter === '#') {
callbackCallable = true;
} else if (e.keyCode === keycodeEnter || e.keyCode === keycodeSpace) {
callbackCallable = false;
} else if (callbackCallable) {
callback();
}
});
}(myCallback));
If you want to detect only typing you can listen for a key pressed event.
var anyHitYet = false;
jQuery('#massage').keydown(function (event) {
if (anyHitYet) return;
var key = event.keyCode;
if (key === 51) {
//call your function here
} else if (key === 13 || key === 32) {
anyHitYet = true;
}
});
Basically if it's 51 then # is hit so call your function if space or enter are hit your #-when-pressed-function won't be executed until you make anyHitYet=false again
Somebody might paste something though so then it is a different story
Not sure if the above answers do what the OP wants.
I think a second or third # should be monitored aswell, till a space or return ends monitoring.
// have a flag somewhere and initialize it to FALSE
var doMonitor = FALSE;
$('#message').keydown(function(event){
// trigger monitoring after # was tipped
// (only once till space or return reset)
if(event.keyCode == 51 && !doMonitor){
doMonitor = TRUE;
}
else if(event.keyCode == 32 || event.keyCode == 13)
doMonitor = FALSE;
else if(doMonitor){
// do whatever needs to be done
}
});
You may also add an attribute to your #message textarea and remove it (or change its value) instead of using a variable.
// for setting an attribute
.attr( attributeName, value )
// for removing it
.removeattr( attributeName )
look here http://api.jquery.com/removeAttr/ and here http://api.jquery.com/attr/

Categories

Resources