The code below works as I am able to click a button on the webpage using Python/Selenium/Firefox.
button on the webpage
driver.execute_script('''return document.querySelector('dba-app').shadowRoot.getElementById('configRenderer').shadowRoot.querySelector('ing-default-layout-14579').querySelector('dba-overview').shadowRoot.querySelector('ing-feat-agreement-overview').shadowRoot.querySelector('ing-ow-overflow-menu-14587').shadowRoot.querySelector('button')''').click()
However, some elements are dynamic and the numbers are changing anytime you rerun the script.
The changing elements:
'ing-default-layout-14579'
'ing-ow-overflow-menu-14587'
What must I do to get around the dynamic elements?
One option is to look for other attributes that stay the same across pageloads. For example, given your HTML, you could do:
document.querySelector('#configRenderer') // returns the config renderer element
document.querySelector('[data-tag-name="ing-default-layout"]') // returns the ing-default-layout element
document.querySelector('[data-tag-name="dba-overview]') // returns the dba-overview element
And so on. Or you could the same method to identify a parent or a child, and then navigate to the child or parent respectively.
If the HTML isn't stable enough even for that, another approach would be to search through all elements, and find the one(s) whose tagName starts with what you need.
for (const elm of document.querySelectorAll('*')) {
if (elm.tagName.toLowerCase().startsWith('ing-ow-overflow-menu')) {
// do stuff with elm, which is the overflow menu element
}
}
I have an jsTree, data comes from HTML
$("#tree_container").jstree();
Now I want to implement deep linking on the tree elements. I am getting the class and data-id from URL parameters and now I want to select the correspondent node.
var id=$("#tree_container").find("li."+get_class+"[data-id='"+get_id+"']").attr("id");
if(id!=undefined && id!=0) {
treeElem.jstree(true).select_node(id);
}
This only works if the node is already in the DOM Tree.
(sub-Trees are getting inserted in if the parent node is clicked)
If the node I want is not in the tree ... id is undefined and the select fails.
Thing is, if I put in the id (like "#j1_6") in directly the node is found even if it is not in the DOM tree. It only work with the Id in that format, I try putting other selectors in or even elements ($(".class[data-id='1']"), nothing worked.
My problem is that I do not know how to get the id of the node if it is not in the DOM Tree yet. I did not find a api function or anything to do that.
====== UPDATE ======
I found a workaround ...
When building the HTML tree I now combine the class and data-id to make up the html id of the element (li).
So I have controll over the ids and know them and just do:
treeElem.jstree(true).select_node("#"+get_type+"_"+get_id);
so yeah, as I said for me it is just a workaround...
I have this event handler from kendo's drag and drop UI and I've assigned it to a variable, lets say e.
I'm trying to select divs that have ID's containing a certain string. I know the syntax for that when continuing from classic jQuery selectors, i.e.
$('select div[id*="whatever"]')
But can I do this off of a variable that contains a DOM element? I know this is a rather simple question but google has thus far been unable to help me.
If you want to filter a preexisting jQuery result, you can go with this:
var $allDivs = $("div"),
$certainDivs = $allDivs.filter("[id*='whatever']");
I believe you might want .find
// returns all DOM elements that
// (1) are descendants of e
// (2) match the selector
e.find("selector");
If e isn't wrapped with jQuery, you might need to do $(e) instead.
I'm working on creating a basic question app to better understand backbone marionette. I'm my free-text questions right now use the same "#question-number-range id for setting the range of numbers users can enter when taking a survey. Then I split up the range and assign the min/max values accordingly.
This works great for the first free-text question view. But when I try to do the same thing on a second it ends up getting set to the first's min/max values because they have the same id.
What I'm wondering - is there a way I can do something like $(#el < '#question-number-range') to target just the input within the current view's el, rather than any input that has that id?
Or am I completely going about this wrong and need to maybe dynamically create the ids?
An id attribute is:
A unique identifier for the element.
There must not be multiple elements in a document that have the same id value.
so if you have duplicate ids then you don't really have (valid) HTML and all sorts of strange things can happen.
A better approach is to use a class to identify elements of interest. Then you could use #$('.whatever-the-class-is') to find the element within your view's el:
$ (jQuery) view.$(selector)
If jQuery is included on the page, each view has a $ function that runs queries scoped within the view's element. If you use this scoped jQuery function, you don't have to use model ids as part of your query to pull out specific elements in a list, and can rely much more on HTML class attributes. It's equivalent to running: view.$el.find(selector)
so #$(x) is the same as #el.find(x) and will limit your search to the view.
This is the same question as this:
Referring to a div inside a div with the same ID as another inside another
except for one thing.
The reason there are two elements with the same ID is because I'm adding rows to a table, and I'm doing that by making a hidden div with the contents of the row as a template. I make a new div, copy the innerhtml of the template to my new div, and then I just want to edit bits of it, but all the bits have the same ID as the template.
I could dynamically create the row element by element but it's a VERY complex row, and there's only a few things that need to be changed, so it's a lot easier to just copy from a template and change the few things I need to.
So how do I refer to the elements in my copy, rather than the template?
I don't want to mess up the template itself, or I'll never be able to get at the bits for a second use.
Or is there another simpler way to solve the problem?
It will probably just be easiest when manipulating the innerHtml to do a replace on the IDs for that row. Maybe something like...
var copiedRow = templateRow.innerHTML.replace(/id=/g,"$1copy")
This will make the copied divs be prefixed with "copy". You can develop this further for the case that you have multiple copies by keeping a counter and adding that count variable to the replace() call.
When you want to make a template and use it multiple times its best to make it of DOM, in a documentFragment for example.
That way it doesn't respond to document.getElementById() calls in the "live" DOM.
I made an example here: http://jsfiddle.net/PM5544/MXHRr/
id's should be unique on the page.
PM5544...
In reality, there's no use to change the ID to something unique, even though your document may not be valid.
Browsers' selector engines treat IDs pretty much the same as class names. Thus, you may use
document.querySelector('#myCopy #idToLookFor');
to get the copy.
IDs on a page are supposed to be unique, even when you clone them from a template.
If you dynamically create content on your page, then you must change the id of your newly cloned elements to something else. If you want to access all cloned elements, but not the template, you can add a class to them, so you can refer to all elements with that class:
var clonedElement = template.cloneNode(yes); // make a deep copy
clonedElement.setAttribute("id", "somethingElse"); // change the id
clonedElement.setAttribute("class",
clonedElement.getAttribute("class") + " cloned"
);
To access all cloned elements by classname, you can use the getElementsByClassName method (available in newer browsers) or look at this answer for a more in-depth solution: How to getElementByClass instead of GetElementById with Javascript?
Alternatively, if you have jQuery available, you can do this is far less lines of code:
$("#template").clone().attr("id","somethingElse")
.addClass("cloned").appendTo("#someDiv");
The class lookup is even simpler:
$(".cloned").doSomethingWithTheseElements();
Try to avoid using IDs in the child elements of the cloned structure, as all ids of the cloned element should be changed before adding the clone to the page. Instead, you can refer to the parent element using the new id and traverse the rest of the structure using classnames. Class names do not need to be unique, so you can just leave them as they are.
If you really must use ID's (or unique "name" attributes in form fields), I can strongly suggest using a framework like jQuery or Prototype to handle the DOM traversal; otherwise, it is quite a burden to resolve all the cross-browser issues. Here is an example of some changes deeper in the structure, using jQuery:
$("#template").clone().attr("id","somethingElse")
.addClass("cloned") // add a cloned class to the top element
.find("#foo").attr("id","bar").end() // find and modify a child element
.appendTo("#someDiv"); // finally, add the node to the page
Check out my ugly but functional cheese. I wrote a function that works like getelementbyid, but you give it a start node instead of the document. Works like a charm. It may be inefficient but I have great faith in the microprocessors running today's browsers' javascript engines.
function getelement(node, findid)
{
if (node)
if (node.id)
if (node.id == findid)
return node;
node = node.firstChild;
while(node)
{
var r = getelement(node, findid);
if (r != null)
return r;
node = node.nextSibling;
}
return null;
}
When you copy the row, don't you end up having a reference to it? At that point can't you change the ID?