Difference between .getAttribute and dataset in JS - javascript

I have been using .getAttribute and today found out about .dataset, so i was wondering what the differences are and when should each be used.
So here is an example. Let's say we have a paragraph:
<p class="test" data-something="this is a test">some text</p>
if we use .getAttribute
let testText = document.querySelector('.test');
let testGetAttribute = testText.getAttribute('data-something');
console.log(testGetAttribute);
we get as output "this is a test".
if we use .dataset
let testText = document.querySelector('.test');
let testDataset = testText.dataset.something;
console.log(testDataset);
we also get "this is a test".
So, is there a difference between this two approaches? Are there some benefits in using one over the other?
Thank you!

I'm only replying this because I faced a difference between the two methods that actually affected the functioning of my application.
I did getAttribute('data-id') and dataset.id to collect a todo item id.
For getAttribute, if I ran through the debugger line by line, it worked fine. If I didn't, all sorts of wonky things would happen. For dataset.id it worked fine either way.
If you're curious about it, you can check lines 201 and 202 in my code:
https://glitch.com/~wnc-reading-exercise-3 Comment out line 201 and uncomment line 201.
When running the app, try toggling complete on a todo item and see what happens to the DOM. If you go around toggling a few at a go you'll see some strange values show up.

Related

Xpath: How to combine these two child node to get parent node?

I am new to XPath and confused. Anyone can have a quick glance and see what is wrong in my syntax?
I'm trying to select all direct child div's of id="list-overview" which has two child nodes somewhere down their tree containing data-price<=20 and a div containing "Orange" text
let xy = $x(`//*[#id="list-overview"]/div[./div/a/div/div/div[#data-price<=20]][./div/a/div/div[#class='fruit'][contains(.,'Orange')]])`)
to break it up. I have tested these two separately and they worked.
`//*[#id="list-overview"]/div[./div/a/div/div/div[#data-price<=20]]`
`//*[#id="list-overview"]/div[./div/a/div/div[#class='fruit'][contains(.,'Orange')])]`
I just can't seem to combine them somehow and not sure what I'm doing wrong?
EDIT:
Tried the suggestions and the following xpath doesn't throw an exception anymore. But it returns empty Array while there are elements matching price < 20 and fruit="Orange"
$x(`//*[#id="list-overview"]/div[./div/a/div/div/div[#data-price<=20] and ./div/div/a/div/div[#class='fruit'][contains(.,'Orange')]]`)
If I understand your idea, you are missing the logical and between these 2 conditions. I corrected the XPath expression accordingly. Please try this:
let xy = $x(`//*[#id="list-overview"]/div[./div/a/div/div/div[#data-price<=20] and ./div/a/div/div[#class='fruit'][contains(.,'Orange')]])`)
UPD
Please try this:
let xy = $x(`//*[#id="list-overview"]/div[.//div[#data-price<=20] and .//div[#class='fruit'][contains(.,'Orange')]])`)
Instead of this
$x(//*[#id="list-overview"]/div[./div/a/div/div/div[#data-price<=20]][./div/a/div/div[#class='fruit'][contains(.,'Orange')]]))
You could do this to combine both of them,
to tightly couple both the child
$x(//*[#id="list-overview"]/div[./descendant::div[#data-price<=20]] and [./div/a/div/div[#class='fruit'][contains(.,'Orange')]])
or to either have one of them and still you would want to proceed further.
$x(//*[#id="list-overview"]/div[./descendant::div[#data-price<=20]] or [./div/a/div/div[#class='fruit'][contains(.,'Orange')]])
Also, I have included descendant to make it more readable.

How can I perform a double click on an element with Protractor?

I would like to double click on an element but I could not find a way to do this in the document API. I found some references dating back to 2013 but I know things have changed a lot.
Can someone help and tell me how I can perform a double click.
Thanks
Always remember that protractor is a wrapper around webdriverjs.
doubleClick() is available in browser.actions():
browser.actions().doubleClick(element(by.id('mybutton'))).perform();
For anyone looking at this in 2019, this still works. Just know thatProtractor selectors use the Locator object to find elements. The above solution uses the webElement object. So if you're using Protractor to find your element, you'll need to do something like browser.actions().doubleClick(myElement.getWebElement()).perform();
var el=element(by.id('id'));
browser.executeAsyncScript(function() {
var evt=new MouseEvent('dblclick', {bubbles: true,cancelable: true,view: window});
var callback = arguments[arguments.length - 1];
arguments[0].addEventListener('dblclick',callback);
arguments[0].dispatchEvent(evt);
},el).then(function(){...});
await browser.actions().mouseMove(Element).doubleClick().perform();
await browser.actions().doubleClick(Element.getWebElement()).perform();
the above 2 codes works properly to double click on any element when it's visible on screen.
Here Element is
"let Element = element(by.xpath("locator"));"
Below code did not works as a msg is shown saying
"Failed: JavaScript error: arguments[0].dblclick is not a function"
whereas when checked in console similar scripts did worked to double click the item: "$($x(element(by.xpath("locator")))).dblclick()".
Will update my comment if able to find the exact JavaScript syntax to make below code run.
await browser.executeScript("arguments[0].dblclick();",
Element.getWebElement());

How do I configure jshint to not give me the error "Bad line breaking before"?

It's giving me the error "Bad line breaking before ','" because I have code like the following
var one = 1
, two = 2
, three = 3
;
If I put the , at the end of the line instead of the beginning of the next, it doesn't complain. But I want to code this way. Is there a way I can make it not show this warning?
I looked though JSHint's options but there isn't anything pertaining to this error.
As mentioned in the comments of the laxbreak answer, laxcomma option should actually be used for this particular situation (it has been implemented in the meantime). See http://jshint.com/docs/options/ for details.
laxbreak = true is the option to set.
You can find the option on the main page of JSHint site as "About unsafe line breaks".

removeChild in javascript/ DOM is not working correctly when more than one is present in the function

UPDATE:
Here's the JsFiddle link:
http://jsfiddle.net/zAVFv/
It seems to be not working in JsFiddle, but guess it serves to show the whole code - html, css and Js.
I am facing a very weird situation in DOM editing using Javascript. My sample code is below. Basically, the swapCells would take in two objects, which have 2 children each - one is an img element, and the other is a textNode. What I want to see is the how removeChild works.
I have marked the 2 lines where all the confusion comes from.
issue#1 is on the line where sourceTD has its child removed, issue#2 is when the lastChild is removed from the destinationTD.
Let me explain how the code below is running:
a) when only issue line#1 is present in the code, the sourceTD child gets removed, the output says source has 1 child of img type; destination has 2 children - img and text ---- works as expected
b) when only issue line #2 is present in the code, the destinationTD child gets removed, again works similar to above, AS EXPECTED
c) NOW THE PROBLEM - when both lines are present in the code, it only removes the sourceTD lastChild. output is received only for the sourceTD part of alerts. The destinationTD alerts are not coming, so I am unable to evaluate whether the destination child got removed
CODE:
function swapCells(sourceTD, destinationTD){
//line below is issue line#1
sourceTD.removeChild(sourceTD.lastChild);
//line below is issue line#2
destinationTD.removeChild(destinationTD.lastChild);
if(sourceTD.hasChildNodes()){
alert("Source has: " + sourceTD.childNodes.length);
alert(sourceTD.childNodes[0].alt);
alert(sourceTD.childNodes[1].nodeName);
}
destinationTD.removeChild(destinationTD.lastChild);
if(destinationTD.hasChildNodes()){
alert("Destination has: " + destinationTD.childNodes.length);
alert(destinationTD.childNodes[0].alt);
alert(destinationTD.childNodes[1].nodeName);
}
}
Please let me know why the code is behaving abnormally when both the issue lines are present. Also, is there something like a function can remove only a single node, or that only a single removeChild will work...????? I am confused.
Thanks!
Sorted -> http://jsfiddle.net/zAVFv/3/
The first childNode of TD is a newline not the img element .... incremented the numbers by 1 and its working fine ... seems a little flimsy to use in a prod environment - unless you can control the HTML - perhaps look at using getelementbytagname('img') instead ?
When you have both lines in there, you end up calling destinationTD.removeChild(destinationTD.lastChild); twice, so both children get removed. Your if statement then evaluates to false because destinationTD has no child nodes, so you don't get anything output - in this case, lack of output is proof that the code IS working, rather than proof that it ISN'T.
Ahhh... figured it out.
the issue was because of an error created due to referencing a childnode that was no more present, after deletion.
For example, if the sourceTD has 3 children, and were referenced as childNodes[1], and childNodes[2], then upon deletion of the lastChild of the sourceTD, there is no longer childNodes[2], as there are only 2 left and no third node anymore. As a result of this error in JS, the remaining code is somehow suppressed and not run. so this is the reason why the destinationTD alerts also are getting suppressed.
Stupid referencing..!
Thanks everyone, especially #ManseUK for all the help

Problem with regexp in userscript for chrome

This might be a noob question, but I have tried to find an answere here and on other sites and I have still not find the answere. At least not so that I understand enough to fix the problem.
This is used in a userscript for chrome.
I'm trying to select a date from a string. The string is the innerHTML from a tag that I have managed to select. The html structure, and also the string, is something like this: (the div is the selected tag so everything within is the content of the string)
<div id="the_selected_tag">
link
" 2011-02-18 23:02"
thing
</div>
If you have a solution that helps me select the date without this fuzz, it would also be great.
The javascript:
var pattern = /\"\s[\d\s:-]*\"/i;
var tag = document.querySelector('div.the_selected_tag');
var date_str = tag.innerHTML.match(pattern)[0]
When I use this script as ordinary javascript on a html document to test it, it works perfectly, but when I install it as a userscript in chrome, it doesn't find the pattern.
I can't figure out how to get around this problem.
Dump innerHTML into console. If it looks fine then start building regexp from more generic (/\d+/) to more specific ones and output everything into a console. There is a bunch of different quote characters in different encodings, many different types of dashes.
[\d\s:-]* is not a very good choice because it would match " 1", " ". I would rather write something as specific as possible:
/" \d{4}-\d{2}-\d{2} \d{2}:\d{2}"/
(Also document.querySelector('div.the_selected_tag') would return null on your sample but you probably wanted to write class instead of id)
It's much more likely that tag.innerHTML doesn't contain what you think it contains.

Categories