I work on a site that recently changed, I track certain clicks on the site through GTM and push it into the dataLayer for Google Analytics.
With the changes to the site I can't use jQuery any more so I'm having to change the following jQuery to Javascript, but I just can't get it to work. The script used to collect the h3 text within the div class 'grid_4' when the div was clicked on. The whole structure has changed now, but the old jQuery one looked like this;
<script>
var h3Tile = $("div[class*='grid_4'] a").find('h3').text();
$("div[class*='grid_4'] a").click(function() {
dataLayer.push({
'h3Value' : h3Tile,
'event' : 'tileClick'
});
});
</script>
The js I have so far is;
<script>
var outerElement = document.getElementsByClassName('ContentTeaser');
var childElems = outerElement.getElementsByTagName('h1').innerHTML;
var myFunction = function() {
dataLayer.push({
'h1Value' : childElems,
'event' : 'tileClick'
});
};
for(var i=0;i<childElems.length;i++)
childElems[i].addEventListener('click', myFunction(), false);
</script>
The only problem is that GTM refuses to accept this, saying;
'Uncaught TypeError: outerElement.getElementsByTagName is not a function'
Which I understand is related to the fact that I am creating an array rather than selecting an individual element, but I was hoping my for loop would handle this? or am I mistaken?
Thank you for any help anyone can offer.
Matt
getElementsByTagName is a method found on HTML Elements.
It and (more to the point) getElementsByClassName return an (array-like) HTML Collection, not a single HTML element.
You need to loop over outerElement and call getElementsByTagName on each element in turn instead of trying to call it on the collection itself.
Which I understand is related to the fact that I am creating an array rather than selecting an individual element, but I was hoping my for loop would handle this?
You have two collections. You are looping over the second one, but are trying to treat the first one as a single element.
It would probably be easier to simply use query selector instead:
var childElems = document.querySelectorAll(".ContentTeaser h1");
You then have a couple more problems:
for(var i=0;i<childElems.length;i++)
Since childElems is the value of innerHTML, it is undefined (if you'd called it on an element instead of an html collection then it would be a string instead) so that will throw an error.
Don't use innerHTML (which I already fixed in the query selector example).
childElems[i].addEventListener('click', myFunction(), false);
You are calling myFunction immediately and trying to assign its return value (undefined) as an event handler. Remove the ().
Related
I'm using a pretty cool JavaScript/jQuery library called OpenSeaDragon. It's for displaying deep zoom images. It also have a method for adding 'overlays', essentially creating a div and putting it over the image with coordinates though a viewer object. There's also a method for removing the overlays: https://openseadragon.github.io/docs/OpenSeadragon.Viewer.html#removeOverlay
viewer.removeOverlay(element or element id);
As the doc states regarding the input param: "A reference to the element or an element id which represent the ovelay content to be removed." I'm creating a whole bunch of overlays -- creating a grid out of rectangles -- so I've given them a class. Passing the class to this method doesn't work. So I'm trying to understand what they mean by "element". Is there a way I can use JQuery or JavaScript to select an "element" and pass it to the method? Or some such thing?
thanks
It usually means an element in your document, i.e. a DOM node. So, a div, or a span, or somesuch.
You can select an element with jQuery pretty easily:
var $obj = $('#elementId');
and then grab the underlying DOM node from the jQuery object that results:
var elm = $obj[0];
Thanks everyone. Here's how to do it:
var n = $(".gridcell").length
for(i=0; i<n; i++) {
viewer.removeOverlay($(".gridcell")[0]);
}
At first I though I could iterate through the array, calling removeOverlay() on each item index successively. This was causing half the overlays to be deleted on each run. So, for 16 overlay, I have to run it 4 times. After a few minutes it clicked... Each time you get the elements $(".gridcell"), it returns a new array.
I would like to know if it's possible to access an object property from an appended element. For example:
function anyFct(){
this.div=$('<div ref="dv">').html('Hi').appendTo('body');
div.animal='dog';
div.yld=function(){
alert(div.animal);
};
$('input type="text" value="anyIn" onclick="yeldAnimal(this);"').appendTo(div);
}
function yeldAnimal(obj){
var actElement=$(obj).closest('div[ref=dv]');
actElement.yld(); // I want that this yields 'dog'
}
and my HTML:
<input type="button" value="test" onclick="anyFct();">
So this is the logic: I create a div element when the button is clicked on. This div element has a text that when clicked on calls an external function that calls a method on its parent element (the div).
For many contextual reasons this must be the logic. I've already found a solution that is saving the object div in a global array and then search in all values of the array for the object that triggered the method. However, I would like to know if there is a 'cleaner' or correct way to do this.
It's possible, and there are a couple of ways you could achieve it. The important thing you need to understand is the distinction between jQuery objects and actual DOM elements. When you use jQuery to create a <div> element, you create both; but what you end up with a reference to is the jQuery object - or, if you're chaining jQuery function calls, the result of the last function called. The DOM element, assuming you actually append it to the DOM, persists once that section of code has finished execution, but the jQuery object that's created will vanish when that variable goes out of scope.
When you execute some jQuery code later on to get a reference to your DOM element, it's referring to the same element on your page but it's a different jQuery object, so any custom properties you added to the original one won't be available. How do you get around that? Set the properties on the actual DOM element.
You can use the .get() method to access the underlying DOM element from a jQuery object, indexed from 0 (so .get(0) called on a jQuery object will return the first DOM element it references). With that you can then set your custom properties and later retrieve them, something like this:
function anyFct(){
this.div=$('<div ref="dv">').html('Hi').appendTo('body');
var elem = div.get(0); // the actual DOM element, the div
elem.animal='dog';
elem.yld=function(){
alert(elem.animal);
};
$('<input type="text" value="anyIn" onclick="yeldAnimal(this);"/>').appendTo(div);
}
function yeldAnimal(obj){
var actElement=$(obj).closest('div[ref=dv]').get(0); // also the div
actElement.yld(); // alerts 'dog'
}
jsFiddle demo
Note that I've made a few changes to your code in addition to adding in the usage of .get(), most notably correcting the syntax for creating the <input type="text"> element in the first function.
Okay, most of this is not syntactically correct javascript and seems to be overly complicated. I believe if I understand what you're trying to achieve you want the following:
function anyFct(){
var div=$('<div ref="dv">').html('Hi');
div.animal='dog';
div.yld=function(){
alert(this.animal);
};
var element = $('<input type="text" value="anyIn">');
$(element).click(function() {
div.yld();
});
$(div).append(element);
$('body').append(div);
}
I am attempting to fire off an AJAX call based on the onclick event for a google map integration. The info_window_content function seen here: http://jsfiddle.net/6xw2y/ is the call to create the divs that reside within the map itself.
The "v" variable does in fact contain a store_id. So in the opening line of that function, it has the following:
var info_window_string = "<div class='maps_popup' id="+v.id+">";
Now I have an onclick event that I have duplicated and modified. The first onclick event works just fine and refreshes the panel as it should. The second onclick event doesn't work and the code for that is below:
$("#div").click(function(){
var store_id = $(this).find("div").attr("id");
var pathname = "ajax=1&store_id="+store_id+"&action=get_nearby_stores&distance="+distance+"&lat="+lat+"&lng="+lng+"&products="+$('#edit-products').val();
$("#pocp_content").load("file1.php?" + pathname);
});
That doesn't seem to work. I've also tried changing the div tag to be like this:
$("div").click(function(){
Which still doesn't work. As an added side hint. At one point I was able to get it to refresh but it was passing map-container as the store_id, instead of the id itself.
What am I missing here?
I agree with Joke_Sense10,
but I think you're probably not binding the event to the right DOM element.
Try to open up the developer console in your browser (while being on the side you develop this code for), and enter $("#div") to see if the element it returns is the one you expect. You can also use console.log($("#div")) in the code for that.
answer in comments
For a larger number of elements, always use .on() method as the latter will bind an single event listener on one of the topmost nodes in the DOM tree.
$(document).on("click","#"+v.id, function(){
I am trying to append some links with data and a click handler to a containing div.
jQuery 1.4.3
Fails in FireFox 5.0/Chrome 13.0.782, but works in IE9
I first create the element as a jQuery object, then add the data and click handler. Then I use .append() to append it to the container:
var $selector = $('Test');
$selector.data('testdata', "Test");
$selector.click(function(event) {
alert('Clicked: ' + $(this).data('testdata'));
return false;
});
$('#container').append($selector);
I see the link added, but when I click on it, the click handler does not fire.
I thought that maybe I needed to do the append first and then add data+click, but that doesn't work either:
var $selector = $('Test');
$('#container').append($selector);
$selector.data('testdata', "Test");
$selector.click(function(event) {
alert('Clicked: ' + $(this).data('testdata'));
return false;
});
Does append not preserve data and handlers? It seems that when I .append($selector), $selector and the newly added DOM object are not one in the same.
Which browser are you using? Also, which version of JQuery? This works for me in firefox, ie, and chrome on JQuery version 1.6. Here's the test fiddle I was using.
I don't think the append is the cause of your problem. It's because the html you're passing into $() to create your elements is not a simple tag.
According to the documentation of jQuery(html):
If the HTML is more complex than a single tag without attributes, as it is in the above example, the actual creation of the elements is handled by the browser's innerHTML mechanism. In most cases, jQuery creates a new element and sets the innerHTML property of the element to the HTML snippet that was passed in. When the parameter has a single tag, such as $('<img />') or $('<a></a>'), jQuery creates the element using the native JavaScript createElement() function.
This quote is from this page: http://api.jquery.com/jQuery/#jQuery2
This means that you may get a different element than what you intend because it's dependent on the browser's innerHTML property. You may find it easier if you pass in a simple tag '<a></a>' and add other attributes to it as a second argument map to $(html, props).
To get this to work with a simple tag in the $(html, props) call, you would do something like this:
var $selector = $('<a></a>',
{
"class" : "x",
"href" : "#",
text : "Test",
click: function() {
alert('Clicked: ' + $(this).data('testdata'));
return false;
}
});
$('#container').append($selector);
$selector.data('testdata', "Test data");
For my page, the problem exists using jQuery 1.4.3 and 1.4.4. But if I upgrade to 1.6.1, the problem goes away and the code works as expected. At this particular point, I am worried about upgrading to 1.6.1.
My other option is to append the element, then requery for it using jquery before adding data and handlers. That code does work, but obviously not ideal.
I ran into the same issue, try using .appendTo() instead of .append().
It worked for me.
So, say I have selected, in JQuery, a singular DOM div.
I then proceed to create a new DIV like so:
var DIV = $("<div>Hello, world</div>");
After that, I attempt to place that DIV inside the original one like so:
$(OriginalDiv).append(DIV);
Okay, that works.
Now I want to edit DIV further.
Calls to .click, .html, .addClass, (And likely more) do not work!
Okay, instead I do:
var OriginalDiv = $("someSelector");
var DIV = $("<div>Hello, world</div>");
DIV = $(OriginalDiv).append(DIV);
That appears to work at first; However, instead, it sets DIV to reference the same DOM object as OriginalDiv and NOT the newly appended DOM object. Naturally, this does not allow me to edit DIV.
So, then, I try two more methods:
var OriginalDiv = $("someSelector");
var DIV = $("<div>Hello, world</div>");
$(DIV).appendTo(OriginalDiv);
and
var OriginalDiv = $("someSelector");
var DIV = $("<div>Hello, world</div>");
DIV = $(DIV).appendTo(OriginalDiv);
Not even these work.
If I haven't done a very good job explaining, here is my exact dilemma
I am trying to create a DOM object in jquery, then append it to another DOM object using jquery. The problem is, once it gets appended, there seems to be no way for me to directly access it without using somethign like .children.
I'd like very much to be directly returned somewhere along in that process a reference to the DOM object which I am appending. As in the one that actually gets appended.
I'm not sure how to do this in JQuery. Anybody know a solution?
Thanks
--G
Yes, append won't work as it returns a reference to the element the new element was appended to. jQuery supports method chaining, so this should work easily:
$("<div>Hello, world</div>")
.click(function() {
// something
})
.appendTo('someSelector');
But even
var $ele = $("<div>Hello, world</div>").appendTo('someSelector');
will work. appendTo returns a reference to the element which was appended. If this does not work for you, you have your problem elsewhere.
Comments on your code: This is not your problem, however it is important for you to know what is going on here.
This part
var OriginalDiv = $("someSelector");
var DIV = $("<div>Hello, world</div>");
$(DIV).appendTo(OriginalDiv);
is the same as
$($("<div>Hello, world</div>")).appendTo($("someSelector"));
You see, you have a nested call to jQuery, because DIV is already a jQuery object. There is no need to pass it again to jQuery.
You can also pass a selector directly to appendTo.
you could try this;
var DIV = document.createElement('div');
then you can use;
$(div).html('Test!');
or what ever you want to use with.
You don't have to get anything back from the DOM. Once you create the element with jQuery, you already have a reference to the DOM element. Inserting it into the document does not do anything special.
// this will create the DOM element, and the jQuery
// object wrapping that newly created DOM object
// is assigned to DIV.
var DIV = $("<div>Hello, world</div>");
// Don't worry about getting a return value from this
// append() call. What we need is already available inside
// the variable DIV.
$(OriginalDiv).append(DIV);
// continue using DIV as you normally would. It is referring
// to the same DOM object that was just appended to the document.
DIV.addClass('green');