0

I am doing a JavaScript code to hide elements on a website that does not start with a certain text.

There are a bunch of combinations that can be output in a <span> on the website. They all start with 2 digits and then a letter. For example:

76T
92Q
18H
71S

Sometimes the strings also contain text at the end of the line. But right now I am trying to find out which lines contains 2 digits (no matter which) and the letter "F" afterwards. Like 92F, 35F, 19F and so on.

I am trying to use the javascript .Match but I get no results. it says no such function exists.

My code:

var descriptions = document.getElementsByClassName('myClass');
var reg = new RegExp("^([0-9])F(.*)");

for (var i=0; i<descriptions.length; i++) {
    if (descriptions[i].match(reg)) {
        console.log('it exists!');
    }
}

Basically I just want all the strings that begins with digits (0-9) and the letter F. there are NO spaces between them.

Output on website looks like this:

<span class="myClass">36P Wooden</span>

Edit:

Hide/remove the divs that does not contain this text.

var descriptions = document.getElementsByClassName('myClass');
var reg = /^\d{2}F/;

for (var i=0; i<descriptions.length; i++) {
    if (!descriptions[i].textContent.match(reg)) {
        descriptions[i].closest('myClass2').style.display = 'none';
    }
}
Lee Cheung
  • 101
  • 2
  • 9

1 Answers1

1

getElementsByClassName returns an array-like collection of elements, and elements do not have a .match method. Check the textContent of each element instead, and consider using regex literals instead of new RegExp:

var descriptions = document.getElementsByClassName('myClass');
var reg = /^\d{2}F/;

for (var i=0; i<descriptions.length; i++) {
    if (descriptions[i].textContent.match(reg)) {
        console.log('it exists!');
    }
}

var descriptions = document.getElementsByClassName('myClass');
var reg = /^\d{2}F/;

for (var i=0; i<descriptions.length; i++) {
    if (descriptions[i].textContent.match(reg)) {
        console.log('it exists!', descriptions[i]);
    }
}
<span class="myClass">36P Wooden</span>
<span class="myClass">11F something</span>

If you want a collection of elements which match the pattern, use .filter instead:

var descriptions = document.getElementsByClassName('myClass');
var reg = /^\d{2}F/;

const matchingElements = [...document.querySelectorAll('.myClass')]
  .filter(elm => elm.textContent.match(reg));
console.log(matchingElements);
<span class="myClass">36P Wooden</span>
<span class="myClass">11F something</span>
<span class="myClass">22F something else</span>

Or, if you need all of the matching strings, use Array.from to map each element to its textContent first, before filtering:

var descriptions = document.getElementsByClassName('myClass');
var reg = /^\d{2}F/;

const matchingStrings = Array.from(
  document.querySelectorAll('.myClass'),
  elm => elm.textContent
)
  .filter(textContent => textContent.match(reg));
console.log(matchingStrings);
<span class="myClass">36P Wooden</span>
<span class="myClass">11F something</span>
<span class="myClass">22F something else</span>

To find each parent of an element which does not match, check if .every one of the parent's myClasses do not matche:

const parentsWithNoMatches = [...document.querySelectorAll('.myClass2')]
  .filter(parent =>
    [...parent.querySelectorAll('.myClass')]
      .every(child => !child.textContent.match(reg))
  );
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Great! Thank you! As I only want to display the ones that does match 2 digits and F, is there any way I can hide all other objects on the page? This has to be done to the parent classes. Because there are about 6 divs, and then inside the 6th div there is this string. I'd have to go back 6 steps in the code and remove all of those nested divs prior to the string. Any idea how to do that? EDIT: I can't use jquery to hide it. – Lee Cheung Jun 29 '19 at 23:21
  • Sounds like you need to invert the test - check if the match fails, rather than if the match succeeds. Hard to say what to do about the parent elements without seeing their code – CertainPerformance Jun 29 '19 at 23:24
  • I'd have to remove / hide the entire div with the class "myClass2" that is the parent of this string. So the closest "myClass2" (above) should be hidden. – Lee Cheung Jun 29 '19 at 23:27
  • I edited my first post here with the current code. Getting the error: `Uncaught TypeError: Cannot read property 'style' of null at :6:53` – Lee Cheung Jun 29 '19 at 23:30
  • Sounds like one of the `myClass` elements does not have a `myClass2` parent. Iterate over the parents instead – CertainPerformance Jun 29 '19 at 23:31
  • I uploaded an image of what it looks like. The parent div with class `w-50-ns w-100 ph1` is the one I want to hide or remove. https://i.imgur.com/WUS3IBf.png – Lee Cheung Jun 29 '19 at 23:36
  • Ok, so just substitute the parent class name into where `myClass2` is in the code in the answer (and the child class name into where `myClass` is) – CertainPerformance Jun 29 '19 at 23:37
  • Yes I tried it but it says undefined. The "..." should be replaced with something else? In that const – Lee Cheung Jun 29 '19 at 23:39
  • "It says undefined" isn't an error message - what exactly is the error message? No, the `...` is necessary, it spreads the collection into an array – CertainPerformance Jun 29 '19 at 23:40
  • I may be placing the const at a weird position. I placed this in the if statement of my code. Where should I place it? because I am just getting "undefined" in the console. – Lee Cheung Jun 29 '19 at 23:41
  • The last code block stands on its own - it doesn't go anywhere in particular in your Javascript, it could even be *all* of your Javascript. What exactly is the error message? `undefined` by itself won't appear in the console unless you actually log `undefined` somewhere, which isn't anywhere in the code I posted – CertainPerformance Jun 29 '19 at 23:44
  • When you type code into the console directly, the last expression evaluated will be printed on the next line of the console - unless you're *looking* for an expression, you can just ignore it. That's not an error - you now have an array of all parents which do not have one of those children. – CertainPerformance Jun 29 '19 at 23:48
  • The `.w-50-ns w-100 ph1` selector string will select children which have a tag name of `ph1`, which have a parent of a tag name of `w-100`, which have a parent with a class of `w-50`. You don't want the descendant selector here, if you want to select the elements in the picture, prefix all the class names with `.`, not with a space – CertainPerformance Jun 29 '19 at 23:51
  • Oh okay. So the `parentsWithNoMatches` contains all the items. So to hide them, I should loop through each or can I hide all at once? But how do I even target each item in the array. I only did that by targeting either id or class before. But this is an object. I can't use style.display = none on the objects – Lee Cheung Jun 29 '19 at 23:52
  • Just loop through the array https://stackoverflow.com/questions/3010840/loop-through-an-array-in-javascript – CertainPerformance Jun 29 '19 at 23:53
  • My brain just exploded. I can loop it, but is each one in the list a document? I just make document[i].style.display = none; ? Because it dont work – Lee Cheung Jun 29 '19 at 23:53
  • No, each page/tab/`window` only has one document associated with it (the HTML page). Each item in the array is an *element*, so if you loop through it properly, setting its style like that should work fine https://jsfiddle.net/jcLvb62k/ – CertainPerformance Jun 29 '19 at 23:57
  • My entire code: `var reg = /^\d{2}F/; const parentsWithNoMatches = [...document.querySelectorAll('.w-50-ns w-100 ph1')] .filter(parent => [...parent.querySelectorAll('.f6 fw7 silver')] .every(child => !child.textContent.match(reg)) ); for (int j=0; j – Lee Cheung Jun 29 '19 at 23:57
  • `int j` is invalid syntax - use `let` instead (or, preferably, use an array method like `forEach`) – CertainPerformance Jun 29 '19 at 23:58
  • Like I said in an above comment, `he .w-50-ns w-100 ph1 selector string will select children which have a tag name of ph1, which have a parent of a tag name of w-100, which have a parent with a class of w-50. You don't want the descendant selector here, if you want to select the elements in the picture, prefix all the class names with ., not with a space ` – CertainPerformance Jun 29 '19 at 23:58
  • I finally did it. Holy shit. I learned something new today. It's my 3rd day with javascript. thank you! – Lee Cheung Jun 29 '19 at 23:59