started programming javascript a few months ago. I've been using the 'document.write()' command initially but having it wipe my html each time it's used is a little counterproductive.
Using the getElementByID("div's ID").innerHTML = or anything you think is better, what would effectively run this code but add it to whatever's currently in the div, not replace it.
x = x + 1
document.write( "you have clicked this button" + x + "times")
So like after 3 clicks it should say:
you have clicked this button 1 times
you have clicked this button 2 times
you have clicked this button 3 times
Thanks very much.
element.insertAdjacentHTML('beforeend', htmlString);
Where element is a reference to a DOM element (e.g. returned from document.getElementById).
Demo
insertAdjacentHTML Reference
Note: though element.innerHTML += htmlString is also possible, it is usually a bad practice as all of the element's innerHTML would be re-parsed into new DOM elements, trashing out the old elements and their attached listeners/data.
Did you try console.log(""). the console.log() is used to display your string on the console of your chrome or firefox browser. Right Click on the browser and select inspect element, then select console tab on topright. any errors in the page and any function called on console will be displayed here
Related
I am a .NET (C#) programmer with no background in javascript trying to automate mouse clicks and text extraction. I am using MS Edge as a control and passing javascript to it from C#.
Here is the page I want to automate: link. Scroll mid-page to the Variants section, you will see nested tabs. The idea is to click an outer tab and then click each inner tab it contains, and repeat for each outer tab. Here is a gif of the mouse clicks done manually: gif.
For the extraction part I'd like to extract the text right under each mouse click in the gif. For e.g. for the first outer tab and its nested tabs, I should get "Nephalem Rifts", "Wizard", "Enchantress".
Retrieving the number of outer tabs, clicking each one and getting their text labels works.
Retrieving the number of inner tabs works, but clicking and extracting their text label does not work.
Here's my js code so far: {i}, {j} and {k} are integer variables resolved at runtime before passing to MS Edge. Assume {i} is always 0. {j} and {k} refer to the indices of the outer and inner tabs respectively.
Number of outer tabs:
document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab').length;
Click an outer tab:
document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab')[{j}].click();
Extract the text label of an outer tab:
document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab')[{j}].getElementsByTagName('span')[0].textContent;
Number of inner tabs: ("" resolves to " before the string is passed to Edge)
document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab-body-wrapper')[0].querySelector('div[style=""display: block;""').getElementsByClassName('d3p-mode').length;
The following code DOES NOT work.
Click an inner tab: (when there are 2 inner tabs, the 2nd is never clicked. I pause execution for 1.5 seconds in C# after each click)
document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab-body-wrapper')[0].querySelector('div[style=""display: block;""').getElementsByClassName('d3p-mode')[k].click();
Read the text label of an inner tab: (returns null)
document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab-body-wrapper')[0].querySelector('div[style=""display: block;""').getElementsByClassName('d3p-mode')[k].getElementsByClassName('d3p-name')[0].innerText;
Please explain why it's not working and provide the correct code.
What tool/IDE would you use to debug and execute such javascript against a live (not locally hosted) webpage?
I dumped the DOM snapshot to a local file. What tool/IDE would you use to debug and execute such javascript against a local file?
Thanks!
i fixed the code, please try now. i hard coded the indices to run in browser, you can replace it with your indices
for clicking tabs
document.getElementsByClassName('advgb-tabs-wrapper')[0].getElementsByClassName('advgb-tab-body-wrapper')[0].querySelector('div[style="display: block;"').getElementsByClassName('d3p-mode')[0].click();
for reading texts from tabs
document.getElementsByClassName('advgb-tabs-wrapper')[0].getElementsByClassName('advgb-tab-body-wrapper')[0].querySelector('div[style="display: block;"').getElementsByClassName('d3p-mode')[1].getElementsByClassName('d3p-name')[0].innerText;
there is issue with your css selectors:
querySelector('div[style=""display: block;""')
i fixed here
querySelector('div[style="display: block;"')
*developers tool is the best debugger for debugging clientside issues.
When you use querySelector searching for 'style=' you will only match elements that have that exact style, meaning only 'display: block'! Elements do always have more than one style, which means they won't be matched.
The solution is to use the 'contains' selector (*=) instead.
So you inner tab selector should look like this:
#"document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab-body-wrapper')[0].querySelector('div[style*=""display: block;""]').getElementsByClassName('d3p-mode').length;"
Now it should match all elements that contains the 'display: block;' style even when they have plenty of other styles too.
Important note: This will only work, if you have set the style on the element using the style attribute! I f you have set the style using other css like classes, it won't work, even when the class contains display: block;.
If you have set the style using a class you should query for that instead.
And finally: The universal solution:
Using getComputedStyle works no matter how you have set the style, since it checks the actual style. The syntax is a bit different:
#"[...document.getElementsByClassName('advgb-tabs-wrapper')[{i}].getElementsByClassName('advgb-tab-body-wrapper')[0].children].filter(value =>
{
return getComputedStyle(value).display !== 'none';
}).getElementsByClassName('d3p-mode')[k].getElementsByClassName('d3p-name')[0].innerText;"
This code will first convert the children list to an array and filter that array (display must not be 'none').
I have this code I wrote
Currently it uses innerHTML to write to the page with a forloop. However, I noticed that instead of writing everything. It just writes the last element in the array.
I searched and saw that I have to use the DOM to get this done as innerHTML will ALWAYS destroy instead of replacing. So I wrote this
function print(message) {
var mydiv = document.getElementById("box");
mydiv.appendChild(document.createTextNode(message));
}
To go inside my code and replace the innerHTML line. However, this doesn't seem to work. Can anybody help me getting it running?
by "this doesn't seem to work" i mean that the code won't append to the child of box. so my text will not be inserted into the element with the 'box' ID.
What i want to happen is just like in my codepen where i used innerHTML but instead of each only the last element in the array showing up, i want them all to show up
edit:
okay updated the codepen. seems the code I posted on this page kinda works. but it doesn't seem to go in the right place. if you check the codepen and add some text and scroll down you can see it doesn't fit into place
Change the print function in this way:
function print(message) {
var html = document.getElementById("box").innerHTML;
document.getElementById("box").innerHTML = html + message;
}
http://codepen.io/anon/pen/bwBOdq
I have this function:
function main() {
var bottomArea = document.getElementsByClassName("bottom-area");
for (var i = 0; i < bottomArea.length; i++) {
var showDialogLink = document.createElement("a");
showDialogLink.innerHTML = "link";
showDialogLink.onclick = function(){showSelect(this);return false;};
bottomArea[i].insertBefore(showDialogLink, bottomArea[i].childNodes[3]);
}
}
So far the code works just fine. When I click the newly created link, it calls showSelect(this) function just fine.
The problem is there is another userscript/browser extension (which I don't have access to - it's not mine), which basically clones whole another div in which 'bottom-area' div is nested. This is all right too, but the problem is that it doesn't clone my function trigger and those newly cloned instances (I'm not really sure what is their nature) of that link do no longer trigger showSelect(this) function. Only the first one created by my userscript does.
Is there some way in which I should add my function trigger on my link, that will stay even after cloning/copying?
EDIT: I'll just edit to show html tree:
This is at the beginning:
<div>
<div class="bottom-area"></div>
</div>
My userscript adds a link with an onclick eventlistener on the 'a' tag:
<div>
<div class="bottom-area"><a>link</a></div>
</div>
The other userscript basically clones it (there is a textarea inside the div and its value gets cloned too), but without the eventlistener, so clicking on the cloned links no longer triggers my function.
EDIT2: If it helps, the userscript I'm creating is a reddit userscript. I'm adding small functionality to commenting and adding a link right next to the 'reddiquette' link under the comment text field. That works with the pre-generated text field. However when I click 'reply' down the comment tree, the whole div together with text field, submit button and my link gets cloned under the comment I'm replying too, but my link no longer has the function trigger on itself.
The easiest solution may be to simply use HTML event attributes (instead of addEventListener), such as <a onclick="dostuff();">link</a>, because the attribute should be preserved during 'cloning'. See this fiddle (tested in Firefox 40) for an example.
Letting the code in the onclick attribute interact with your userscript may be be a little difficult because it runs in a different JavaScript environment. Luckily there's plenty of possible workarounds, depending on your exact needs.
Can't seem to get this one to work...
I have a page that hides certain links. When the DOM is loaded, I'm using jQuery to toggle some of those elements. This is driven by using a data attribute like so:
<div class="d_btn" data-usr='48'>
<div class="hidden_button">
Then, I have the code:
$.each($(".d_btn"), function() {
var btn = $(this).data('usr');
if ( btn == '48' ){
$(this).children('.hidden_button').toggle();
}
The above all works as planned. The problem is that I am trying to remove the data-usr from the class .d_btn once the if statement is evaluated. I've tried the following and nothing works (i.e., after the page is loaded, the source still shows the data-usr attribute:
$(this).removeAttr("data-usr");
$(this).removeData("usr");
I've been working on this for a couple of hours now and...nothing! Help is greatly appreciated!
UPDATE
I've tried the great suggestions of setting the data attribute to an empty string but I'm still not getting the desired result.
To explain a little further, The reason I'm trying to remove the attribute is so when an ajax response adds another item to the page, the previously added items would already have the button either shown or hidden. Upon AJAX response, I'm calling the same function once the DOM is loaded.
Currently, when something is added via AJAX, it toggles all the buttons (showing the ones that were hidden and vice versa.) Ugh...
I'm also fully willing to try alternatives to my approach. Thanks!
UPDATE
Well, the light bulb just flashed and I am able to do what I want to do by just using .show() instead of .toggle()
Anyway, I'd still like to find an answer to this question because the page will be potentially checking hundreds of items whenever something is added - this seems horribly inefficient (even for a computer, hahaha.)
Why don't you set the value to a random value or empty variable instead if removeAttr does not work..
$(this).attr("data-usr" , '');
$(this).prop("data-usr" , '');
Changing the DOM doesn't affect the source. It affects the DOM, which you can view with the Inspector/Developer Tools. Right click => View Source will give you the original source of the page, not the actual current source as modified by JavaScript.
Set it to a blank string:
$(this).attr("data-usr", "");
I second what Kolink said: check the DOM, not the source. (Chrome: Ctrl + Shift + i).
As others have stated. Checking the source will only show the original unedited source for the webpage. What you need to do is check the DOM using developer tools.
I've just checked everything in Chrome's inspector on jsfiddle here and the attribute is definitely being removed as well as the data.
So, I have this pretty complex ajax thing going.
It loads new html (including div tags and all) to show up on the page.
I included a 'more' link to load additional data.
This more link links to my javascript function. The 'more' link is located in a div, which I gave a unique id. The next time the load function is called, I use document.getElementById(the id).style.display="none"; to "remove" this div from the look of the page.
I set error traps for this, the div with that id is found without problems, but javascript fails to change my style property.
I tested alert(document.getElementById(the id).innerHTML); and that worked without problems - hence the title of the question.
So, does anyone have any ideas/do I need to offer more information? The main problem is that it doesn't throw any errors anywhere, yet it fails to complete the task I asked...
Here's a bit of code to go with it -
try
{
var myidthing = "morelink" + ContentStart.toString(); //the id is correct
var div = document.getElementById(myidthing);
if (!div)
{
}
else
{
div.style.display="none"; //this doesn't work, but doesn't raise an error
alert(div.innerHTML); //this works without problem
}
}
catch(theerr)
{
alert(theerr);
}
------------------------->EDIT<-------------------------
I'm incredibly sorry if I upset any people.
I'm also angry at myself, for it was a stupid thing in my code. Basically, I had a variable that stored the contents of a parent div. Then I (succesfully) removed the div using the removeChild() method. Then my code pasted the contents of that vaiable (including the div I wanted gone) back into the parent div.
I switched around the order and it works fine now.
Again, excuse me for this.
Throwing out a few ideas of things to look for:
You said the div is generated by javascript. Is it possible the div you are targeting is not the one you think you are? It could be you are targeting another div, which is already hidden, or obstructed... or maybe the innerHTML you are displaying goes with a different element than the one you intend to target. Put an alert or script breakpoint in the if(!div) case, also, and see if it's going down that path.
If the above code is only a stripped-down version of your actual code, check your actual code for typos (for example: style.display = "none;";)
Using the FireBug plugin for FireFox, inspect the target element after the operation completes, and make sure that the display: none appears in the style information. If not, use FireBug's debugger to walk through your javascript, and see if you can figure out why.
Use FireBug to break on all script errors, in case there is another error causing this behavior.
Try empty quotes instead of 'none' and see if that works?:
document.getElementById('element_id').style.display="";
Failing that, don't change the style, just add a class which hides the element.