e.target is working only on links - javascript

I am a noob, I was developing a chrome plugin , which gives the info about the elements clicked on in the web page,
It works fine , but the problem is the e.target works only on links and input boxes, but when I click on some text it does not do anything , it is blank[Expected: the id/class/etc of the div within which the text is present]
Here is my code (please do not mark me down, as am really new to this):
document.addEventListener("click", function (e) {
var dom_id = e.target.getAttribute("id");
var dom_name = e.target.name.toString();
var dom_class = e.target.className.toString();
var dom_html = e.target.innerHTML;
var dom_href = e.target.getAttribute("href");
var dom_text = e.target.text;
var dom_el = e.target.tagName;
var dom_src = e.target.src;
}, false);
All I want is when I click on a div, I should get the div info, span should give span info, likewise etc.

The problem
Since (based on another question of yours) it seems the listener is registered properly (e.g. after the DOM has been loaded, the only problem I see, is that you are calling e.target.name.toString();.
The explanation
It will only work with elements that have the name attribute set (not only for links or inputs, but any element that has a name attribute). For elements with no name, an exception will be raised, as you are calling method toString of undefined (e.target.name equals undefined when the name attribute is missing).
(Note that this is not the case with className, because className refers to the elements property (not directly the class attibute and it defaults to an empty string when the class attribute is missing.)
The solution
Just remove the .toString() part and it will work:
var dom_name = e.target.name;
Based on how you use that var later on, you might want to add a check and set it to an empty string if it not defined:
var dom_name = (e.target.name !== undefined) ? e.target.name : '';

Related

Add Event Listener not Connecting to Button

I am trying to click a button, that will then change the display of overlay on my page to none. In the console it is telling me that, startButton.addEventListener is not a function. Can someone help me find the bug?
const letters = document.getElementById('qwerty');
const keyWords = document.getElementById('phrase');
const startButton = document.getElementsByClassName('btn__reset');
const overlay = document.getElementsByClassName('main-container');
var missed = 0;
startButton.addEventListener("click", function(){
overlay.style.display = 'none';
});
getElementsByClassName does not return a single element - it returns an arraylike HTMLCollection of all matching elements. You are not able to attach an event listener to a non-element.
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
If you would like to just get the first element matching a class, you can use
const startButton = document.querySelector('.btn__reset'); (the dot signifies the selector is a class name)
Or access the first item of the return value of getElementsByClassName like so:
const startButton = document.getElementsByClassName.item(0); (You likely want to check for its existence first before)
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
As it currently stands your 'startButton' constant is actually returning a collection from this:
document.getElementsByClassName('btn__reset');
Even if it's a collection of only one object you need to go an additional level deeper to get the correct one
I suggest using
.getElementById('buttonID');
instead. This will will only return a single element to attach your listener to.
Get your button with getElementById, it works
let startButton = document.getElementById('button');
startButton.addEventListener("click", function(){
console.log('yes');
});
<button id="button">Go!</button>

changing the value of a select box by only having the xpath

I am currently using robotium to record a load of actions in an android web view. There is a known bug in robotium that doesnt let you change the value of a select box. in order to combat this when the test is running i am creating another javascript injection to change it. It works with name and Id but it needs to be able to use xpath as well in case a name or id arent available.
At the moment I can do this using the name and Id of the select box using:
selectBox = document.getElementById(identifyingValue);
or
selectBox = document.getElementByName(identifyingValue);
After this I can create a method to change the value of the select box the value that I want. The issue is that sometimes i cannot get the id or name of the select box and there isn't a similar method to do this via an Xpath ie:
selectBox = document.getElementByXpath(identifyingValue);
My code currently looks like this:
var selectBox;
var identifyingAttribute = ('$identifyingAttribute');
var identifyingValue = ('$identifyingValue');
var selectedIndex = '$selectedIndex';
if (identifyingAttribute === 'id') {
selectBox = document.getElementById(identifyingValue);
} else if (identifyingAttribute === 'name') {
selectBox = document.getElementByName(identifyingValue);
} else if (identifyingAttribute === 'xpath') {
selectBox = document.getElementByXpath(identifyingValue);
}
selectBox.selectedIndex = selectedIndex;
if (selectBox.onchange) {
selectBox.onchange();
}
So far you can see that I am trying to use the id and name first and the xpath as a last resort.
Is they a away that I can select an element by its Xpath and then change its value or perform a similar action. Any help or input would be greatly appreciated.
you can use document.querySelector() and select the property with a css selector.
documentation can be found here: https://developer.mozilla.org/en-US/docs/Web/API/document.querySelector
I have found a solution to the problem using document.evaluate()
The statement works for me:
selectBox = document.evaluate(identifyingValue, document, null , 9, null).singleNodeValue;

contenteditable not working on dynamically generated elements

I am dynamically creating an unordered list and adding items to it on a click of a button. I append this to a section that has contenteditable attribute set true. However, I do not see it working. I did set the contenteditable attribute to true even for the list but I guess it is supposed to inherit that from the section it is appended to. Here is the code of what I am doing.
// create text input
var categoryInput = document.createElement('input')
// create button to add the text entered to a list
var btnAddToList = document.createElement('input');
btnAddToList.type ="button";
//create a section to add a list to
var section = document.createElement('section');
var ul=document.createElement('ul');
section.appendChild(ul);
section.contenteditable = "true";
ul.contenteditable = "true";
//create an event handler to add to the list
if (btnAddToList.addEventListener) { btnAddToList.addEventListener('click', function () { addToList(ul, categoryInput.value);});
} else if (btnAddToList.attachEvent) {
btnAddToList.addEvent('click', function () { addToList(ul, categoryInput.value);});
Here is the function I call
function addToList(unorderedlist, inputText) {
if(inputText.length == 0) {
alert("Add Text");
return;
}
var listitem = document.createElement('li');
var listvalue = document.createTextNode(inputText);
listitem.appendChild(listvalue);
unorderedlist.appendChild(listitem);
}
What am I doing wrong or not doing? Any help appreciated. Thanks
The property is contentEditable (note upper-case 'E'), not contenteditable.
section.contentEditable = "true";
You need to set the attribute, not the property:
section.setAttribute('contenteditable', 'true');
Instead of
section.contenteditable = "true";
Some more info here and here (in the context of jQuery, but covers the topic splendidly nonetheless).
My current understanding of the difference is that attributes are the things you can set through markup (id, class, contenteditable, etc.), whereas properties are the properties of the actual javascript objects representing the DOM nodes. As the linked article mentions, the two are often kept in sync by the browser, but not always.
Edit:
As Tim Down states in his answer, while the above works (setting the attribute), the actual problem is that the name of the property is cased wrong. It should be
section.contentEditable = "true"; //Note the upper case 'E'
The reason setting the attribute works, is that attributes are case-insensitive.

How to know if an element, created dynamically, exist?

I have this simple function:
var x = document.createTextNode("ERROR");
document.body.appendChild(x);
So then I need to create an IF to verify if this message exist [If this message has been created]. This is the problem, I don't know how to do that.
GetElementByID seems to don't work with element created by dynamically.
Any help? Thanks.
You can use document.contains to check if a element is in the DOM
Just a quick example of how it works
document.contains($('<div>')[0]); // FALSE
And
document.contains($('<div>').appendTo('body')[0]); // TRUE
jQuery only used for a shorthand to element creation
This also works for text nodes and you can use contains on any node.
document.body.contains(Node); // Example
The browser support is somewhat very good
Documentation: https://developer.mozilla.org/en-US/docs/Web/API/Node.contains
Question specifics:
var x = document.createTextNode("ERROR");
document.body.appendChild(x);
document.contains(x); // Should be TRUE
You are creating a text node, not an element. You need to create an element and give it an id to be able to use getElementById.
I don't know of any reasonable way to search for a text node, although you could always check the text nodes of the element you attached it to and see if it's there.
var message = "ERROR";
var t = document.createTextNode(message);
var node = document.getElementById('content').appendChild(t);
if (document.getElementById('content').innerHTML !== message) {
console.log('element not added');
} else {
console.log('element added');
}
Here is a fiddle:
http://jsfiddle.net/btipling/rBg4w/
I believe this would work:
var x = document.createTextNode("ERROR");
var element = document.body.appendChild(x); //returns text node
if(!element){
//element was not added
}
although if I were you I might create a span element with an id or a class called error. This way you can apply any css styles to it.
Try this:
var x = document.createTextNode("ERROR");
document.body.appendChild(x);
if (document.body.innerText.indexOf('ERROR')>=0){
alert('"ERROR" found');
}
indexOf doesn't work in all browsers.
As #slowpython said I'd rather create a DOM element with ID or NAME.

Javascript reference element created from appendchild?

I am creating tables with the appendchild method. They contain checkboxes. I would like to be able to have the user to click a checkbox and have it run a function. I need the function to access the other checkbox and see if its checked or not. Currently I can' seem to reference the table or checkboxes at all.
My code for creating the table is:
function makeTable() {
var ItemA = Item.ItemName.options[Item.ItemName.options.selectedIndex].text;
var myParagraph=document.getElementById("myLine");
myForm = document.createElement("FORM");
mytable = document.createElement("TABLE");
mytablebody = document.createElement("TBODY");
var CB_Format = document.createElement('input');
CB_Format.type = 'checkbox';
CB_Format.name= "CB_Test";
CB_Format.value= 1;
CB_Format.setAttribute("name", "CBTest2");
CB_Format.onclick = changeColor;
theCell.appendChild(CB_Format);
var CB_Delete = document.createElement('input');
CB_Delete.type = "checkbox";
CB_Delete.name = "CB_Test";
CB_Delete.setAttribute("name", "CBTest2");
CB_Delete.value = 2;
CB_Delete.onclick = answer;
theCell.appendChild(CB_Delete);
My understanding is that my solution should be as simple as alert(document.form.checkbox.checked) but no matter what combination of possible names I try I get the error that it is null or not an object in both ie8 and firefox.
Thank you for your help
> function makeTable() {
> var ItemA = Item.ItemName.options[Item.ItemName.options.selectedIndex].text;
> var myParagraph=document.getElementById("myLine");
> myForm = document.createElement("FORM");
> mytable = document.createElement("TABLE");
> mytablebody = document.createElement("TBODY");
If you don't declare variables with var, they become global variables when first evaluated. Always declare variables.
> var CB_Format = document.createElement('input');
> CB_Format.type = 'checkbox';
> CB_Format.name= "CB_Test";
> CB_Format.value= 1;
> CB_Format.setAttribute("name", "CBTest2");
The above line changes the name property from the value assigned a couple of lines earlier, why do both? Just assign the correct value to the name property once:
CB_Format.name = "CBTest2";
The same goes for the use of setAttribute later. Note that setting the value of a property doesn't always change the associated attribute in some browsers, so always use properties unless there is a specific reason to use setAttribute,
[...]
My understanding is that my solution should be as simple as
alert(document.form.checkbox.checked) but no matter what combination
of possible names I try I get the error that it is null or not an
object in both ie8 and firefox. Thank you for your help
Form controls are made available as named properties of the form element. If there is more than one control with the same name, they are in a collecion. Assigning different values to the name property and attribute is asking for trouble. It should be that the second assignment overwrites the first, but no doubt there is a browser somewhere that will keep both values (one for the attribute and the other for the property).
The simple solution is to always use properties and only assign one value. If you want the name to be CBTest2 (since that is the second one assigned), then when the input is added to the form and the form to the document it will be available as:
document.forms['formName'].elements['CBTest2']
If the names are valid identifiers, then shorthand dot notation can be used:
document.formName.CBTest2
Since you have two elements with that name, the returned value will be a collection (a little like an array), so to get the first one, use:
document.formName.CBTest2[0]
You could use some code similar to...
var checkboxes = document.querySelectorAll('#some-form input[type="checkbox"]');
Array.forEach(checkboxes, function(checkbox) {
checkbox.addEventListener(function() {
var hasOtherCheckedCheckbox = Array.every(checkboxes, function(checkbox) {
return checkbox.checked;
});
});
});
Of course, for complete browser support, you'll need to modify this code a bit.

Categories

Resources