Another Easy jQuery Question - javascript

I have the bellow code, I wish to create an IF statement so the loadScript function is only called for a specific HREF. But when I try and alert the value of the href it returns "Undefined"...
Many Thanks,
J
$(document).ready(function()
{
$('.jNav').click(function()
{
$('#sandbox').load($(this).attr('href'),function()
{
alert("From here " + $(this).attr('href') + " to here.");
loadScript();
});
return false;
});
});

Your issue is just scoping. In your load() callback, this refers to the element you're calling load() on, which happens to be $('#sandbox'), and thus: no href. Usually what I do is something like this:
$('.jNav').click(function()
{
var self = this;
$('#sandbox').load($(this).attr('href'),function()
{
// Notice the use of self here, as we declared above
alert("From here " + $(self).attr('href') + " to here.");
loadScript();
});
return false;
});
Doing this ensures that you can still get to the thing that you clicked from inside the load() callback.

The problem is one of context: The call to $(this) in the alert refers to $('#sandbox') not $('.jNav'). Simply define a variable for you first reference.

When you are inside the callback for $('#sandbox').load, this refers to $('#sandbox'), and not to $('.jNav'). If you want to alert the href, save that (or a reference to this) in a variable.
$('.jNav').click(function(){
var that = this;
$('#sandbox').load($(this).attr('href'),function(){
alert($(that).attr('href'));
//...
});
}
OR
$('.jNav').click(function(){
var href = $(this).attr('href');
$('#sandbox').load($(this).attr('href'),function(){
alert(href);
//...
});
}

$(this) was the .jNav, but in your callback it's now the #sandbox. Pre-cache the variable at the point where it's presented to you, then use it wherever you like.
Improving slightly on Groovetrain's answer, I'd write:
$('.jNav').click(function(event) {
var $self = $(this);
var href = $self.attr('href');
$('#sandbox').load(href, function() {
alert("From here " + href + " to here.");
loadScript();
});
event.preventDefault(); // better than `return false`
});

Inside your innnermost function the context (this) is set to the #sandbox element. You'll want to get the href attribute from the .jNav element beforehand and store it in a variable.
Example code

Take care of what "this" is in what part of your function. In the innermost function, you are calling it from $('#sandbox'),which I suspect doesn't have a href attribute. the best solution would probably be to pass the value of the href into the function or store it in a variable.

$(document).ready(function()
{
$('.jNav').click(function()
{
$('#sandbox').load($(this).attr('href'),function()
{
alert("From here " + $(this).parent().attr('href') + " to here.");
loadScript();
});
return false;
});
});

Related

Google Tag Manager - storing id of a clicked div/button

Looked for the answer all over, tried reading seperatly but couldn't find an answer..
I have a site, on which Google Tag Manager is implemented, and I need to extract the id of a clicked button (or its parent).
this is my code:
function(){
$(document).ready(function(){
var editid;
$('div.uk-button').click(function() {
editid = $(this).attr('data-id');
});
return editid;
});
}
Thanks!
The simplest approach is to create the following custom javascript variable:
function(){
return $({{Click Element}}).attr('data-id');
}
This will return the data-id attribute for all events (including clicks).
Attach this variable to the relevant event tag, and use click class contains uk-button as the trigger.
You can remove the outer function and code like below.
$(document).ready(function () {
$('div.uk-button').click(function () {
var editid;
editid = $(this).attr('data-id');
alert(editid);
});
});
Hey it looks like you may be not be catching the returned value of the document ready callback.
For example, this returns undefined since the return of $(document).ready() callback is not being returned by the containing function:
function testfunc() {
$(document).ready(function(){
var editid = 'this is the return value';
return editid;
});
}
testFunc()
"returns undefined"
I'm guessing that you might be trying to set up a custom javascript variable in GTM. You can still use document ready to ensure the elements are present but the returned value needs to be returned by the outer function for it to be passed into the variable.
So your example should work as follows:
function(){
var editid;
$(document).ready(function(){
$('div.uk-button').click(function() {
editid = $(this).attr('data-id');
});
});
return editid;
}

binding html events to an instance of a controller class _within_ the constructor

Sorry, probably bit of a noob JS question regarding binding handlers to instances.
I am creating a controller instance with some data that will subsequently be used to process incoming events (the actual use case is composing complex d3 handlers with varying ajax urls and into which I compose the function(s) doing the actual tree update).
RequireJS and jquery are involved, but I suspect my issue has more to do with my specific binding code. I guess I could forego the use of 'this' since I have only one controller per page which can be a global. But this feels like it should be doable, if only I knew how to.
This is how I bind the controller to its target, from within the constructor (doing it outside the constructor seems to work):
function BtnMgr(msg, tgt_id) {
this.msg = msg;
this.tgt_id = tgt_id;
var selector = "#" + tgt_id;
$(selector).on("click", this.handleClick);
}
What is going wrong?
When I click on the button, 'this', in the handleClick refers to the html button, not to the controller instance.
If I call the controller instance method directly, 'this' is correct.
I've tried call or creating a wrapper function, as suggested in
How can I bind an event handler to an instance in JQuery?
$(selector).click(function(e) { BtnMgr.prototype.handleClick.call(this, e); });
My button click keeps seeing 'this' as the button, not the controller:
output
global var controller:BtnMgr.I am a button
this:[object HTMLButtonElement],type:
e:[object Object],type:Object
BtnMgr.handleClick:this.msg:undefined
Simplified version:
HTML
page4.html
<!DOCTYPE html>
<html>
<head>
<title>Page 4</title>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>
<script type="text/javascript">
requirejs.config({
baseUrl: '.',
paths: {
"jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min"
}
});
var controller;
require(["main4"], function(BtnMgr) {
controller = new BtnMgr("I am a button", "btn_click");
//this simulated call works - 'this' refers to the BtnMgr instance
controller.handleClick("dummy_btn");
});
</script>
</head>
<body>
<button id="btn_click">click me!</button>
</body>
</html>
RequireJS
main4.js
define(["jquery"], function($) {
function BtnMgr(msg, tgt_id) {
this.msg = msg;
this.tgt_id = tgt_id;
var selector = "#" + tgt_id;
$(selector).on("click", this.handleClick);
}
BtnMgr.prototype.toString = function(){
return "BtnMgr." + this.msg;
};
BtnMgr.prototype.handleClick = function(e) {
//I want 'this' to refer to the BtnMgr instance
//and e to the html element that got clicked...
console.log("global var controller:" + controller);
console.log("this:" + this + ",type:" + this.constructor.name);
console.log("e:" + e + ",type:" + e.constructor.name);
console.log("BtnMgr.handleClick:this.msg:" + this.msg);
};
//define is returning the constructor method for the object
return BtnMgr;
});
You could achieve (nearly) what you want with :
$(selector).on("click", this.handleClick.bind(this));
this will be the instance of BtnMgr and e.target will, as always, be the button.
However, that would fly in the face of convention and confuse anyone trying to understand your code, including yourself in 6 months time. In a click handler, this should always refer to the clicked element, as is natural.
If you really must have a reference from the handler back to the instance of BtnMgr that attached the click, then I might opt for "e-augmentation" like this :
function BtnMgr(msg, tgt_id) {
var that = this;
this.msg = msg;
this.tgt_id = tgt_id;
var selector = "#" + tgt_id;
$(selector).on("click", function(e) {
e.clickAttacher = that;
that.handleClick(e);
});
}
BtnMgr.prototype.toString = function(){
return "BtnMgr." + this.msg;
};
BtnMgr.prototype.handleClick = function(e) {
console.log("click attacher was instance of : " + e.clickAttacher.constructor.name); // BtnMgr
console.log("button id: " + e.target.id); // xxx
console.log("msg: " + e.clickAttacher.msg); // Hello World!
};
var b = new BtnMgr('Hello World!', 'xxx');
DEMO
Having done that, you have to ask whether it's really worthwhile defining handleClick in that way. Sure, if it's a monster function then yes, define it with BtnMgr.prototype...., but if it's only small, then define it in the constructor itself and take direct advantage of that being in the scope chain (as does the augmenter function above).
Try this when you bind your onClick:
function BtnMgr(msg, tgt_id) {
this.msg = msg;
this.tgt_id = tgt_id;
var selector = "#" + tgt_id;
$(selector).on("click", $.proxy(this.handleClick, this));
}
That would make sure that the 'this' variable in your callback is your class and not the clickevent.
You can read more about jQuery Proxy here: http://api.jquery.com/jquery.proxy/

Simple Javascript Calling function not working/don't know how to get it to work

I'm trying to call a function and not the alert and I thought it was as easy as just doing something like this: FunctionsName(); and delete the alert(''); but it's not working for me :(
Can someone please look at the code I have below and tell me what is wrong ?
Thank you so much!!
<script type="text/javascript">
var comper;
function checkComper() {
var onResponse = function(comperNow) {
if (comper === undefined) {
comper = comperNow;
return;
}
if (comper !== comperNow) {
// show a message to the visitor
alert("New Info Added"); // <--*** I WANT TO TAKE THIS OUT AND CALL $("#append").click(function(e)
comper = comperNow;
}
};
$.get('getlastupdate.php', onResponse);
}
var tid = setInterval(checkComper, 2000);
$(function() {
var $table = $("table.tablesorter");
$("#append").click(function(e) {
e.preventDefault();
$.get('updatetable.php', function(data)
{
$table
.find('tbody')
.html('')
.append(data);
$table.trigger("update", [true]);
});
});
/*........ and so on.... */
</script>
What about changin that :
alert("New Info Added");
to that :
$('#append').trigger('click');
It will simulate a click and trigger the function.
One thing important to distinguish:
alert("New Info Added") is a function. Actually, alert() is a function, being passed the parameter "New Info Added".
$('#append').click(function(e) { is not a function, at least, not in the same way. $('#append') is a jQuery selector function, which selects all elements with an id of "append". $('#append').click() is a function that sets a click event on all elements returned in the selector.
What the whole syntax of $('#append').click(function(e) { means is on its own a syntax error. What you're doing is telling the elements found in the selector what their click function should be. But the function(e) { says that it's the start of the code of the function. That line of code isn't complete until the ending }) - the } closing the function declaration and the ) closing the call to click.
So, you can't simply replace alert("New Info Added"), which is a complete function call, with $('#append').click(function(e) {, because it's a syntax error - you haven't completed the function(e) declaration, nor the click function call. You can trigger the click function, as Karl's answer told you. Or, you can use the shortcut:
$('#append').click()
Note that this is a full proper sentence, and can therefore replace the alert.

Defined function is not found

I have this function which is called in a for loop.
function printResult(name, i) {
$('#list').append("<a href='#' onClick='goto(" + i + ");' class='item'><H1>" + name + "</H1> </a>");
}
The a href-tags are appended as they should, but when I call the goto function firebug says: 'goto is not defined'
But it is!!
This is the function:
function goto(myPoint){
map.setCenter(new google.maps.LatLng(marker[myPoint-1].position.lat(), marker[myPoint-
1].position.lng()));
markerArr[myPoint-1]['infowindow'].open(map, markerArr[myPoint-1]);
}
I'm clueless as to why the function is not found. Does it have something to do with it being called in the appended a href-tag?
goto() is a terrible name for a function, because it's commonly used as a keyword in a lot of programming languages.
In Javascript, it is not a keyword. However, it is a reserved word, on the grounds that it may be used in future versions of the language. This alone may be causing JS to reject your function or fail to call it.
But even if it weren't a reserved, is could be seen as a potential ambiguity, and so would not be recommended for use.
Therefore, my suggestion would be to change the function name. With luck, it might magically start working.
Using jQuery click events like this:
Html:
function printResult(name, i) {
$('#list').append("<a href='#' rel='" + i + "' class='item'><H1>" + name + "</H1></a>");
}
Js:
$(document).on('click', 'a.item', function (e) {
goto($(this).attr("rel"));
});
But I recommend to rename the function goto to something else or do:
$(document).on('click', 'a.item', function (e) {
var myPoint = $(this).attr("rel");
map.setCenter(new google.maps.LatLng(marker[myPoint-1].position.lat(), marker[myPoint-
1].position.lng()));
markerArr[myPoint-1]['infowindow'].open(map, markerArr[myPoint-1]);
});
When you define event handlers by using onclick attributes, the definition of goto() must be global, i.e. window.goto must exist.
More importantly, this is not the jQuery way; event handlers should be defined in JavaScript code rather than HTML.
function printResult(name, i)
{
var $title = $('<h1 />', { text: name }),
$anchor = $('<a href="#" class="item" />')
.append($title)
.on('click', {
index: i
}, moveToIndex)
.appendTo('#list');
}
// this is the click handler
function moveToIndex(evt)
{
// evt.data.index = the value of i
}
I have renamed your goto() function into moveToIndex() which is somewhat more descriptive. This should not have the same scope issues as your current code.
You are using onClick='goto(" + i + ");'. Use onclick ='goto("+i+")' instead, don't use a semicolon

Javascript scope question: Can't change element via 'this' obj passed to function, but I can using longhand approach

REVISED QUESTION (SEE BELOW FOR ORIGINAL):
Here is an example of a simple ajax load with an event binding on an element within the loaded content:
soTest.htm
<!DOCTYPE html>
<html>
<head>
<script language="JavaScript" type="text/javascript" src="http://code.jquery.com/jquery-1.6.min.js"></script>
<script>
function changeBG(obj)
{
alert('Color 1: Should Turn Red');
jQuery(obj).css('background-color','red');
alert('Color 2: Should Turn Green');
jQuery('#' + jQuery(obj).attr('id')).css('background-color','green');
}
jQuery(document).ready(
function() {
jQuery('.loadedContent').load('soTest2.htm');
jQuery('body').delegate("#theElem","click",
function(){
var obj = this;
jQuery('.loadedContent').load('soTest2.htm',
function(){
changeBG(obj);
}
);
});
}
);
</script>
</head>
<body>
<div class="loadedContent">
</div>
</body>
</html>
Ajax loaded content, soTest2.htm:
<div id="theElem" >
Hello
</div>
So why is it that this doesn't work:
jQuery(obj).css('background-color','red');
But this does:
jQuery('#' + jQuery(obj).attr('id')).css('background-color','red');
++++++++++ORIGINAL QUESTION:++++++++++
I have a table that I want to sort when specific table headings are clicked (those with the class "sort").
For instance:
Location
To do that I have this code:
jQuery('body').delegate("click", ".sort", function(event) {
event.preventDefault();
jQuery('.searchResults').html('<div align="center" style="margin-top:35px;"><img src="/common/images/ajax-loader_big.gif" /></div>');
var TimeStamp = new Date().getTime();
var sortItem = this;
jQuery('.searchResults').load('modules/configSearchResultsOutput.cfm?' + TimeStamp + '&sortby=' + jQuery(this).attr('sortby') + '&direction=' + jQuery(this).attr('direction'), {
data: jQuery('#results').val()
}, function() {
sortCallback(sortItem);
});
});
So on the click event for one of these sortable column headings I'm storing the entire 'this' scope in a var to pass through to this function.
To simplify the question I'll just say that we're trying to change the background color of the clicked element based on the custom attr 'direction' I'm using:
function sortCallback(obj) {
//Returns correct attribute value
alert('In Callback: ' + jQuery(obj).attr('direction'));
//Does not return correct attribute value -- almost like it's cached or something
alert('Long hand reference: ' + jQuery('.sort[sortby="' + jQuery(obj).attr('sortby') + '"]').attr('direction'));
//Must reference value via (obj) to get correct updated value
if (jQuery(obj).attr('direction') == 'asc') {
//Changing a value within the element via this longhand approach works
jQuery('.sort[sortby="' + jQuery(obj).attr('sortby') + '"]').css('background-color', 'red');
//Changing a value within the element via this shorter approach does not work
jQuery(obj).css('background-color', 'red');
}
else {
//Works
jQuery('.sort[sortby="' + jQuery(obj).attr('sortby') + '"]').css('background-color', 'green');
//Doesn't work
jQuery(obj).css('background-color', 'green');
}
}
I'm assuming I'm not understanding some aspect of javascript scoping (understanding 'this' has been very elusive to me).
Question summarized:
If I'm passing a var'd 'this' scope to a function why can't I change the aspects of the 'this' element, why must I drill down using the long way to change them?
A tricky question for me to articulate, hopefully I did a good enough job.
Thanks!
This is happening because your ajax call replaces the DOM element. obj refers to a DOM element that was in the DOM before you called .load, but was replaced. Another element with the same ID does exist, though! That's the one you're referring to with your 'longhand' method.
I think your problem is because that load call is asynchronous, causing jQuery to get confused. Put your code inside a callback for load and it should work:
jQuery(document).ready(function() {
jQuery('.loadedContent').load('soTest2.htm',
function(resp, status, xhr){
jQuery("#theElem").bind('click',
function(){
changeBG(this);
});
});
});

Categories