javascript find node without id - javascript

Due to a limitation of the Javascript library I'm using, I can't assign an id to a <div>. Unfortunately, I don't know how to attach a Tooltip object from Tipped, a Javascript tooltip library, to the element without an id. I don't know if this is possible, but I'm trying to find the object via other means which will hopefully allow me to modify the id.
The element I'm looking for is a button on a toolbar, but it's not an HTML button. It's a <div> that has CSS styles and Javascript events assigned to make it look and feel like a button. I know the class name of the parent and I know the id of the grandparent <div>, but that's as much as I know. Part of the issue is that there doesn't seem to be a good reference for how to iteratively operate on HTML objects once you get a reference to them. I've seen plenty of examples like this:
var x = document.getElementsById("asdf")
but no follow-up code showing how to actually do anything. What's in x? What methods does it have? I know of innerHTML and innerTEXT, but I can't figure out if they apply to x, a child of x, or ???. The Chrome console has helped a little bit, but I'm basically lost.
This is the relevant code for my button:
As you can see, there is no id on the Export button, but the parent has a class name and the grandparent has an id. The other snag is that the grandparent's id isn't static. It always starts with "dhxtoolbar" and there is only one toolbar on the page, but I haven't been able to make a regex search find the toolbar.
Ultimately, I'd like to be able to attach a Tipped tooltip to the Export button. I think Tipped requires an id, but maybe it doesn't. Regardless, I'd like to understand more about how to iterate through the DOM and, as a bonus, figure out how or if I can change the id of an element on a live page. Thanks.

Tipped actually accepts any CSS selector as an argument. If the class is unique, you could target it that way:
Tipped.create('.dhx_toolbar_btn', 'some tooltip text');
Or if the class isn't unique, you could try target it via the tree structure. Made up example:
Tipped.create('.header .sidebar .dhx_toolbar_btn', 'some tooltip text');
I noticed in your html that the buttons have empty title attributes (or maybe your inspector just added them). If you can set the title attribute for the buttons Tipped will pick it up automatically. Example:
<div class="dhx_toolbar_btn" title="test title">
You would then only have to use:
Tipped.create('.dhx_toolbar_btn');
And Tipped will automatically pick up the title and use it.

This is what I was trying to have explained:
var Obj = document.getElementsByClassName("classname");
var ObjChildren = Obj[0].getElementsByTagName("tag")
var searchText = "string";
for (var i = 0; i < ObjChildren.length; i < i++) {
if (ObjChildren[i].innerHTML == searchText) {
console.log(ObjChildren[i].innerHTML);
}
}

Related

Changing an elements ID using Javascript

I'm trying to change the id 'character' to 'characterSelected'
var character = document.getElementById('character');
var characterSelected = document.getElementById('characterSelected');
function klik() {
character.innerHTML = characterSelected;
}
character.addEventListener('click', klik);
This is what I have so far but it doensn't seem to work. I want to do this using Javascript only, no jQuery.
Thanks
You tried something, it didn't work. Now is the time to look up the standard properties and functions you're using incorrectly. If guessing doesn't work, always look for reliable documentation.
A good reference would be the Mozilla Developer Network (MDN). It's a wiki-style encyclopedia about the web, its standards and current browser compatibility. If you look at the page about innerHTML, you'll find the following:
The Element.innerHTML property sets or gets the HTML syntax describing
the element's descendants.
This means that the innerHTML property is used to replace the content of a tag as if you wrote that HTML inside it. Not what you want.
What you wanted was to change the id of an element. If you search for element id, you'll land on the Element.id page. And how practical, there's an example:
var idStr = elt.id; // Get the id.
elt.id = idStr; // Set the id
However, this is not going to fix your issues. You see, you guessed wrong when trying to use the getElementById function. This function looks at the page and finds the element with that id right now. If you don't have any element with the characterSelected id at first, then this variable you set is going to be null for the rest of time. Variables won't magically update when an element with that id is placed in the page.
And finally, you have missed the purpose of the id attribute itself.
Its purpose is to identify the element when linking (using a fragment
identifier), scripting, or styling (with CSS).
The purpose of an id is to identify an element uniquely. You might think: "that's what I'm doing". No. You're using an id to represent whether or not an element is selected. This is wrong. Depending on your objective, I would say: just store the selected element inside a variable. Then whenever you need to do something with the selected element, it's in that variable. If you need specific style for that element, then you could set a class to it. But the id isn't meant for this at all - in fact, an id isn't meant to change once an element is placed.

Targeting an inputs value inside an HTML collection

I am making a card flipping game and I'm stuck on a particular function. During gameplay, cards disappear (by changing class name)
function reShuffle() {
var cds = document.getElementsByClassName('nocard');
for (var t = 0; t < cds.length; t++) {
console.log(cds[t]);
///i need to target an input within a div, inside another div, inside cds[t];
///make sense?
}
}
The function above is sending a collection of HTML to my console. The console looks like this: (the html collection are the items that the user got points for, so the console return can vary based on user actions)
Now, i want to target all inputs inside of divs that have class 'nocard', but not the other inputs of the same name. When I tried to make a loop to call the class 'fntCls' the console returned all of the inputs and not just the ones inside of the divs with class 'nocard'.
I hope i explained this right. I need to target the values of class 'fntCls' that are in the cards that have the class 'nocard', but not the ones that are in class 'cards'.
I went to make a fiddle, but it doesn't work properly with the way i use localStorage. So i can post a git if necessary. Also, i should mention that i am not using Jquery or any other libraries. I would like "vanilla" JavaScript assistance.
I'm sorry if this is long, or not precise to describe what i need. I really struggled to find the right words to explain what is going on here, it's my first time trying to do this particular action. Thanks in advance.
Using document.querySelectorAll you can target the inputs like so:
document.querySelectorAll('.nocard input.fntCls')
The .nocard targets the elements with the class nocard and input.fntCls will target the inputs inside those elements with the fntCls class.

Javascript - set innerHTML of span under button

I have a DOM that is being set (in part) by a plugin at runtime so I don't have full control over it. The initial object that I create in my HTML is a <select> object to which the plugin bootstrap-select is creating a <button> as a sibling. This <button> in turn has a child <span> element (also created by the plugin). It is this <span> element whose text I want to change.
I also am changing the background color of the button itself, and this works. I just need to add a line or two to my function to update the text of the span, and I'm good to go.
Here is a screenshot of the relevant part of the DOM (the gray part is what I have to set):
And here is my code. This was written originally to set the background color of the button, and to that extent it works correctly. I just need to expand it to set the text, as well:
function setColorForSelect(elem, col) {
// this will change the background color of the <select> object just changed to match the selection
// this is necessary because bootstrap-select imposes a complex DOM structure on the <select> item
// (there is a <button> that is what is being displayed, so that is the object whose background color needs
// to be changed, not the <select> object itself)
$(elem).siblings().each(function() {
var _this = $(this);
if(_this.is(":button")){
_this.css('background-color', col);
$(this).children(":first").innerHTML = col; //<-- THIS IS THE LINE THAT DOESN'T WORK!
return false;
}
});
}
This isn't throwing any errors, but it isn't changing anything that I can see. How can I get a reference to this <span> so that I can change its text? Thank you!
Use this syntax.
Find the first span in the button and change its text.
$(this).find("span:eq(0)").text(col);
Or
Find the span by specific class and change its text.
$(this).find("span.filter-option").text(col);
There are couple of other methods too. I think those are already pointed out in other answers.
The reason there are no errors is because you just assigned the col value to an innerHTML property on a jQuery object.
Either use the html function jQuery provides for its object
.children(":first").html(col);
or use the text function jQuery provides
.children(":first").text(col);
or use the native JavaScript api by accessing the native element
.children(":first")[0].innerHTML = col;
or use the getter jQuery provides to get the native element and then use the native API
.children(":first").get(0).innerHTML = col
One more...
You could also do:
$('span:first',this).text(col); //
Hope it helps!

How to select elements within a variable using jQuery?

I'm trying to make a simple image browser for TinyMCE which I am using in my CMS. As part of this I need to detect whether the user has selected an existing image, so I can display the "edit" form instead of the "choose an image form".
var selected_html = ed.selection.getContent();
var $elem = $(selected_html);
console.log($elem);
The first function returns the user selected text from the editor window as a string of HTML. I then would like to use jQuery (although plain javascript is just ok too) to check if this string contains an img tag before subsequently grabbing the src and title attributes for editing.
Now I've got as far as getting the html to turn into an object. But after this I can't manage to search it for the img element. After reading this (How to manipulate HTML within a jQuery variable?) I tried:
$elem.find('img');
But it just comes out as an "undefined" object...
I think I'm missing something fairly obvious here (it is getting late), but after an hour I still can't figure out how to grab the img tag from the selection. :(
Many thanks in advance.
Because the <img> is at the root of the jQuery object, you need to use .filter() instead of .find().
$elem.filter('img');
The .filter() method looks at the element(s) at the top level of the jQuery object, while .find() looks for elements nested in any of the top level elements.
If you're not sure beforehand where the target element will be, you could place the HTML into a wrapper <div> to search from. That way the HTML given will never be at the top.
var selected_html = ed.selection.getContent();
var $elem = $('<div>').html(selected_html);
var $img = $elem.find('img');
Try to see what is really inside your $elem variable. Just do a console.log($elem) using both Firefox and Firebug and you should be able to manage quite alright! ;)

What information about a DOM element would allow JavaScript to identify it (somewhat) uniquely? (e.g. when it doesn't have `id`)

Here's what I'm trying to do: I have a bookmarklet that is looking for elements in the current page (which can be any site) and dispatch a click event on the ones that match. I have that part working.
In some cases though, nothing matches automatically and I want to be able to show (by hovering it) what element should be activated and then save some info about it in localStorage. The next time I'm using the bookmarklet on that page, I want to retrieve that info to identify the element in the DOM and then dispatch a click event.
The question is: what information should I save to be able to identify it? (in most cases, since it will always be possible to create a case where it doesn't work)
In the best case, said-element will have an id value and I'm good to go. In some other cases, it won't and I'd like to see your suggestions as to what info and what method I should use to get it back.
So far my idea is to save some of the element's properties and traverse the DOM to find elements that match everything. Not all properties will work (e.g. clientWidth will depend on the size of the browser) and not all types of elements will have all properties (e.g. a div node won't have a src value), which means that on one hand, I can't blindly save all properties, but on the other, I need to either choose a limited list of properties that will work for any kinds of element (at the risk of losing some useful info) or have different cases for different elements (which doesn't sound super great).
Things I was thinking I could use:
id of course
className, tagName would help, though className is likely to not be a clear match in some cases
innerHTML should work in a lot of cases if the content is text
src should work in most cases if the content is an image
the hierarchy of ancestors (but that can get messy)
...?
So, my question is a bit "how would you go about this?", not necessarily code.
Thanks!
You could do what #brendan said. You can also make up a jQuery-style selector string for each element in the DOM by figuring out the element's "index" in terms of its place in its parent's list of child nodes, and then building that up by walking up the DOM to the body tag.
What you'd end up with is something that looks like
body > :nth-child(3) > :nth-child(0) > :nth-child(4)
Of course if the DOM changes that won't work so good. You could add class names etc, but as you said yourself things like this are inherently fragile if you don't have a good "id" to start with, one that's put there at page creation time by whatever logic knows what's supposed to be in the page in the first place.
an approach would be using name, tagName and className-combination. innerHTML could may be too big.
another approach would be to look for child elements of your choosen element which have an id.
check for id => check for childs with id => check for name, tagName and className-combination (if => tell user to choose a different item :-)
What about finding all elements without an ID and assigning them a unique id. Then you could always use id.
What about using the index (integer) of the element within the DOM? You could loop through every element on page load and set a custom attribute to the index...
var els = document.getElementsByTagName("*");
for(var i = 0, l = els.length; i < l; i++) {
els[i].customIndex = i;
}

Categories