0

I hope my question is not too specific.

I want to use a JavaScript function (below) to fetch all divs on an HTML page. The divs are not completely known beforehand, as the end changes based on line numbers and position. I can't seem to get querySelector('[id^= ...]') to work with variables, so need to use elementIds. The function should

  1. grab all DIVs,
  2. use a regex to match the beginning of the ID (that part I know),
  3. make an array, and
  4. grab the one value I need.

I fetch the textContent and run an operation on it (also not working). I have probably made this too complicated.

I have supplied some dummy data, which works for me to a point, but not all of it. When I use a live page, I get an HTML Collection, so I have tried: e.g.:

if (targetelements) {
  if (typeof targetelements.length === "undefined") {
    targetelements = targetelements.textContent;
  }

  targetelements = [].slice.call(targetelements).map(function(el) {
    return el.textContent;}).join(", ");
  }

  return targetelements;
}

but to no avail.

Where I have looked:

How can get the text of a div tag using only javascript (no jQuery)

JavaScript match against array

javascript - match string against the array of regular expressions

But I just have pieces I can't fit together. I basically CANNOT process the page, and CANNOT perform the other action on the argument "subfield" either.

What I am doing so wrong? Can anyone help? No jQuery (unfortunately), please. Thanks in advance.

NOTE 2 things:

  1. In reality, the IDs I want do not have classNames either, so I can't get the className and get the .id, and
  2. My function is triggered by a button and there are several iframes on the page. These are commented out below, but that's an implementation issue.

If I want a field, I put in e.g.: getfield("300", "a"). Here is my code:

function getfield(field, subfield) {
    //var iFrame = document.getElementById("iframe1").contentWindow.document.getElementById("iframe2");
    var i;
    var gotfield;
    //var target = "standard.textArea." + field;
    var target = new RegExp("standard.textArea." + field);
    var targetids = "";
    var targetid = "";
    var val = "";
    var targetelements = "";
         // dummy data, I turn it on, I turn if off
    var targetelements = "<div id='standard.textArea.245.Left.10'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 1 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div><div id='standard.textArea.264.Left.11'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 2 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div><div id='standard.textArea.300.Left.12'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 3 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div><div id='standard.textArea.500.Left.13'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 4 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div><div id='standard.textArea.520.Left.14'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 5 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div>";
    //targetelements = document.getElementsByTagName("div"); //<-- this is the live data I really will use, an html collection (inside an iframe.contentWindow)

    targetids = targetelements.match(/id='(.*?)'/g).map((val) => {
        if (val.indexOf(target) !== 1 && val.match(target)) {
            return val.replace(/id='/g, '').replace("'", '');
        }
    })
        targetid = targetids.find(el => el.match(field));

    console.log("The div I want is: " + targetid);
    if (document.getElementById(targetid)) { 
        gotfield = document.getElementById(targetid).getElementsByClassName("classlabel")[0].textContent;
        if (typeof subfield === "undefined") {
            // oh no
        }
        else {
            if (gotfield.indexOf("‡" + subfield) !== -1) {
                gotfield = gotfield.split("‡" + subfield + " ").pop(0).split(" ‡").shift();
            }
            else {
                return;
            }
        }
        return gotfield;
    }
    else {
        return "null"; // just so I can see
    }
}
// run a test with function 
getfield("245", "a"); 
kmoser
  • 8,780
  • 3
  • 24
  • 40
  • Use `querySelectorAll()` to find all matching DIVs. – Barmar Mar 19 '21 at 21:50
  • There is a huge difference between targetElements (the string) and targetElements (the HTMLCollection) that will make a lot of your code fail if you switch between them. For example, there is no match method on the htmlcollection. – James Mar 19 '21 at 21:54
  • 1
    ```document.querySelectorAll(`[id^=${variable}]`)``` will find all elements whose ID begins with the value of `variable` – Barmar Mar 19 '21 at 21:56
  • Can you describe in one short sentence what the `getField()` function is supposed to do? In other words, distinguish between the end result of what you're trying to accomplish from *how* you're trying to accomplish it. E.g. "Given a number X, retrieve all the divs whose IDs begin with `standard.textArea." or something like that. – kmoser Mar 19 '21 at 22:13
  • @Barmar many thanks, but I get a DOMException: '[id^=standard.textArea.245]' is not a valid selector with that (I am using variable: var target = "standard.textArea." + "245"; in my example and putting in: document.querySelectorAll(`[id^=${target}]`); -- what I am doing wrong here?). – Werther's Sorrows Mar 19 '21 at 22:16
  • Sorry, I forgot that JS requires the value to be in quotes, I'm used to jQuery. – Barmar Mar 19 '21 at 22:17
  • ```document.querySelectorAll(`[id^="${variable}"]`)``` – Barmar Mar 19 '21 at 22:18
  • @kmoser getfield() is called in a larger script by another function that checks certain fields and evalutes whether field X has a valid number in it, is missing information, etc. – Werther's Sorrows Mar 19 '21 at 22:26
  • @James many thanks also; I see this is a problem and tried to solve it with slice-call-map-join, thinking I could(?) make an array out of the HTMLCollection. I have looked here: https://stackoverflow.com/questions/29107655/getting-values-from-an-htmlcollection-to-a-string but still don't understand how to "match" or "find" or deal with this Collection ... can you explain? – Werther's Sorrows Mar 19 '21 at 23:02

1 Answers1

0

Try to get querySelector/querySelectorAll to work as @Barmar suggested.

const field = "300";
const theThing = document.querySelector(`div[id^='standard.textArea.${field}']`);
console.log(theThing);
const theSubThing = theThing.querySelector('.classlabel').textContent;
console.log(theSubThing);
//etc
<div id='standard.textArea.245.Left.10'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 1 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div>
<div id='standard.textArea.264.Left.11'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 2 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div>
<div id='standard.textArea.300.Left.12'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 3 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div>
<div id='standard.textArea.500.Left.13'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 4 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div>
<div id='standard.textArea.520.Left.14'><div class='classlabel'><h2>Lorem Ipsum</h2> <p>‡a 5 Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p></div>
James
  • 20,957
  • 5
  • 26
  • 41
  • All this is very helpful. I am _still_ having issues with NodeLists/HTML Coll. For instance, if I have: `var targetids = document.querySelectorAll(`[id^="${target}"]`);` then act on that with `targetids = document.querySelectorAll(`div[id^="${target}"]`); Array.from(targetids).forEach(element => {console.log(element); return element.id; });` then I can see it in the NodeList as an Attribute in `NamedNodeMap`. But it gets returned with id **and** `style` information. I just need the ID name (e.g. standard.textArea.X) as in James' example. What am I doing so wrong? – Werther's Sorrows Mar 21 '21 at 02:37
  • I am currently trying to access this information as per [link] (https://stackoverflow.com/questions/30850158/i-need-value-from-a-named-node-map). I'm using `targetid = targetids.attributes.getNamedItem("data-value").id;` but not getting anywhere. Am I going down a rabbit hole here...and making things too complicated? – Werther's Sorrows Mar 21 '21 at 03:09
  • **Answered my question** I solved my problem. I'll post the bit I had questions about in case it helps someone else. The following code allows me to get both the text content of "standard.textArea.X" and the element.id so I can use both as needed. I'd like to thank Barmar and James for all your help! Thanks guys! Wish I could up-vote you. `var target = "standard.textArea." + field; var targetids = ""; var targetid = ""; targetids = document.querySelectorAll(`div[id^="${target}"]`); targetid = [].slice.call(targetids).map(function(el) {return el.id;}).join(", ");` – Werther's Sorrows Mar 21 '21 at 06:27