1

I've been having a hard time with cross browser compatibility and scrapping the dom. I've added data analytics tracking to ecommerce transactions in order to grab the product and transaction amount for each purchase.

Initially I was using document.querySelectorAll('#someId')[0].textContent to get the product name and that was working fine for every browser except internet explorer.

It took some time to figure out that it was the .textContent part that was causing ie problems.

Yesterday I changed .textContent to .innerText. From looking inside analytics it seems that the issue has been resolved for ie but now Firefox is failing.

I was hoping to find a solution without writing an if statement to check for the functionality of .textContent or .innerText.

Is there a cross browser solution .getTheText?

If not what would be the best way around this? Is there a simple solution? (I ask given my knowledge and experience with scripting, which is limited)

** added following comments ** If this is my code block:

// build products object
var prods = [];
var brand = document.querySelectorAll('.txtStayRoomLocation');
var name = document.querySelectorAll('.txtStayRoomDescription');
var price = document.querySelectorAll('.txtStayRoomSplashPriceAmount');

for(var i = 0; i < brand.length; i++) {

//set granular vars
var prd = {};

//add to prd object
prd.brand = brand[i].innerText;
prd.name = name[i].innerText;
prd.price = price[i].innerText;
prd.quantity = window.session_context_vars.BookingContext.Booking.ReservationLineItems[i].ReservationCharges.length/2;;

//add to prods array
prods.push(prd);
}

Then if I understand the syntax from the comments and the question linked to in the comment, is this what I should do:

// build products object
var prods = [];
var brand = document.querySelectorAll('.txtStayRoomLocation');
var name = document.querySelectorAll('.txtStayRoomDescription');
var price = document.querySelectorAll('.txtStayRoomSplashPriceAmount');

for(var i = 0; i < brand.length; i++) {

//set granular vars
var prd = {};

//add to prd object
prd.brand = brand[i].textContent || brand[i].innerText;
prd.name = name[i].textContent || name[i].innerText;
prd.price = price[i].textContent || price[i].innerText;
prd.quantity = window.session_context_vars.BookingContext.Booking.ReservationLineItems[i].ReservationCharges.length/2;;

//add to prods array
prods.push(prd);
}

So using or with a double bar || assigns the first non null value?

Doug Fir
  • 19,971
  • 47
  • 169
  • 299
  • 3
    I usually just write `element.textContent || element.innerText`. – Josh Crozier Apr 25 '15 at 20:58
  • 1
    Is there a reason you're not just using a DOM wrapper library like jQuery? – Korvin Szanto Apr 25 '15 at 21:00
  • Closely related: [Cross-browser innerText for setting values](http://stackoverflow.com/q/11646398/1048572) – Bergi Apr 25 '15 at 21:02
  • @JoshCrozier thanks for the tip I'm going to add a few lines to my question based on your feedback. at Korvin yes there is - it's because I'm a novice and don't now what that is – Doug Fir Apr 25 '15 at 21:02
  • @Doug Firr elem.textContent || elem.innerText is the right way to go and this is the way jQuery implement their lib text functions, and yes to your last question, you may just put ( ) around your elem.textContent || elem.innerText to be (elem.textContent || elem.innerText) – Amr Elgarhy Apr 25 '15 at 21:14
  • [ ] - square brackets for object property - instead of (). – Sidd Apr 25 '15 at 21:16

1 Answers1

1

Re: your edit, not quite. The way to access methods or properties on an object (eg a DOM element) is to use dot notation if you have the name itself, or square brackets in case of variables/expressions (also works with strings, as in obj["propName"], which is equivalent to obj.propName). You can also just test the property against one element and use that from there on:

// build products object
var prods = [];
var brand = document.querySelectorAll('.txtStayRoomLocation');
var name = document.querySelectorAll('.txtStayRoomDescription');
var price = document.querySelectorAll('.txtStayRoomSplashPriceAmount');

for(var i = 0; i < brand.length; i++) {

//set granular vars
var prd = {};

//add to prd object
var txtProp = ("innerText" in brand[i]) ? "innerText" : "textContent"; //added string quotes as per comments
prd.brand = brand[i][txtProp];
prd.name = name[i][txtProp];
prd.price = price[i][txtProp];
prd.quantity = window.session_context_vars.BookingContext.Booking.ReservationLineItems[i].ReservationCharges.length/2;;

//add to prods array
prods.push(prd);
}

Regarding the line:

var txtProp = (innerText in brand[i]) ? innerText : textContent;

The in keyword checks an object to access the property (syntax: var property in object). As for the question notation (I made an error earlier, using ||, the correct thing to use was a :),

var myVar = (prop in object) ? object[prop] : false;

As an expression, it basically evaluates the stuff before the ?, and if it's true, returns the expression before the :, else the one after. So the above is the same as / a shorthand for:

if(prop in object){
     var myVar = object[prop];
}
else{
    var myVar = false;
}

Since you are checking between two properties only and wanting to assign one or the other, the shortest way would indeed be:

var txtProp = brand[i].innerText || brand[i].textContent;

It would basically test the first property, and if it were false or undefined, it would use the second one. The only reason I (pedantically) avoid using this is because the first test of a || b would fail even if a existed but just had a value of 0, or an empty string (""), or was set to null.

Sidd
  • 1,389
  • 7
  • 17
  • Hi Sidd thanks for taking the time to answer. There's some syntax that is new to me in there "var txtProp = (innerText in brand[i]) ? innerText || textContent;". What exactly is that doing? What's the question mark in there? – Doug Fir Apr 25 '15 at 21:21
  • 1
    Cool, glad it helped. Just wanted to add that since you are clearly using a loop here, txtProp will be evaluated (needlessly) each time the loop runs. You can move it outside the loop, but be sure to test it against an element that exists in the DOM (otherwise the script will throw an error). – Sidd Apr 25 '15 at 21:36
  • Awesome, thanks for spotting that, will edit my post. (Very duh of me, obviously anything without string quotes would need to be a defined variable!) – Sidd Apr 25 '15 at 22:08