Call function with params as another functions param - javascript

this has been bugging me, and I'd like to understand.
Let's say that I have a site, where some elements need to be switched at a certain window size. So I've created a function that I can call with any elements.
function switcher (one, two) {
if (win.width() < 900) {
one.insertAfter(two);
} else {
one.insertBefore(two);
}
}
var frst = div.find('.first');
var scnd = div.find('.second');
My question is: this is working:
win.on('resize', function () {
switcher(frst, scnd);
});
this is NOT working, and WHY?
win.on('resize', switcher(frst, scnd));
Thanks!

Related

Carousel of Images Will Not Advance (HTML/JavaScript)

I am attempting to have the carousel start immediately upon visiting the page and cycle through a series of images every 2.5 seconds, however it will not advance past the first image. I've looked around here and w3schools but haven't been able to locate where my issue is. Any help would be greatly appreciated!
JavaScript is as follows:
window.onload slideShow();
var i=0;
function slideShow() {
window.setInterval("nextSlide()", 2500);
}
function nextSlide() {
var images["images/stockton0.jpg",
"images/stockton1.jpg"
"images/stockton2.jpg"
"images/stockton3.jpg"
"images/stockton4.jpg"
"images/stockton5.jpg"
"images/stockton6.jpg"
"images/stockton7.jpg"
"images/stockton8.jpg"
"images/stockton9.jpg"
"images/stockton10.jpg"]
var photo = document.getElementByClass("stocktonPics");
photo.src = images[i];
i++;
}
HTML code:
<img class="stocktonPics" src="images/stockton0.jpg" alt="slides">
A good tip is to check the console for errors.
There's nothing wrong with the flow of your code, besides some tips on making it more maintainable, readable, or semantically correct.
You simply forgot an = in window.onload = slideShow;
And document.getElementByClass doesn't exist. You need to use document.getElementsByClassName(...) to get an array of elements with that class, and finally get its first item with [0] like so:
var photo = document.getElementsByClassName("stocktonPics")[0];
Note that slideShow no longer has the () to call it, when window.onload is assigned to it. This is because you're assigning window.onload to the slideShow function, not the result of calling slideShow(), which in this case is undefined, as nothing is returned.
Your image array should be assigned in this way: var images = [ a, b, c ]
The other thing you should do is keep the array of images outside the scope of the function, so you can use it more easily and change it, rather than creating one (if you don't count optimizations) ever time the function is called. And lastly, window.setInterval( a, b ) can take either a string that will be eval()ed (or equivalent to it), which is what you did, or a function itself. In your case, what you want is simply the function: window.setInterval( nextSlide, 2500 ).
Here's the final full code:
var i=0;
var images=[
"images/stockton0.jpg",
"images/stockton1.jpg",
"images/stockton2.jpg",
"images/stockton3.jpg",
"images/stockton4.jpg",
"images/stockton5.jpg",
"images/stockton6.jpg",
"images/stockton7.jpg",
"images/stockton8.jpg",
"images/stockton9.jpg",
"images/stockton10.jpg" ];
function slideShow() {
window.setInterval( nextSlide, 2500);
}
function nextSlide() {
var photo = document.getElementsByClassName("stocktonPics")[0];
photo.src = images[i];
i++;
}
window.onload = slideShow;
getElementsByClass
method is will get a like array elements object,
so, you should use [0] to get the first element object and set src attr.
var pics = document.getElementsByClassName("stocktonPics")
It's a like array elements object
var firstPic = document.getElementsByClassName("stocktonPics")[0]
It's a element object
let i = 0;
const images = ["images/stockton0.jpg",
"images/stockton1.jpg",
"images/stockton2.jpg",
"images/stockton3.jpg",
"images/stockton4.jpg",
"images/stockton5.jpg",
"images/stockton6.jpg",
"images/stockton7.jpg",
"images/stockton8.jpg",
"images/stockton9.jpg",
"images/stockton10.jpg"];
const stockton = document.getElementsByClassName("example")[0];
const slideShow = () => {
window.setInterval(nextSlide, 2500);
}
const nextSlide = () => {
stockton.src = images[i];
if(i >= images.length - 1) {
i = 0;
} else {
i++;
}
console.log(i, stockton)
}
slideShow()
<img class="example">

jQuery Not Defined within a function

Alright, here's a puzzler. I've got a jQuery function to display a PHP generated list of announcements for a website via .fadeIn/.fadeOut; the very first thing loaded on the page is jQuery 1.11.xx from a CDN. I'm running Bootstrap, fullCalendar, SmartMenus, etc., and jQuery is most definitely loading.
Except within the setInterval() to update the announcement. This is rough-code, some functionality isn't present, but to my mind it should be doing an animation.
var announcementArray = [];
var announcementSource = "../announcements.php";
var totalAnnc;
$.getJSON(announcementSource, function(data) {
announcementArray = data.concat();
totalAnnc = announcementArray.length;
});
var count = 0;
var fadeAnnc = function() {
$('#announcementArea').text(announcementArray[count].announceText);
$('#announcementArea').fadeIn('slow',function() {
$('#announcementArea').css('display','block');
}).delay(2000).fadeOut('slow',function() {
count = (count + 1) % totalAnnc;
});
};
setInterval(function() {
fadeAnnc();
}, 3000);
Instead, when I run the page, I get a "function not defined" error for any jQuery function that's called within the setInterval(). If I call using document.getElementById('announcementArea').innerHTML = etc., it works, but doing the fade in/out via DOM manipulation seems to be more work than is needed when jQuery is available and working everywhere else on the page.
I've tried a few scope adjustments and have been working on what should be simple code for the last 5 hours. So, where's my glaring error? ;)
Not sure what kind of scope issue you are having (looks like it's the result of unposted code, as everything in your question looks OK), but if you want a fairly foolproof way of passing along the jQuery object, you could always pass it as a parameter:
var fadeAnnc = function($) {
$('#announcementArea').text(announcementArray[count].announceText);
$('#announcementArea').fadeIn('slow',function() {
$('#announcementArea').css('display','block');
}).delay(2000).fadeOut('slow',function() {
count = (count + 1) % totalAnnc;
});
};
setInterval(function() {
fadeAnnc($);
}, 3000);
Based on your updated answer, here's another possible solution:
(function($){
var announcementArray = [];
var announcementSource = "../announcements.php";
var announcementSpace = "#announcementArea";
$.getJSON(announcementSource, function(data) {
announcementArray = data.concat();
if (announcementArray.length === 0) {
$('#anncRow').css('display','none');
}
});
var count = 0;
var masterCount = 0;
var totalAnnc = announcementArray.length;
var timer;
var fadeAnnc = function() {
if (announcementArray.length > 0) {
$(announcementSpace).html(announcementArray[count].announceText);
$(announcementSpace).fadeIn(750, function() {
$(announcementSpace).css('display','block');
}).delay(4500).fadeOut(750, function() {
$(announcementSpace).css('display','hidden');
});
}
count += 1;
if ((count % announcementArray.length) == 0) {count = 0}
};
setInterval(fadeAnnc, 6000);
}(jQuery));
$ is defined as a function parameter and thus overrides the globally scoped $ within the function body, protecting it's definition for your code. This is actually exactly what jQuery recommends when creating an extension.
My previous answer - scratch that:
The issue was more interesting - somewhere between the SmartMenu plugin and the LibraryThing book display widget there is a jQuery conflict created. This explains why - depending on the load order - different parts would break, but always the setInterval(), which always loaded after SmartMenu and LibraryThing.
So, my somewhat messy solution is to release the $ at the beginning of the script and reclaim it at the end so on other pages jQuery has access to it, like so:
jq = jQuery.noConflict();
var announcementArray = [];
var announcementSource = "../announcements.php";
var announcementSpace = "#announcementArea";
jq.getJSON(announcementSource, function(data) {
announcementArray = data.concat();
if (announcementArray.length === 0) {
jq('#anncRow').css('display','none');
}
});
var count = 0;
var masterCount = 0;
var totalAnnc = announcementArray.length;
var timer;
var fadeAnnc = function() {
if (announcementArray.length > 0) {
jq(announcementSpace).html(announcementArray[count].announceText);
jq(announcementSpace).fadeIn(750, function() {
jq(announcementSpace).css('display','block');
}).delay(4500).fadeOut(750, function() {
jq(announcementSpace).css('display','hidden');
});
}
count += 1;
if ((count % announcementArray.length) == 0) {count = 0}
};
setInterval(fadeAnnc, 6000);
$ = jQuery.noConflict();
Use closures (which is considered good practice anyways):
(function($) {
var your_function = function() {
$(...);
};
setTimeout(function() {
your_function();
});
}(jQuery));
Using closures creates a sort of 'sandbox' for your code, so you don't have to worry about overwriting any variables declared in a parent scope (such as the dollar-sign $ used by jQuery).

Is $(window).scrollTop() the correct statement?

I'm trying to build a function like this one:
var t =$('#top');
var q1=$('#fe1');
var q2=$('#fe2');
var q3=$('#fe3');
var q4=$('#fe4');
var q5=$('#fe5');
var win = $(window);
var doc=$(document);
var wins = win.scrollTop();
var docs = doc.scrollTop();
function next (){
if (wins == docs) {
q1.ScrollTo();
}
else if (wins == q1.scrollTop()) {
q2.ScrollTo();
}
else if (wins == q2.scrollTop()) {
q3.ScrollTo();
}
else if (wins == q3.scrollTop()) {
q4.ScrollTo();
}
else if (wins == q4.scrollTop()) {
q5.ScrollTo();
}
}
I want to go scrolling to the next section. To do so, the code checks in which section I am so it knows which section to scroll to. But I think $(window).scrollTop() is not what I am looking for.
I want a statement that returns the distance between the top of the page and the top of what I am displaying. Maybe i have to do a more complex operation. Do you know how can i get this?
Thanks.
This problem is quite simple to solve even without jQuery or similar in plain JavaScript. Here it is for your example:
var next = (function (sections) {
function getTop(node) {
return node ? node.offsetTop + getTop(node.offsetParent) : 0;
}
return function () {
var i, nodeTop, top = window.pageYOffset;
for (i = 0; i < sections.length; i += 1) {
nodeTop = getTop(document.getElementById(sections[i]));
if (nodeTop > top) {
window.scrollTo(window.pageXOffset, nodeTop);
return;
}
}
};
}(['top', 'fe1', 'fe2', 'fe3', 'fe4', 'fe5']));
The code is quite general, so you can pass any section ids you want (they just need to appear in the correct order).
We use two standard DOM properties/functions here window.pageYOffset and window.scrollTo() to get and set vertical offset of the window (window.pageXOffset is used to keep horizontal offset the same). To get the vertical offset of the section start I defined getTop function using simple recursion (jQuery uses similar code IMHO).
Resulting function next() is defined in a self-invoking closure to hide the implementation and helper function. To use it after this code is run, you simply call
next();
I tested this code, so I am quite confident it works :).

Difficulty developing unique dynamic onclick events in Javascript

I am working with a decent sized set of data relating to objects on the page and some objects need links applied to them onclick. The link to connect to is part of the dataset and I build a string for the link with the variable linkTarget and apply it like so.
if (dataTag[i][3]==true){
if(prepend==undefined || prepend=="undefined"){
var linkTarget=ResultsJSON["targetUrl"];
ele.onclick = function(){
window.open(linkTarget);
};
} else {
var linkTarget=prepend+ResultsJSON["targetUrl"];
ele.onclick = function(){
window.open(linkTarget);
};
}
ele refers to an element picked up with getElementByID. Now I am going through quite a few objects and the problem I have is the onclick for every object is the last value of linkTarget. This is all contained in a function and link target is a local variable so I have no idea why. I have tried using an array with something like
ele.onclick=function(){window.open(linkTarget[linkTarget.length-1]);};
and even
ele.onclick=function(){window.open(linkTarget.valueOf());};
with the same results. I am at a loss now and would appreciate any help.
Use Array.forEach() to iterate your data and watch your troubles melt away.
dataTag.forEach(function (item) {
if (item[3]==true) {
var linkTarget = "";
if (prepend==undefined || prepend=="undefined") {
linkTarget = prepend;
}
linkTarget += ResultsJSON.targetUrl;
ele.onclick = function () {
window.open(linkTarget);
};
}
});
See this compatibility note for using Array.forEach() in older browsers.
You're in a loop — therefore, you need to put your things-to-be-executed in another function, like so:
if(dataTag[i][3]) {
if(prepend) {
(function(linkTarget) {
ele.onclick = function() {
window.open(linkTarget);
};
})(ResultsJSON.targetUrl);
} else {
(function(linkTarget) {
ele.onclick = function() {
window.open(linkTarget);
};
})(ResultsJSON.targetUrl);
}
I also made some general corrections.

How do I run an object's method onEvent in javascript?

I just started using javascript and I'm missing something important in my knowledge. I was hoping you could help me fill in the gap.
So the script I'm trying to run is suppose to count the characters in a text field, and update a paragraph to tell the user how many characters they have typed. I have an object called charCounter. sourceId is the id of the text area to count characters in. statusId is the id of the paragraph to update everytime a key is pressed.
function charCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
}
There is one method called updateAll. It updates the count of characters and updates the paragraph.
charCounter.prototype.updateAll = function() {
//get the character count;
//change the paragraph;
}
I have a start function that is called when the window loads.
function start() {
//This is the problem
document.getElementbyId('mytextfield').onkeydown = myCounter.updateAll;
document.getElementbyId('mytextfield').onkeyup = myCounter.updateAll;
}
myCounter = new charCounter("mytextfield","charcount");
window.onload = start;
The above code is the problem. Why in the world can't I call the myCounter.updateAll method when the event is fired? This is really confusing to me. I understand that if you call a method likeThis() you'll get a value from the function. If you call it likeThis you are getting a pointer to a function. I'm pointing my event to a function. I've also tried calling the function straight up and it works just fine, but it will not work when the event is fired.
What am I missing?
Thanks for all the answers. Here's three different implementations.
Implementation 1
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
};
CharCounter.prototype.updateAll = function() {
this.count = document.getElementById(this.sourceId).value.length;
document.getElementById(this.statusId).innerHTML = "There are "+this.count+" charactors";
};
function start() {
myCharCounter.updateAll();
document.getElementById('mytextfield').onkeyup = function() { myCharCounter.updateAll(); };
document.getElementById('mytextfield').onkeydown = function() { myCharCounter.updateAll(); };
};
myCharCounter = new CharCounter('mytextfield','charcount');
window.onload = start;
Implementation 2
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
};
CharCounter.prototype.updateAll = function() {
this.count = document.getElementById(this.sourceId).value.length;
document.getElementById(this.statusId).innerHTML = "There are "+ this.count+" charactors";
};
CharCounter.prototype.start = function() {
var instance = this;
instance.updateAll();
document.getElementById(this.sourceId).onkeyup = function() {
instance.updateAll();
};
document.getElementById(this.sourceId).onkeydown = function() {
instance.updateAll();
};
};
window.onload = function() {
var myCounter = new CharCounter("mytextfield","charcount");
myCounter.start();
};
Implementation 3
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
};
CharCounter.prototype.updateAll = function() {
this.count = document.getElementById(this.sourceId).value.length;
document.getElementById(this.statusId).innerHTML = "There are "+this.count+" charactors";
};
function bind(funcToCall, desiredThisValue) {
return function() { funcToCall.apply(desiredThisValue); };
};
function start() {
myCharCounter.updateAll();
document.getElementById('mytextfield').onkeyup = bind(myCharCounter.updateAll, myCharCounter);
document.getElementById('mytextfield').onkeydown = bind(myCharCounter.updateAll, myCharCounter);
};
myCharCounter = new CharCounter('mytextfield','charcount');
window.onload = start;
I think you are having problems accessing your instance members on the updateAll function, since you are using it as an event handler, the context (the this keyword) is the DOM element that triggered the event, not your CharCounter object instance.
You could do something like this:
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
}
CharCounter.prototype.updateAll = function() {
var text = document.getElementById(this.sourceId).value;
document.getElementById(this.statusId).innerHTML = text.length;
};
CharCounter.prototype.start = function() {
// event binding
var instance = this; // store the current context
document.getElementById(this.sourceId).onkeyup = function () {
instance.updateAll(); // use 'instance' because in event handlers
// the 'this' keyword refers to the DOM element.
};
}
window.onload = function () {
var myCharCounter = new CharCounter('textarea1', 'status');
myCharCounter.start();
};
Check the above example running here.
The expression "myCounter.updateAll" merely returns a reference to the function object bound to "updateAll". There's nothing special about that reference - specifically, nothing "remembers" that the reference came from a property of your "myCounter" object.
You can write a function that takes a function as an argument and returns a new function that's built specifically to run your function with a specific object as the "this" pointer. Lots of libraries have a routine like this; see for example the "functional.js" library and its "bind" function. Here's a real simple version:
function bind(funcToCall, desiredThisValue) {
return function() { funcToCall.apply(desiredThisValue); };
}
Now you can write:
document.getElementById('myTextField').onkeydown = bind(myCounter.updateAll, myCounter);
You can:
function start() {
//This is the problem
document.getElementbyId('mytextfield').onkeydown = function() { myCounter.updateAll(); };
document.getElementbyId('mytextfield').onkeyup = function() { myCounter.updateAll(); };
}
In ASP.Net Ajax you can use
Function.createDelegate(myObject, myFunction);
I want to do something like this but simpler.
The idea is to have the user click on bolded text and have a text field appear where they can change all the values of a role-playing character. Then when the value is changed, have the text field disappear again replaced by the updated bolded text value.
I can do this already using an annoying text box alert. But I would rather have something similar to this below to replace all that.
I have searched for months and CMS is the closest to answering my question in the simplest way with a full html example. Nobody else on the net could.
So my question is, how do I do this?
I have multiple objects(characters) and need this.elementId to make this work.
I've modified this example but it breaks if I try to add to it.
html>
head>
title>Sandbox
/head>
body>
input id="textarea1" size=10 type=text>
script>
function CharCounter(sourceId, statusId)
{this.sourceId=sourceId;
this.statusId=statusId;
this.count=0;
}
CharCounter.prototype.updateAll=function()
{text=document.getElementById(this.sourceId).value
document.getElementById(this.statusId).innerHTML=text
}
CharCounter.prototype.start=function()
{instance=this
document.getElementById(this.sourceId).onkeyup=function ()
{instance.updateAll()}
}
window.onload=function ()
{myCharCounter=new CharCounter('textarea1', 'status')
myCharCounter.start()
}
/script>
/body>
/html>

Categories