Re-printing a div without having to refresh the page (incursion?) - javascript

I've been stuck with this for a while and have tried a few different things to no avail.
I have a function that prints elements to a page. Within that function, I have an addEventListener that upon click will change the order of those elements. When I refresh the page, it works, and the order is changed. However, I'd actually like the order to be changed upon click.
My original thought it calling the function within itself which I've tried but that doesn't seem to work. Any thoughts here?
printElements()
{
//prints elements to the page
addEventListener('click', function(event)
{
//changes order of elements
div.innerHTML = ''
printElements()
}
}

First get the info of the elements in array or object
Second remove all the elements
Third create the elements and set the info that you stored to them
Last append the the elements in order
that you want

Related

How to get around dynamic elements when web-scraping?

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
}
}

Assigning JQuery On Click Function in For Loop

I have a function that dynamically creates div elements based upon whatever input is given, and lets them choose certain items by clicking on each div. I have it so that if the div is clicked, a function (named checkToggle) is called that makes it looks like it is selected and adjusts some related variables. There is a checkbox in the div element that is toggled by this function (hence its name). Long story short, I had to jump through some hoops to get it to work, most of which I don't even remember. Please don't ask me about that.
The point of this question is this. I initially used the following JavaScript code to run the function when the checkbox was clicked. It was assigned by the main function, which created these div elements using a for loop.
document.getElementById(`${itemID}-checkbox`).onclick = function() {
checkToggle(`${itemID}-checkbox`);
};
This works, but I wanted to try to convert all of my onClick functions to JQuery. Here is the JQuery alternative I created.
$(`${itemID}-checkbox`).on(`click`, function() {
checkToggle(`${itemID}-checkbox`);
});
While the code itself seems to be fine, it does not work. It seems as if JQuery functions cannot be created like this in a for loop or something. It is applied after the element is created and put in its place, so I don't think it has anything to do with the element not being ready. I am also having the same issue with 2 other similar cases. Any idea as of why this isn't working?
Let me know if more information is needed and if so, what kind of information is needed.
You need to update the selector to Target HTML id using the # character. Simply prepend the character to the query:
$(`#${itemID}-checkbox`).on(`click`, function() { checkToggle(`${itemID}-checkbox`); });
It would also apply to DOM methods querySelector or querySelectorAll as well.
Hopefully that helps!

JQuery fails to find elements in iFrame after initial load

I have page specific html loading into an iFrame which contains objects that I'm trying to reference with jquery. When the page loads initially the elements are found as expected, but if I go to a new page and return or refresh the page the elements are no longer found consistently (fails more often then not) until I clear the cache and reload the page.
I've tried different combinations of querySelectorAll and getElementsByClassName but they only work consistently that first time in. It would seem like a race condition but why would it work the first time?
Does this problem sound familiar to anyone?
It did turn out to be a race condition where the dynamic elements were not yet available for reference. In my case the iFrame element was created using ExtJS so it needed this additional listener so I could take action after the load (putting this delay in afterrender came from another post that I'll need to find and give credit to);
afterrender: function (cmp) {
var element = cmp.getEl();
element.on('load', function () {
renderer.onIFrameReady();
});
}

why does removeChild in Javascript always removes the last child and not the one it got the id from?

i have four divs with the eventlistener onclick,
calling a js function which just does the following :
this.parentNode.removeChild(this);
i expect it to remove the div i clicked on, but it does not.
instead it deletes the last child and changes the id given after to the
id of the removed child (first click, the last child) and by further clicking on the
other divs counts down the given id to one. removing
the childNodes in the array from the last to the first.
i tried a lot of variants, for example
document.getElementById('parentElementName').removeChild(this.gettAttribute('id'));
or
parent =document.getElementById('parentElementName');
to_be_removed = document.getElementById(this.gettAttribute('id');
parent.removeChild(to_be_removed);
or with childNodes // id = 1,2,3,4
to_be_removed =document.getElementById('box_content').childNodes[this.getAttribute('id')];
parent =document.getElementById('box_content');
parent.removeChild(to_be_removed);
strange i can successfully change the visibility or the backgroundColor:
document.getElementById('box_content').childNodes[this.getAttribute('id')].style.visibility='hidden';
or
Managed to remake what you intended, go to http://jsfiddle.net/6YHcv/ to check it out. Is this what you needed?
If you are on IE and use attachEvent, this in the event handler would probably refer to the global object, not your element. Otherwise I can't tell why your code isn't working.
I see a few typos in your code. Your second example should work just fine, I think (see comments):
// make sure this is the parent element's ID and not the name, as this suggests.
parent = document.getElementById('parentElementName');
//note the double 't' in getAttribute; also, you are missing an end bracket
to_be_removed = document.getElementById(this.gettAttribute('id');
//looks good
parent.removeChild(to_be_removed);
Check out this example too, though: jsfiddle
It should be as simple as calling the function this.parentNode.removeChild(this) after an onclick handler.

Javascript multiple boxes design

I am writing a script using jQuery to add multiple control boxes(divs) to a web page. These divs contain controls (anchors) like close, prev, next, search etc. A code sample:
$div_overlay =
$('<div></div>')
.addClass('overlay')
.append($('<div></div>')
.addClass('text_controls')
//The onClick method below works perfect but not .click() of jQuery(due to the way 'index' is used)
.append($('<a onClick="overlay_hide('+index+'); return false;"></a>')
.addClass('close')
.attr('href','#')
/*.click(function(){
//The 'index' gets incremented as divs are created and hence a wrong value(the last one) is passed irrespective of the div clicked
overlay_hide(index)
})*/
)
'index' is a global var to keep track of the 'overlay' divs created.
It is incremented as the divs are created and each div is pushed in an array as it is created. So, 'index' is basically the array index of a div.
To keep it simple, I only added the 'close' anchor. The $div_overlay is in a function which is called every time an image is clicked.
My problem is to handle the click events for the anchors like 'close'. I would like to identify the div for which the anchor is clicked using an 'index' which is a global var.
I would like to be able to pass a reference to the div on which the close action is performed. If I use the jQuery click method which is commented in above code to close the div, it passes the last index value as the parameter to overlay_hide() (since index is incremented as the divs are created). If I use the onClick method as above, it works fine by passing the correct index value.
So, how do I identify these divs using indexes and be able to uniquely access them based on which div control is clicked? (Probably objects need to be used but I am not sure.)
One way would be to get the parent of the clicked anchor but I do not want to do it that way and would like to use an index.
You could add meta data to the anchor with a data attribute.
$('<a data-index="' + index + '"></a>').click(function(){
var data = $(this).data();
overlay_hide(data.index); // note index will be a string
return false;
});
Another way you could do it is with a closure on the click function:
$('<a />').click(function(i){
return function(e){
// use i here this is the callback.
overlay_hide(i);
return false;
};
}(index));
I would also like to point out that you have an id .attr('id','overlay') being added - and id's must be unique across the DOM.
You should read about closures and scope in JS: http://bonsaiden.github.com/JavaScript-Garden/#function.closures
Quick fix to your problem:
var closeButton = (function(index){
return $('<a></a>').addClass('close').attr('href','#').click(function(){
overlay_hide(index);
})
})(index);
var $div_overlay = $('<div></div>').attr('id','overlay').append(
$('<div></div>').addClass('text_controls').append(closeButton)
)
It'd be so much easier to just use the "overlay" class that's on the container:
$('body').delegate('a.close', 'click', function() {
$(this).closest('div.overlay').hide();
});
Just set that up, and things like it for the other types of control, and then you don't have to worry about sticking those ugly DOM0 handlers in your added tags at all.
I know you said you "don't want to do it that way", but unless you can explain why such an exercise is valuable in general, it seems unethical not to recommend the most obvious way to go about solving the problem.
I think you need to use the live() function, read this:
http://api.jquery.com/live/

Categories