Code reuse with different event methods - javascript

I have two similar pieces of code in two different functions of my project
and I want to get rid of the repeating code. How can I do that?
1:
getArray("my-hand").forEach(function(elem){
$(elem).mouseover(function(){
$(this).css({'top': '1em'});
});
$(elem).mouseout(function(){
$(this).css({'top': '0em'});
});
$(elem).click(function(){
var cardNode = $(this).get(0);
//some jquery animation
play(cardNode,time);
});
})
and the second piece
2:
getArray("my-hand").forEach(function(elem){
$(elem).mouseover(function(){
$(this).css({'top': '1em'});
});
$(elem).mouseout(function(){
$(this).css({'top': '0em'});
});
$(elem).click(function(){
var cardNode = $(this).get(0);
//a function with another jquery animation
validateCardAndAddForCollection(checkNumber,cardNode,time);
});
})

One way is to put it in a function, and pass as an argument to that function a callback that will execute the desired code:
function handleCards (cb) {
getArray("my-hand").forEach(function(elem){
$(elem).mouseover(function(){
$(this).css({'top': '1em'});
});
$(elem).mouseout(function(){
$(this).css({'top': '0em'});
});
$(elem).click(function(){
var cardNode = $(this).get(0);
//some jquery animation
cb(cardNode);
});
});
}
handleCards(function (cardNode) {
play(cardNode, time);
});
handleCards(function (cardNode) {
validateCardAndAddForCollection(checkNumber,cardNode,time);
});

I'm assuming that the main re-usable logic is the setting up of the events. In that case, I would use a setupHandEvents method to do all of the boring stuff, but pass it a different method to represent it's click handler.
function setupHandEvents (hand, handler){
getArray(hand).forEach(function (elem) {
$(elem).mouseover(function () {
$(this).css({'top': '1em'});
});
$(elem).mouseout(function () {
$(this).css({'top': '0em'});
});
$(elem).click(function (){
handler($(this).get(0));
});
});
}
setupHandEvents('my-hand', function (cardNode) {
play(cardNode, time);
});
setupHandEvents('my-hand', function (cardNode) {
validateCardAndAddForCollection(checkNumber, cardNode, time);
});
Update
You've commented on the other answer that you have these re-used pieces of code wrapped up inside another function (one that delivers variables checkNumber and time from elsewhere. Here is how you would use my setupHandEvents method with the code you posted in that comment:
var func1 = function(time){
setupHandEvents('my-hand', function (cardNode) {
play(cardNode, time);
});
}
var func2 = function(checkNumber, time){
setupHandEvents('my-hand', function (cardNode) {
validateCardAndAddForCollection(checkNumber, cardNode, time);
});
}

Related

jQuery select element after async function

I have a problem with selecting element after generating by async callback function.
How to do that?
My code:
$(document).ready(function() {
function1(function2);
//here i want to select generated element by id $('#select-id')
});
function function1(callback) {
$.getJSON('./ajax/results_get.php', function(data) {
console.log("function1");
callback();
});
}
function function2() {
console.log("function2");
}
EDIT:
Now i used callback, but i don't know how to make visible object created within function3 to the click button event.
$(document).ready(function() {
function1(function() {
function2(function() {
function3(function(){
var foo = $('#element');
});
});
});
$('#savebtn').click(function(){
//how to use assigned foo here?
});
});

How to override function in javascript ? casperjs then function

I want to check if the "login page" appear before each step :
Here is my code:
casper.then(function() {
checkIfRedirectedToLoginPage();
this.evaluate(function() {
document.getElementById("").click();
});
});
casper.then(function() {
checkIfRedirectedToLoginPage();
this.evaluate(function() {
});
});
function checkIfRedirectedToLoginPage(){
if loginPage{
this.then(function(){
this.sendKeys(x('//*[#id="user_name"]'), USER_NAME);
this.sendKeys(x('//*[#id="password"]'),PASSWORD);
this.click(x(//*[#id="login"]));
});
}
}
How it's possible to override casper.then without littering my code with the checkIfRedirectedToLoginPage function . thanks
it is possible to do this though it is not recommended. what I would suggest instead is to create a helper method that calls casper.then and accepts a function as a callback.
function myCasperThen(callback) {
return casper.then(function() {
checkIfRedirectedToLoginPage();
callback();
}
}

Javascript clearInterval with button click

I'm having issues getting clearInterval to work when I try to bind it to a button click. Also, apparently the function is starting on it's own... Here's my code
var funky = setInterval(function() {
alert('hello world');
}, 2000);
$('#start').click(function() {
funky();
});
$('#stop').click(function() {
clearInterval(funky);
});
Here's a js fiddle
You have forgot to add jquery library and have made wrong assignment, it needs to be inside callback function.
Working example:
var funky;
$('#start').click(function() {
funky = setInterval(function() {
alert('hello world');
}, 2000);
});
$('#stop').click(function() {
clearInterval(funky);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="start">start</button>
<button id="stop">stop</button>
First off, yes, when you assign a variable to a function, it self invokes.
Secondly, your click events are not working because you need assign the interval to the variable on the click, not invoke the function - there is no function to invoke, as you would see if you looked at your developer console.
Lastly, it is good practice to wrap the jQuery code in the document ready function to ensure all of your event handlers get bound properly.
$(function () {
var funky;
$('#start').click(function() {
funky = setInterval(function() {
alert('hello world');
}, 1000);
});
$('#stop').click(function() {
clearInterval(funky);
});
});
You're saving the wrong value. Try this:
var funky = function() {
alert('hello world');
}
var funkyId = setInterval(funky, 2000);
$('#start').click(function() {
funky();
});
$('#stop').click(function() {
clearInterval(funkyId);
});
Here I am giving you the idea.
declare a variable e.g. let x;
create a function which you want to bind with setInterval.
e.g.
function funky() {
alert("Hello World");
}
assign start.onclick to a function which will assign the setInterval to x.
e.g start.onclick = function(){
clearInterval(x); // to prevent multiple interval if you click more than one
x = setInterval(funky, 2000); // assign the setInterval to x
};
assign stop.onclick to clearInterval(x) to stop the interval.
e.g. stop.onclick = function() {
clearInterval(x); // to stop the interval
};
That's it. Easy right.

Migrating js file from prototype to jQuery does not work

I'm migrating files from prototype to jQuery.
prototype:
function hideEditableMarkers() {
$$('.edit_marker').each(function(el) {
el.hide();
});
$$('.show_marker').each(function(el) {
el.show();
});
}
Event.observe(window, 'load', hideEditableMarkers);
jQuery:
function hideEditableMarkers() {
jQuery('.edit_marker').each(function(el){
el.hide();
});
jQuery('.show_marker').each(function(el){
el.show();
});
}
jQuery(document).ready(hideEditableMarkers());
I don't know why it does not work.
The first parameter of the each callback function is the index of the element not the reference to it
so here is the jquery code
function hideEditableMarkers() {
$('.edit_marker').each(function(idx,el){
$(el).hide(); // You may use 'this' variable in here as it points to the current element as well
});
$('.show_marker').each(function(idx,el){
$(el).show();
});
}
This:
jQuery(document).ready(hideEditableMarkers());
should be:
jQuery(document).ready(hideEditableMarkers);
You need to pass the function reference to ready so it's executed as the callback handler for the DOM ready event. What you're currently doing is executing the function immediately (when the elements don't exist), then passing the return from that function (nothing) as the callback for .ready().
use $(this) inside each so it takes the current element... what you have is index and use index as jquery selector el.hide()
try this
function hideEditableMarkers() {
jQuery('.edit_marker').each(function(el){
$(this).hide();
});
jQuery('.show_marker').each(function(el){
$(this).show();
});
}
jQuery(document).ready(function(){
hideEditableMarkers() ;
});
//or
jQuery(document).ready(hideEditableMarkers);
I believe a function should be reusable:
/*global jQuery */
function toggleMarkers (hideSelector, showSelector) {
jQuery(hideSelector).each(function () {
jQuery(this).hide();
});
jQuery(showSelector).each(function () {
jQuery(this).show();
});
}
jQuery(document).ready(function ($) {
toggleMarkers('.edit_marker', '.show_marker');
});

Wait for animation function in javascript

I have the following methods in javascript:
Controller.prototype.changeScene = function (curScene, newScene) {
sf.scene.hide(curScene);
sf.scene.show(newScene, curScene);
sf.scene.focus(newScene);
};
And in another JS Class:
Test.prototype.handleHide = function () {
alert("SceneDialog.handleHide()");
$(".screenOverlay").fadeOut("slow");
$(".dialogBox").fadeOut("slow");
};
sf.scene.hide() calls the handleHide method. In handleHide there's some animation, but it's not shown. The Controller doesn't wait for it to be finished.
I tried $.when(sf.scene.hide()).done() without any luck.
Any suggestions?
You can use the jQuery queue to keep a list of animations that are queued to occur only after the previous one has completed.
sf.scene.hide(curScene);
sf.scene.show(newScene, curScene);
sf.scene.focus(newScene);
would become:
sf.scene.hide(curScene);
sf.scene.queue(function() {
$(this).show(newScene, curScene);
$(this).dequeue();
});
sf.scene.queue(function() {
sf.scene.focus(newScene);
$(this).dequeue();
});
You can use the promise() function of jquery to call a callback when ALL animations are over.
Try out:
Test.prototype.handleHide = function (callback) {
$(".screenOverlay,.dialogBox").each(
function(i) {
$( this ).fadeOut("slow");
}
);
$(".screenOverlay,.dialogBox").promise().done(callback);
};
And pass the callback as an argument to handleHide. Your changeScene function should look like this:
Controller.prototype.changeScene = function (curScene, newScene) {
sf.scene.hide(curScene, function() {
sf.scene.show(newScene, curScene);
sf.scene.focus(newScene);
});
};
if you are using jquery animation functions, jquery generally provides a complete parameter which will be called when the function is complete.
using fadeout:
$('#test').fadeOut('slow', function() {
// fadeout is finished!! do something
});

Categories