Как найти элемент внутри другого элемента js

Alright, I’ve dabbled in JavaScript before, but the most useful thing I’ve written is a CSS style-switcher. So I’m somewhat new to this. Let’s say I have HTML code like this:

<div id="foo">
    <div class="bar">
        Hello world!
    </div>
</div>

How would I change Hello world! to Goodbye world!?

I know how document.getElementsByClassName and document.getElementById work, but I would like to get more specific. Sorry if this has been asked before.

Jakub Muda's user avatar

Jakub Muda

5,86010 gold badges37 silver badges56 bronze badges

asked Oct 19, 2011 at 0:45

Tanner Babcock's user avatar

Tanner BabcockTanner Babcock

3,1626 gold badges20 silver badges23 bronze badges

Well, first you need to select the elements with a function like getElementById.

var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];

getElementById only returns one node, but getElementsByClassName returns a node list. Since there is only one element with that class name (as far as I can tell), you can just get the first one (that’s what the [0] is for—it’s just like an array).

Then, you can change the html with .textContent.

targetDiv.textContent = "Goodbye world!";
var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];
targetDiv.textContent = "Goodbye world!";
<div id="foo">
    <div class="bar">
        Hello world!
    </div>
</div>

answered Oct 19, 2011 at 0:47

Joseph Marikle's user avatar

Joseph MarikleJoseph Marikle

75.9k17 gold badges111 silver badges129 bronze badges

4

You can do it like this:

var list = document.getElementById("foo").getElementsByClassName("bar");
if (list && list.length > 0) {
    list[0].innerHTML = "Goodbye world!";
}

or, if you want to do it with with less error checking and more brevity, it can be done in one line like this:

document.getElementById("foo").getElementsByClassName("bar")[0].innerHTML = "Goodbye world!";

In explanation:

  1. You get the element with id="foo".
  2. You then find the objects that are contained within that object that have class="bar".
  3. That returns an array-like nodeList, so you reference the first item in that nodeList
  4. You can then set the innerHTML of that item to change its contents.

Caveats: some older browsers don’t support getElementsByClassName (e.g. older versions of IE). That function can be shimmed into place if missing.


This is where I recommend using a library that has built-in CSS3 selector support rather than worrying about browser compatibility yourself (let someone else do all the work). If you want just a library to do that, then Sizzle will work great. In Sizzle, this would be be done like this:

Sizzle("#foo .bar")[0].innerHTML = "Goodbye world!";

jQuery has the Sizzle library built-in and in jQuery, this would be:

$("#foo .bar").html("Goodbye world!");

answered Oct 19, 2011 at 0:46

jfriend00's user avatar

jfriend00jfriend00

676k94 gold badges966 silver badges963 bronze badges

1

If this needs to work in IE 7 or lower you need to remember that getElementsByClassName does not exist in all browsers. Because of this you can create your own getElementsByClassName or you can try this.

var fooDiv = document.getElementById("foo");

for (var i = 0, childNode; i <= fooDiv.childNodes.length; i ++) {
    childNode = fooDiv.childNodes[i];
    if (/bar/.test(childNode.className)) {
        childNode.innerHTML = "Goodbye world!";
    }
}

user113716's user avatar

user113716

317k63 gold badges449 silver badges440 bronze badges

answered Oct 19, 2011 at 0:53

John Hartsock's user avatar

John HartsockJohn Hartsock

84.9k23 gold badges131 silver badges146 bronze badges

10

The easiest way to do so is:

function findChild(idOfElement, idOfChild){
  let element = document.getElementById(idOfElement);
  return element.querySelector('[id=' + idOfChild + ']');
}

or better readable:

findChild = (idOfElement, idOfChild) => {
    let element = document.getElementById(idOfElement);
    return element.querySelector(`[id=${idOfChild}]`);
}

Alex Nolasco's user avatar

Alex Nolasco

18.6k9 gold badges86 silver badges81 bronze badges

answered Oct 27, 2017 at 22:47

Benjamin Werner's user avatar

1

We can also make use of CSS selectors with querySelector

var targetDiv = document.querySelector('#foo .bar');
targetDiv.textContent = "Goodbye world!";

answered Mar 2, 2022 at 18:43

rajesh kumar's user avatar

rajesh kumarrajesh kumar

1,54816 silver badges14 bronze badges

you can use getElementById or getElementsByClassName on DOM Elements too. and not just the document

var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];
targetDiv.textContent = "Goodbye world!";
<div id="foo">
    <div class="bar">
        Hello world!
    </div>
</div>

Abilogos's user avatar

Abilogos

4,6472 gold badges19 silver badges39 bronze badges

answered Nov 15, 2021 at 21:33

Jhonny SAN's user avatar

1

Recursive function :

function getElementInsideElement(baseElement, wantedElementID) {
    var elementToReturn;
    for (var i = 0; i < baseElement.childNodes.length; i++) {
        elementToReturn = baseElement.childNodes[i];
        if (elementToReturn.id == wantedElementID) {
            return elementToReturn;
        } else {
            return getElementInsideElement(elementToReturn, wantedElementID);
        }
    }
}

answered Oct 18, 2015 at 13:17

Avi Shimshilashvili's user avatar

1

You should not used document.getElementByID because its work only for client side controls which ids are fixed . You should use jquery instead like below example.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>                                                                                                             
<div id="foo">
   <div class="bar"> 
          Hello world!
     </div>
</div>

use this :

$("[id^='foo']").find("[class^='bar']")

// do not forget to add script tags as above

if you want any remove edit any operation then just add “.” behind and do the operations

Scott Marcus's user avatar

Scott Marcus

63.3k6 gold badges48 silver badges68 bronze badges

answered Aug 1, 2015 at 18:22

hardik akbari's user avatar

2

Пусть у нас есть некоторый элемент родитель,
а внутри него другие элементы:

<div id="parent">
<div class="child">text</div>
<div class="child">text</div>
<div class="child">text</div>
</div>

Пусть ссылка на родитель уже получена в переменную:

let parent = document.querySelector('#parent');

В таком случае, при необходимости мы можем
выполнить поиск по селектору внутри этого
родителя, а не по всему документу. Для этого
метод для поиска нужно применить не к document,
а к переменной, содержащей нашего родителя.

Давайте для примера найдем внутри нашего
родителя элементы с классом child:

let elems = parent.querySelectorAll('.child');

Дан элемент #parent:

<div id="parent">
<p class="www">text</p>
<p class="www">text</p>
<p class="www">text</p>
<p class="ggg">text</p>
<p class="ggg">text</p>
<p class="ggg">text</p>
</div>

let parent = document.querySelector('#parent');

Найдите внутри родителя элементы с классом
www и запишите их в переменную elems1.
Затем найдите внутри родителя элементы с
классом ggg и запишите их в переменную
elems2.

В этой статье мы изучим методы JavaScript для поиска элементов в HTML-документе: querySelector, querySelectorAll, getElementById и другие. Кроме них рассмотрим ещё следующие: matches, contains и closest. Первые два из них могут быть полезны для выполнения различных проверок, а третий использоваться, когда нужно получить родительский элемент по CSS-селектору.

Методы для выбора HTML-элементов

Работа с веб-страницей так или иначе связана с манипулированием HTML-элементами. Но перед тем, как над ними выполнить некоторые действия (например, добавить стили), их сначала нужно получить.

Выбор элементов в основном выполняется с помощью этих методов:

  • querySelector;
  • querySelectorAll.

Они позволяют выполнить поиск HTML-элементов по CSS-селектору. При этом querySelector выбирает один элемент, а querySelectorAll – все.

Кроме них имеются ещё:

  • getElementById;
  • getElementsByClassName;
  • getElementsByTagName;
  • getElementsByName.

Но они сейчас применяются довольно редко. В основном используется либо querySelector, либо querySelectorAll.

querySelectorAll

Метод querySelectorAll применяется для выбора всех HTML-элементов, подходящих под указанный CSS-селектор. Он позволяет искать элементы как по всей странице, так и внутри определённого элемента:

// выберем элементы по классу item во всем документе
const items = document.querySelectorAll('.item');
// выберем .btn внутри #slider
const buttons = document.querySelector('#slider').querySelectorAll('.btn');

Здесь на первой строчке мы нашли все элементы с классом item. На следующей строчке мы сначала выбрали элемент с id="slider", а затем в нём все HTML-элементы с классом btn.

Метод querySelectorAll как вы уже догадались принимает в качестве аргумента CSS-селектор в формате строки, который соответственно и определяет искомые элементы. В качестве результата querySelectorAll возвращает объект класса NodeList. Он содержит все найденные элементы:

Выбор HTML-элементов с помощью метода querySelectorAll в JavaScript

Полученный набор представляет собой статическую коллекцию HTML-элементов. Статической она называется потому, что она не изменяется. Например, вы удалили элемент из HTML-документа, а в ней как был этот элемент, так он и остался. Чтобы обновить набор, querySelectorAll нужно вызвать заново:

Статический набор HTML-элементов, выбранный с помощью querySelectorAll в JavaScript

Узнать количество найденных элементов можно с помощью свойства length:

// выберем элементы с атрибутом type="submit"
const submits = document.querySelectorAll('[type="submit"]');
// получим количество найденных элементов
const countSubmits = submits.length;

Обращение к определённому HTML-элементу коллекции выполняется также как к элементу массива, то есть по индексу. Индексы начинаются с 0:

// получим первый элемент
const elFirst = submits[0];
// получим второй элемент
const elSecond = submits[1];

Здесь в качестве результата мы получаем HTML-элемент или undefined, если элемента с таким индексом в наборе NodeList нет.

Перебор коллекции HTML-элементов

Перебор NodeList обычно осуществляется с помощью forEach:

// получим все <p> на странице
const elsP = document.querySelectorAll('p');
// переберём выбранные элементы
elsP.forEach((el) => {
  // установим каждому элементу background-color="yellow"
  el.style.backgroundColor = 'yellow';
});

Также перебрать набор выбранных элементов можно с помощью цикла for или for...of:

// получим все элементы p на странице
const elsP = document.querySelectorAll('p');
// for
for (let i = 0, length = elsP.length; i < length; i++) {
  elsP[i].style.backgroundColor = 'yellow';
}
// for...of
for (let el of elsP) {
  el.style.backgroundColor = 'yellow';
}

querySelector

Метод querySelector также как и querySelectorAll выполняет поиск по CSS-селектору. Но в отличие от него, он ищет только один HTML-элемент:

// ищем #title во всём документе
const elTitle = document.querySelector('#title');
// ищем footer в <body>
const elFooter = document.body.querySelector('footer');

На первой строчке мы выбираем HTML-элемент, имеющий в качестве id значение title. На второй мы ищем в <body> HTML-элемент по тегу footer.

В качестве результата этот метод возвращает найденный HTML-элемент или null, если он не был найден.

querySelector всегда возвращает один HTML-элемент, даже если под указанный CSS-селектор подходят несколько:

<ul id="list">
  <li>First</li>
  <li>Second</li>
  <li>Third</li>
</ul>
<script>
  // выберем <li>, расположенный в #list
  const elFirst = document.querySelector('#list > li');
  elFirst.style.backgroundColor = 'yellow';
</script>

Задачу, которую решает querySelector можно выполнить через querySelectorAll:

const elFirst = document.querySelectorAll('#list > li')[0];

Но querySelector в отличие от querySelectorAll делает это намного быстрее, да и писать так проще. То есть querySelectorAll не возвращает как querySelector сразу же первый найденный элемент. Он сначала ищет все элементы, и только после того, как он это сделает, мы можем уже обратиться к первому HTML-элементу в этой коллекции.

Обычно перед тем, как выполнить какие-то действия с найденным HTML-элементом необходимо сначала проверить, а действительно ли он был найден:

const elModal = document.querySelector('.modal');
// если элемент .modal найден, то ...
if (elModal) {
  // переключим у elModal класс show
  elModal.classList.toggle('show');
}

Здесь мы сначала проверили существования HTML-элемента, и только потом выполнили над ним некоторые действия.

Методы getElement(s)By* для выбора HTML-элементов

Здесь мы рассмотрим методы, которые сейчас применяются довольно редко для поиска HTML-элементов. Но в некоторых случаях они могут быть очень полезны. Это:

  • getElementById – получает один элемент по id;
  • getElementsByClassName – позволяет найти все элементы с указанным классом или классами;
  • getElementsByTagName – выбирает элементы по тегу;
  • getElementsByName – получает все элементы с указанным значением атрибута name.

1. Метод getElementById позволяет найти HTML-элемент на странице по значению id:

<div id="comments">...</div>
...
<script>
  // получим HTMLElement и сохраним его в переменную elComments
  const elComments = document.getElementById('comments');
</script>

В качестве результата getElementById возвращает объект класса HTMLElement или значение null, если элемент не был найден. Этот метод имеется только у объекта document.

Указывать значение id необходимо с учётом регистра. Так например, document.getElementById('aside') и document.getElementById('ASIDE') ищут элементы с разным id.

Обратите внимание, что в соответствии со стандартом в документе не может быть несколько тегов с одинаковым id, так как значение идентификатора на странице должно быть уникальным.

Тем не менее, если вы допустили ошибку и в документе существуют несколько элементов с одинаковым id, то метод getElementById более вероятно вернёт первый элемент, который он встретит в DOM. Но на это полагаться нельзя, так как такое поведение не прописано в стандарте.

То, что делает getElementById можно очень просто решить посредством querySelector:

// получим элемент #title
const elTitle = document.getElementById('title');
// получим элемента #title, используя querySelector
const elTitleSame = document.querySelector('#nav');

Кстати, оба этих метода возвращают в качестве результата один и тот же результат. Это либо HTML-элемент (экземпляр класса HTMLElement) или null, если элемент не найден.

2. Метод getElementsByClassName позволяет найти все элементы с заданным классом или классами. Его можно применить для поиска элементов как во всём документе, так и внутри указанного. В первом случае его нужно будет вызывать как метод объекта document, а во втором – как метод соответствующего HTML-элемента:

// найдем элементы с классом control в документе
const elsControl = document.getElementsByClassName('control');
// выберем элементы внутри другого элемента, в данном случае внутри формы с id="myform"
const elsFormControl = document.forms.myform.getElementsByClassName('form-control');

В качестве результата он возвращает живую HTML-коллекцию найденных элементов. Чем живая коллекция отличается от статической мы рассмотрим ниже.

Здесь мы сохранили найденные элементы в переменные elsControl и elsFormControl. В первой переменной будет находиться HTMLCollection, содержащая элементы с классом control. Во второй – набор элементов с классом form-control, находящиеся в форме с id="myform". Для получения этой формы мы использовали document.forms.myform.

Метод getElementsByClassName позволяет искать элементы не только по одному классу, но и сразу по нескольким, которые должны присутствовать у элемента:

// выберем элементы .btn.btn-danger
const elsBtn = document.getElementsByClassName('btn btn-danger');

На querySelectorAll этот пример решается так:

const elsBtn = document.querySelectorAll('.btn.btn-danger');

3. Метод getElementsByTagName предназначен для получения коллекции элементов по имени тега:

// найдем все <a> в документе
const anchors = document.getElementsByTagName('a');
// найдем все >li> внутри #list
const elsLi = document.getElementById('list').getElementsByTagName('li');

На первой строчке мы выбрали все <a> в документе и присвоили полученную HTMLCollection переменной anchors. На второй – мы сначала получили #list, а затем в нём нашли все <li>.

Задачу по выбору элементов внутри другого элемента с помощью querySelectorAll выполняется намного проще:

const elsLi = document.querySelectorAll('#list li');

Для выбора всех элементов можно использовать символ *:

// выберем все элементы в <body>
const els = document.body.getElementsByTagName('*');

4. В JavaScript getElementsByName можно использовать для выбора элементов, имеющих определенное значение атрибута name:

// получим все элементы с name="phone"
const elsPhone = document.getElementsByName('phone');

Через querySelectorAll это выполняется так:

const elsPhone = document.querySelectorAll('[name="phone"]');

getElementsBy* и живые HTML-коллекции

В JavaScript getElementsByTagName, getElementsByClassName и getElementsByName в отличие от других методов (например, querySelectorAll) возвращают живую коллекцию HTML-элементов (на английском live HTMLCollection). То есть коллекцию содержимое которой автоматически обновляется при изменении DOM. Для наглядности рассмотрим следующий пример.

Например, на странице изначально имеется два <li>. Выберем их с помощью getElementsByTagName и сохраним полученную HTMLCollection в переменную els. Теперь с помощью els мы можем получить эту коллекцию. Сейчас в ней два <li>. Затем через 5 секунд, используя setTimeout добавим ещё один <li>. Если сейчас мы обратимся к переменной els, то увидим, что в ней уже находятся три <li>:

<ul>
  <li>One</li>
  <li>Two</li>
</ul>

<script>
// получим живую коллекцию <li>
const els = document.getElementsByTagName('li');
// выведем количество <li> в консоль
console.log(`Количество <li>: ${els.length}`); // 2
// через 5 секунд добавим ещё один <li>
setTimeout(() => {
  // вставим на страницу новый <li>
  document.querySelector('ul').insertAdjacentHTML('beforeend', '<li>Three</li>');
// выведем количество <li> в консоль
  console.log(`Количество <li>: ${els.length}`); // 3
}, 5000);
</script>

Живая коллекция элементов, полученная с помощью getElementsByTagName, обновляется при изменении DOM

Как вы видите, здесь полученная коллекция является живой, то есть она может автоматически измениться. В ней сначала было два <li>. Но после того, как мы на страницу добавили ещё один подходящий элемент, в ней их стало уже три.

Если в коде приведённом выше заменить выбор элементов на querySelectorAll, то мы увидим, что в ней находится статическая (не живая) коллекция элементов:

// получим статическую коллекцию
const els = document.querySelectorAll('li'); <li>

Статическая коллекция элементов, полученная с помощью querySelectorAll, не обновляется при изменении DOM

Как вы видите количество элементов в коллекции не изменилось. Чтобы после изменения DOM получить актуальную коллекцию элементов, их нужно просто выбрать заново посредством querySelectorAll:

<ul>
  <li>One</li>
  <li>Two</li>
</ul>

<script>
// получим статическую коллекцию <li>
let els = document.querySelectorAll('li');
// выведем количество <li> в консоль
console.log(`Количество <li>: ${els.length}`); // 2
// через 5 секунд добавим ещё один <li>
setTimeout(() => {
  // вставим на страницу новый <li>
  document.querySelector('ul').insertAdjacentHTML('beforeend', '<li>Three</li>');
  // получим заново статическую коллекцию <li>
  els = document.querySelectorAll('li');
  // выведем количество <li> в консоль
  console.log(`Количество <li>: ${els.length}`); // 3
}, 5000);
</script>

Таким образом в JavaScript насчитывается 6 основных методов для выбора HTML-элементов на странице. По чему они ищут и что они возвращают приведено на следующем рисунке:

Методы JavaScript для выбора HTML-элементов на странице, приведены сведения по признаку на основании которого они ищут и тому что возвращают в качестве результата

Экземпляры класса HTMLCollection не имеют в прототипе метод forEach. Поэтому если вы хотите использовать этот метод для перебора такой коллекции, её необходимо преобразовать в массив:

const items = document.getElementsByClassName('item');
[...items].forEach((el) => {
  console.log(el);
});

matches, closest и contains

В JavaScript имеются очень полезные методы:

  • matches – позволяет проверить соответствует ли HTML-элемент указанному CSS-селектору;
  • closest – позволяет найти для HTML-элемента его ближайшего предка, подходящего под указанный CSS-селектор (поиск начинается с самого элемента);
  • contains – позволяет проверить содержит ли данный узел другой в качестве потомка (проверка начинается с самого этого узла).

1. Метод matches ничего не выбирает, но он является очень полезным, так как позволяет проверить HTML-элемент на соответствие CSS-селектору. Он возвращает true, если элемент ему соответствует, иначе false.

// выберем HTML элемент, имеющий атрибут data-target="slider"
const elSlider = document.querySelector('[data-target="slider"]');
// проверим соответствует ли он CSS селектору 'div'
const result = element.matches('div');

Пример, в котором выберем все <li>, расположенные внутри #questions, а затем удалим те из них, которые соответствуют селектору .answered:

// выберем все <li> в #questions
const els = document.querySelectorAll('#questions > li');
// переберём выбранные элементы
els.forEach((el) => {
  // если элемент соответствует селектору .answered, то ...
  if (el.matches('.answered')) {
    // удалим элемент
    el.remove();
  }
});

В этом примере проверим каждый <li> на соответствие селектору active. Выведем в консоль каждый такой элемент:

<ul>
  <li>One</li>
  <li class="active">Two</li>
  <li>Three</li>
</ul>

<script>
  document.querySelectorAll('li').forEach((el) => {
    if (el.matches('.active')) {
      console.log(el);
    }
  });
  // li.active
</script>

Ранее, в «старых» браузерах данный метод имел название matchesSelector, а также поддерживался с использованием префиксов. Если вам нужна поддержка таких браузеров, то можно использовать следующий полифилл:

if (!Element.prototype.matches) {
  Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector;
}

2. Метод closest очень часто используется в коде. Он позволяет найти ближайшего предка, подходящего под указанный CSS-селектор. При этом поиск начинается с самого элемента, для которого данный метод вызывается. Если этот элемент будет ему соответствовать, то closest вернёт его.

<div class="level-1">
  <div class="level-2">
    <div class="level-3"></div>
  </div>
</div>

<script>
  const el = document.querySelector('.level-3');
  const elAncestor = el.closest('.level-1');
  console.log(elAncestor);
</script>

Здесь мы сначала выбираем HTML-элемент .level-3 и присваиваем его переменной el. Далее мы пытаемся среди предков этого элемента включая его сам найти такой, который отвечает заданному CSS-селектору, в данном случае .level-1.

Начинается поиск всегда с самого этого элемента. В данном случае он не подходит под указанный селектор. Следовательно, этот метод переходит к его родителю. Он тоже не отвечает этому CSS-селектору. Значит, closest переходит дальше, то есть уже к его родителю. Этот элемент подходит под указанный селектор. Поэтому поиск прекращается и этот метод возвращает его в качестве результата.

Метод closest возвращает null, когда он дошёл бы конца иерархии и не нашёл элемент отвечающий указанному селектору. То есть, если такого элемента нет среди предков.

В этом примере найдем с помощью closest для .active его ближайшего родителя, отвечающего CSS-селектору #list > li:

<ul id="list">
  <li>One</li>
  <li>
    Two
    <ul>
      <li>Four</li>
      <li class="active">Five</li>
    </ul>
  </li>
  <li>Three</li>
</ul>
<script>
  const elActive = document.querySelector('.active');
  const elClosest = elActive.closest('#list > li');
  elClosest.style.backgroundColor = 'yellow';
</script>

В JavaScript closest очень часто используется в обработчиках событий. Это связано с тем, чтобы события всплывают и нам нужно, например, узнать кликнул ли пользователь в рамках какого-то элемента:

document.addEventListener('click', (e) => {
  if (e.closest.matches('.btn__action')) {
    // пользователь кликнул внутри .btn__action
  }
});

3. Метод contains позволяет проверить содержит ли некоторый узел другой в качестве потомка. При этом проверка начинается с самого этого узла, для которого этот метод вызывается. Если узел соответствует тому для которого мы вызываем данный метод или является его потомком, то contains в качестве результата возвращает логическое значение true. В противном случае false:

<div id="div-1">
  <div id="div-2">
    <div id="div-3">...</div>
  </div>
</div>
<div id="div-4">...</div>

<script>
  const elDiv1 = document.querySelector('#div-1');
  elDiv1.contains(elDiv1); // true
  const elDiv3 = document.querySelector('#div-3');
  elDiv1.contains(elDiv3); // true
  const elDiv4 = document.querySelector('#div-4');
  elDiv1.contains(elDiv4); // false
</script>

Здесь выражение elDiv1.contains(elDiv1) возвращает true, так как проверка начинается с самого элемента. Это выражение elDiv1.contains(elDiv3) тоже возвращает true, так как elDiv3 находится внутри elDiv1. А вот elDiv1.contains(elDiv4) в качестве результата возвращает false, так как elDiv4 не находится внутри elDiv1.

В этом примере проверим с помощью contains содержит ли <p> другие узлы в качестве потомка:

<h1>Tag b</h1>
<p>This is <b>tag b</b>.</p>

<script>
  const elP = document.querySelector('p');
  const elB = document.querySelector('b');
  const textNode = elB.firstChild;
  const elH1 = document.querySelector('h1');
  elP.contains(elP); // true
  elP.contains(elB); // true
  elP.contains(elH1); // false
  elP.contains(textNode); // true
</script>

Метод contains позволяет проверить является ли потомком не только узел-элемент, но и любой другой узел. Например, узнаем является ли потомком elDiv1 указанный текстовый узел:

const elDiv1 = document.querySelector('#div-1');
const textNode = document.querySelector('#div-3').firstChild;
elDiv1.contains(textNode); // true

Задачи

1. Узнать количество элементов с атрибутом data-toggle="modal" на странице:

const count = document.querySelectorAll('[data-toggle="modal"]').length;
console.log(count);

2. Найти все элементы <a> с классом nav внутри элемента <ul> :

const anchors = document.querySelectorAll('ul.nav a');

3. Получить элемент по id, значение которого равно pagetitle:

var pagetitle = document.querySelector('#pagetitle');

4. Выполнить поиск элемента по классу nav:

var el = document.querySelector('.nav');

5. Найти элемент <h3>, находящийся в теге <div> с классом comments, который в свою очередь расположен в <main>:

var header = document.querySelector('main div.comments h3');

6. Имеется страница. В ней следует выбрать:

  • последний элемент с классом article, расположенный в <main> (решение);
  • все элементы .section, находящиеся в .aside кроме 2 второго (решение);
  • элемент <nav> расположенный после <header> (решение).

The main idea is: I have a list of beverage in a div and I’d like to check if the beverages are out of stock or not, and click the first drink available in stock. It needs to be in JavaScript (without JQuery)

The elements are in this hierarchy:

Main div containing all the drinks: class="ob-menu-items__items"

Each drink will be in a H4 class="ob-menu-item__title"

If the product is out of stock there will be a span class="ob-menu-item__out-of-stock" with the text " - Out of Stock"

So far I try this (and got stuck):

for (var i = 0; i < 7; i++) {
    // iterating over each drink.
    var drink = document.getElementsByClassName("ob-menu-item__title")[i];
    if (document.getElementsByClassName(".ob-menu-item__out-of-stock").parents(drink).length == 1) {
        // There's out of stock text
        // Do nothing and go to the next drink 
    } else {
        //The product is available. Clik the drink and exit the loop
        document.getElementsByClassName("ob-menu-item__title")[i].click();
        break;
    }
} 

Thanks!

Karan's user avatar

Karan

12k3 gold badges24 silver badges40 bronze badges

asked Aug 13, 2020 at 9:21

Hiago Koziel's user avatar

1

Replace your if condition as below and it will work as expected. It will find elements inside drinks which has class ob-menu-item__out-of-stock.

if (drink.getElementsByClassName("ob-menu-item__out-of-stock").length > 0)

Please refer this answer which says .getElementsByClassName("home")[0] should not be used. You can alternatively use .querySelectorAll() like below. Replace getElementsByClassName with querySelectorAll and pass class name with class selector (.). So document.getElementsByClassName("ob-menu-item__title")[i] will be replaced with document.querySelectorAll(".ob-menu-item__title")[i].

To find elements inside selected element you can use element.querySelectorAll which is done inside if with drink.querySelectorAll(".ob-menu-item__out-of-stock").length

for (var i = 0; i < 7; i++) {
    // iterating over each drink.
    var drink = document.querySelectorAll(".ob-menu-item__title")[i];
    if (drink.querySelectorAll(".ob-menu-item__out-of-stock").length > 0) {
        // There's out of stock text
        // Do nothing and go to the next drink 
    } else {
        //The product is available. Clik the drink and exit the loop
        drink.click();
        break;
    }
}

Try it below.

// get all drink
var drinks = document.querySelectorAll(".ob-menu-item__title");
// iterating over each drink.
for (var i = 0; i < drinks.length; i++) {
  let drink = drinks[i];

  if (drink.querySelectorAll(".ob-menu-item__out-of-stock").length > 0) {
  console.log('out of stock. i = ' + i);
    // There's out of stock text
    // Do nothing and go to the next drink 
  } else {
    //The product is available. Clik the drink and exit the loop
    console.log('In stock. i = ' + i);
    drink.click();
    break;
  }
}
<div class='ob-menu-items__items'>
  <h4 class='ob-menu-item__title'>
    item0<span class='ob-menu-item__out-of-stock'> - Out of stock</span>
  </h4>
  <h4 class='ob-menu-item__title'>
    item4<span class='ob-menu-item__out-of-stock'> - Out of stock</span>
  </h4>
  <h4 class='ob-menu-item__title'>
    item2<span class='ob-menu-item__out-of-stock'> - Out of stock</span>
  </h4>
  <h4 class='ob-menu-item__title'>
    item3
  </h4>
  <h4 class='ob-menu-item__title'>
    item4
  </h4>
  <h4 class='ob-menu-item__title'>
    item5
  </h4>
  <h4 class='ob-menu-item__title'>
    item6
  </h4>
</div>

answered Aug 13, 2020 at 9:31

Karan's user avatar

KaranKaran

12k3 gold badges24 silver badges40 bronze badges

for (var i = 0; i < 7; i++) {
    var drink = document.getElementsByClassName("ob-menu-item__title")[i];
    if (document.getElementsByClassName.("ob-menu-item__out-of-stock").parents(drink).length == 1) {
        // There's out of stock text
        // Do nothing and go to the next drink 
    } else {
        //The product is available. Clik the drink and exit the loop
        document.getElementsByClassName("ob-menu-item__title")[i].click();
        break;
    }
}

Karan's user avatar

Karan

12k3 gold badges24 silver badges40 bronze badges

answered Aug 13, 2020 at 9:37

coder404's user avatar

1

The hard-coded 7 in the for loop initialization doesn’t look good. You can just find all the drinks by document.querySelectorAll and then find the one to click by checking for the span in each of them.

ES6 one-liner:

[...document.querySelectorAll('.ob-menu-item__title')]
  .find( drink => !drink.querySelector('.ob-menu-item__out-of-stock') )
  .click()

What it does is: converts the querySelectorAll result into an Array, then uses Array.prototype.find method which returns the first element that satisfied the callback, and the call back in this case returns true if given element doesn’t contain the “out of stock” span.

More “classic” JS:

var firstInStock = Array.from(document.querySelectorAll('.ob-menu-item__title'))
  .find( function(drink){
    if( drink.querySelector('.ob-menu-item__out-of-stock') ){
      return false;
    }
    return true;
  });
firstInStock.click()

Or if you really want a for loop:

var drinks = document.querySelectorAll('.ob-menu-item__title');
for(var i=0; i< drinks.length; i++){
   if( !drink.querySelector('.ob-menu-item__out-of-stock') ){
     drink.click();
     break;
   }
}

answered Aug 13, 2020 at 9:57

pawel's user avatar

pawelpawel

35.4k7 gold badges56 silver badges53 bronze badges

Немного изменил твой HTML

<div class="container">
  <div class="some_class_1">
    <a class="anchor_class" href="#">target text</a>
    <div class="some_class_2">
      <p>spasecial text</p>
    </div>
  </div>

  <div class="some_class_1">
    <a class="anchor_class" href="#">target text</a>
    <div class="some_class_3">
      <p>special text</p>
    </div>
  </div>
</div>

Вот немного костыльный JS, который реализует твою задачу

// Берем общий контейнер с подобными элементами
var cont = document.querySelector('.container');
// Вещаем на него обработчик
cont.addEventListener('click', function(event) {
  // Используем делегирование для определения того, что клик произошел по нужному нам элементу
  var node = event.target.closest('.some_class_1');
  if (!node) return;
  // Нахдоим детей-элементов этого элемента
  var nodeChildrenArr = Array.from(node.children);
  // Проверяем, есть ли среди них тот, у котрого первым потомком идет элемент с содержимым 'special text'
  if (nodeChildrenArr.some(function(elem){
    if (elem.firstElementChild) {
      return elem.firstElementChild.innerHTML == 'special text';  
    }
    return false;
  })) {
    // Если есть такой элемент, то выводим текст ссылки
    console.log(node.querySelector('.anchor_class').innerHTML);
  }
});

Добавить комментарий