I have an onclick function to navigate from one "page" to another (it's not actually navigating, just imitates it):
$('.button').on('click', function(){
$('.home').css('display','none');
var newPage = $('.'+this.id);
goTo(newPage);
});
goTo simplified for reference:
function goTo(page){
$(page).css('display', 'block');
}
This works perfectly fine. All of the navigation buttons have the class of button, and also an ID that matches the class name of the different "pages". Click #page1, display .page1, etc.
My problem is now I'm having to rewrite my code to do the same thing for other elements - trying to rewrite this with arguments doesn't work for this in particular.
Here's what I'm trying:
function goToPage(link, destination){
link.click(function(){
$('.home').css('display','none');
goTo(destination);
}
}
and calling it as:
goToPage($('#page1'), $('.page1'));
works fine, however:
goToPage($('.button'), $('.'+this.id));
doesn't.
I suppose I'm misunderstanding how "this" is working in this context. I thought it would only determine what "this" is when the argument is called.
So my question is: can "this" be used as an argument in this way, am I slightly off with the logic or am I a complete idiot?
Fiddle: https://jsfiddle.net/hek0ptca/13/
To explicitly answer your question, no, this cannot be used as an argument in this case because it points to nothing.
goToPage($('.button'), $('.'+this.id));
In this context, this points to "undefined". Try running console.log(this.id);at the same scope of the code mentioned above and check your browser's console. It returns "undefined".
A good way to think about this is that you need something for it to reference. Scope matters. If there is nothing for this to reference, you will always get "undefined" as a value. Typically this is used inside a function where an object has already been referenced, for example, inside your event handler:
$('.button').click(function(){
$('#home').css('display', 'none');
goTo($('.'+this.id));
});
This will work in this case because this will refer back to the object that is being operated on, the .button class.
Related
I don't have any trouble with this code but I am very curious as to why the function below seems to need an underscore in its name.
function _clear()
{
document.getElementById("test").innerHTML = "";
}
The function _clear() only executes after clicking the button if the function name contains an underscore.
<button type="submit" onClick="_clear()">Clear</button>
According to the MDN, clear() is a method of the Document object, which one might call by writing document.clear(). But, since this method is deprecated one ought not to call it at all. In fact, in HTML5, the method does nothing (see HTML5 spec).
So, until this method is actually removed from the Document object, one might conclude that a potential conflict exists in having a user-defined function with the same name as that of the Document's method. That said, the following code runs just fine using Google Chrome (Version 49.0.2623.112 m):
var d = document;
d.g = d.getElementById;
function clear()
{
d.g("test").innerHTML = "";
}
var test = d.g("test");
test.onmouseover=clear;
See demo
It's unlikely that there is a conflict between clear() and document.clear(). I wrote a user-defined function that uses the same name as another document method and the code ran flawlessly; see here.
Apparently, when the onclick event attribute is given the user-defined function "clear()" there is some kind of confusion with clear() being associated with document.clear(); see here and read the excellent explanation in the official answer. In brief, the issue boils down to "...the Document object is in the scope chain before the Window object (...)" (see JavaScript: The Definitive Guide).
If for some reason you were determined for the code to work, here's how to specify the correct context:
HTML:
<div id="test">a test to see if this will clear</div>
<button id="but" onclick="window.clear()">Clear</button>
So, the user-defined function actually becomes a method of the Window object, along side the built-in ones like window.open(), allowing the code to execute; see here.
Note, the best way to have an action occur when a click event occurs is to put this line in your JavaScript code given a button with an id of "but":
but.addEventListener('click',clear);
See demo.
That's because clear() is a function that already exists in JavaScript. You could also add the underscore to the end or add another c or do anything so that the function has a different name.
I am a beginner in javascript. and have no experience in programming, at all.
So I'd like you to be generous to beginner.
And here is my question.
I'm trying to code javascript unobtrusively.
So I put in all of my js codes into external js file. for example : test.js
and deleted these codes. to do unobtrusive js coding. for example :
and I tried to use these 2 methods :
variable.onclick=test(arg1, arg2);
variable.addEventListener('click',test(arg1, arg2),true);
but these triggers didn't work.
to put it delicately, function test(arg1, arg2) worked right after dom loding finished. regardless of activating 'click' trigger.
So I spent several hours solving this problem, and finally got a solution. this is it.
variable.onclick = function(){
variable.addEventListener('click',test('arg1','arg2'),true);
}
I wanna know why first two methods didn't work, and why that solution works well.
I solved the problem, but don't know why, and how...
In JavaScript, when you reference a function by name and follow that reference by a parenthesized list of arguments, that means that you want to call the function, right then and there. Thus a statement like
variable.onclick=test(arg1, arg2);
will assign to the "onclick" property the value obtained by calling the "test" function. In other words that statement means
Please call the function "test" passing it "arg1" and "arg2", and assign whatever it returns to the "onclick" property of the object referenced by "variable".
An event handler must be a function, however, and your "test" handler probably returns either nothing, or something that's not a function. So it didn't work.
Your solution, however, is also incorrect. You're successfully assigning a function to the handler property, but your function is itself installing another event handler. There's no reason to do that here, and in general setting up event handlers from within other event handlers is a suspicious practice. All you need is:
variable.onclick = function() { test(arg1, arg2); };
variable.onclick requires a function declaration by design. In your case you could have just done
variable.onclick = function(){
test(arg1,arg2);
};
The way you did it won't work because you're not giving the click handler any instructions. The corrections I have made say that when the variable (the one with the click handler attached) is clicked trigger this function that will in turn trigger the test function.
Same thing goes for the second one
variable.addEventListener('click', function(){
test(arg1,arg2);
});
This works again because you are saying when this variable is clicked run the function that will trigger the test function.
Basically you are trying to assign the result of running a function, the test function as a task for the click handler to run. This won't work except maybe your test function returns a function that contains code that you want to run when the click event is triggered. Hope this helps.
I am learning to program in Javascript. I have created a jsfiddle here - http://jsfiddle.net/vvMRX/1/
function turnRed(node,f){
setTimeout(f,2000,[node]);
}
(function pageLoaded(){
turnRed(document.body,function(node){
alert(node);node.style.backgroundColor = '#ff0000';
});
})();
I am trying to use a setTimeout call on a function to change the body background color. I pass document.body as a node. In the callback, I change the node.style.backgroundColor but it does not work. Interestingly enough, using document.body.style.backgroundColor directly works. If I put an alert(node), it correctly identifies it as html bodyelement.
What am I missing here?
Appreciate responses.
Here's the following error that's being thrown in your JS:
Uncaught TypeError: Cannot set property 'backgroundColor' of undefined
The reason for this is because in your setTimeout, you're passing node in an array. However, in your callback, you're accessing the node directly. Two ways of addressing this are:
Update your callback to access the node within the array.
(function pageLoaded(){
turnRed( document.body, function(node){
alert(node);
// Updated code below
node[0].style.backgroundColor = '#ff0000';
});
})();
The other way would be to update your setTimeout and pass node directly.
function turnRed(node,f){
setTimeout(f,2000,node);
}
Here's an updated fiddle: http://jsfiddle.net/vvMRX/3/
You mentioned that using document.body.style.backgroundColor worked - which makes sense - since document.body will point to the element that contains the content. For most pages, this is almost always the <body> element. However, for frameset documents, this would return the outer frame. (w3.org reference)
Finally, regarding the alert - what's up with that, right? You call alert(node), and it displays [object HTMLBodyElement], which means you were passing the correct element, right? (At least, that's what I would think too!)
What's actually happening is that alert is alerting the value of your array.
Here's a fiddle demonstrating that: http://jsfiddle.net/4Lf3J/
You should see three alerts.
In the first alert, I've updated the original alert to call node.constructor. Object.prototype.constructor will return a reference to the object that created the instance (MDN reference).
In this case, we'll see
function Array() { [native code] }
This hopefully will re-enforce the idea that you're passing an array.
The second alert is actually calling alert(document.body.constructor), which is what we EXPECTED to see originally. In this case, we see:
function HTMLBodyElement() { [native code] }
Finally, a third alert shows the values 1,2,3,4,5, which is just an alert of a simple array with those values (again, re-enforcing the idea that alerts will alert the value of an array - which is why you thought the alert was correct).
Hopefully this helps as you continuing learning JavaScript!
In your function turnRed you are passing node in an array. Try this:
function turnRed(node,f){
setTimeout(f,2000,node);
}
I tried this in the fiddle it works.
In this case i guess that you should use document.bgColor property directly
You can obtain more information and code samples here:
http://www.javascripter.net/faq/backgrou.htm
http://www.webcodingtech.com/javascript/change-background-color.php
Amongst other things, I have read:
what-does-this-mean
you-must-remember-this
mythical-methods
but they haven't solved 'this' problem I'm having with a piece of JavaScript.
I have a Section object that gets passed some XML which it uses to populate the section. In the Section object I append a div which has a specified index. The resulting jQuery object is pushed into a sections Array. The following code is from the Section object code:
sections.push($('#section' + p_sectionIndex));
this.showSection = function() {
this.show();
}
this.hideSection = function() {
this.hide();
}
sections[sections.length-1].on('show', this.showSection.call(sections[sections.length-1]));
sections[sections.length-1].on('hide', this.hideSection.call(sections[sections.length-1]));
Elsewhere I call sections[index].trigger('hide'); and sections[index].trigger('show');
The first of the links I mentioned above seemed to suggest this in a function depends on HOW it's called and that you could pass a reference to this into the function by using call. I know the showSection and hideSection function ARE being triggered - I just can't get the this in those functions to refer to the jQuery objects in the sections Array.
I have tried multiple variations of the above (excluding the call, using $(this) in the functions, adding the showSection and hideSection functions to the jQuery object - amongst others) but I'm kind of out of ideas.
Any help much appreciated!
this in an event handler is the element node that the event was bound to. If you want a jQuery object wrapping that node, use $(this)
Demo: http://jsfiddle.net/b36M6/
This of course assumes you revert back to the correct way of passing a function to the event binding.
When you use .call(), you're invoking the function immediately.
Since you want this to refer to the element, bound, just pas the function itself.
sections[sections.length-1].on('show', this.showSection);
sections[sections.length-1].on('hide', this.hideSection);
Now this in the showSection and hideSection methods will refer to the sections[] member to which it was bound.
I assume "show" and "hide" are some sort of custom events.
I am having trouble with this in Jquery. When I do that on my website, it returns me the window.width. I just want to access the element from within. This is an example.
<div class="section " style="width:400px"></div>
$( ".section" ).html($(this).width());
or
<div class="section "><p></p></div>
$( ".section p" ).html($(this).parent().width());
also here is JSFiddle jsfiddle.net/XY66w/1
I'm going to assume that when you attempt to write this code:
<div class="section " style="width:400px"></div>
$( ".section" ).html($(this).width());
What you're trying to do is show 400px inside the div.section. If that is what you're trying to do, then here's what's happening:
This statement:
$( ".section" ).html($(this).width());
if Javascript, or most other languages I know, is syntactically equivalent to this:
var newHTML = $(this).width();
$( ".section" ).html(newHTML);
As you can see, this isn't a jQuery issue - but more a JavaSciprt / any programming language problem. You're telling the browser to pass in a value to the .html() method, so it must calculate that value first, in the scope of the function that you're calling the method from. In this case, you're calling the method from the window or global scope (or some other undefined scope, so you will never get what you expect.
The simple fix is this:
var section = $('.section');
section.html(section.width());
On the other hand, there are some jQuery methods that accept functions and these are the ones that you seem to be thinking of in this case. For instance, things would be slightly different in case you were using the each method, which accepts a function:
$('.section').each(function(index, element){
$(this).html($(this).width());
});
In this case, you're passing in a function that jQuery will then call in the scope of each element that is matched by your selector.
The big difference is to differentiate when you're passing in a value and when you're passing in a function that will be evaluated later.
You can do what you want this way, I think:
$(".section").each(function() {
$(this).html($(this).width());
});
JavaScript, like a lot of common languages, is not a "lazy" language. An expression statement like yours is evaluated such that all the function parameters are determined before anything's actually called. By using the jQuery .each() API, you can act on each element of the selected set.
jQuery only binds this when it's calling a function, such as an event handler, a callback function, a function supplied to something like $.each, etc.
In your examples, you're just supplying an argument to a jQuery method, and it's not inside a function that was called by jQuery. So this just contains whatever the browser's context is, which is window for top-level code. It's not the element(s) matched by the selector .section.