Задать вопрос
Ответы пользователя по тегу JavaScript
  • Как сделать фильтрацию результатов по поиску?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelector('#filter-input').addEventListener('input', e => {
      const val = e.target.value.toLowerCase();
    
      container.querySelectorAll('.title').forEach(n => {
        n.closest('.card').style.display = n.innerText.toLowerCase().includes(val)
          ? 'block'
          : 'none';
      });
    });

    или

    document.getElementById('filter-input').oninput = function() {
      const val = this.value.toLowerCase();
    
      for (const n of container.getElementsByClassName('title')) {
        let card = n;
        while (!(card = card.parentNode).classList.contains('card')) ;
        card.hidden = n.textContent.toLowerCase().indexOf(val) === -1;
      }
    };
    Ответ написан
    1 комментарий
  • Как динамично сформировать объект?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const obj = Object.fromEntries(arr.map((n, i) => [ `answer${i + 1}`, n ]));

    или

    const obj = arr.reduce((acc, n, i) => (acc['answer' + ++i] = n, acc), {});

    или

    const obj = {};
    for (const [ i, n ] of arr.entries()) {
      obj['answer'.concat(-~i)] = n;
    }
    Ответ написан
    5 комментариев
  • Как проверить регистр первой буквы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str[0] === str[0].toUpperCase()

    или

    /^[A-Z]/.test(str)

    или

    (c => 64 < c && c < 91)(str.charCodeAt(0))

    или

    'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.includes(str.at(0))

    Но что если там вообще не буква?
    Если такое может быть, то...
    ...ни хрена тут больше не скажу, тщательнее надо было вопрос продумывать.
    Ответ написан
    Комментировать
  • Как поменять класс, если выбран checkbox?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('.filter').change(({ target: t }) => {
      $(`[name="${$(t).closest('.button').data('size')}"]`)
        .closest('.product-box')
        .toggleClass('hidden', !t.checked);
    }).find(':checked').change();

    Или, к чёрту jquery:

    const filter = document.querySelector('.filter');
    
    filter.addEventListener('change', ({ target: t }) => {
      const size = t.closest('.button').dataset.size;
      document.querySelectorAll(`[name="${size}"]`).forEach(n => {
        n.closest('.product-box').classList.toggle('hidden', !t.checked);
      });
    });
    
    filter.querySelectorAll(':checked').forEach(n => {
      n.dispatchEvent(new Event('change', { bubbles: true }));
    });
    Ответ написан
    1 комментарий
  • Как валидировать пароль?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Складываем в массив описания проверок, которым должен быть подвергнут пароль - это будут объекты, состоящие из функции, проверяющей соответствие пароля одному конкретному условию, и сообщения, демонстрируемого пользователю в случае, если проверка прошла неудачно.

    Добавляем элементу с паролем обработчик события input, в котором бежим по массиву проверок, передаём функциям текущий пароль, собираем в массив сообщения о допущенных пользователем ошибках.

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

    Ну и всё, дальше остаётся только вывести результаты.

    <div>
      <input id="password">
    </div>
    <div>
      <div>Сложность пароля: <span id="strength_percent">0</span>%</div>
      <progress id="strength_progress" max="100" value="0"></progress>
    </div>
    <div id="errors"></div>

    const validations = [
      {
        test: val => val.length >= 8,
        message: 'пароль должен содержать хотя бы 8 символов',
      },
      {
        test: val => /[A-ZА-ЯЁ]/.test(val),
        message: 'пароль должен содержать хотя бы 1 большую букву',
      },
      {
        test: val => /[a-zа-яё]/.test(val),
        message: 'пароль должен содержать хотя бы 1 маленькую букву',
      },
      {
        test: val => /[^\s\da-zа-яё]/i.test(val),
        message: 'пароль должен содержать хотя бы 1 спецсимвол (не пробел, букву или цифру)',
      },
      {
        test: val => /\d/.test(val),
        message: 'пароль должен содержать хотя бы 1 цифру',
      },
    ];
    
    document.querySelector('#password').addEventListener('input', e => {
      const errors = validations.reduce((acc, n) => (
        n.test(e.target.value) || acc.push(n.message),
        acc
      ), []);
    
      const strength = (validations.length - errors.length) / validations.length * 100;
    
      document.querySelector('#strength_progress').value = strength;
      document.querySelector('#strength_percent').innerText = strength | 0;
      document.querySelector('#errors').innerHTML = errors
        .map(n => `<p>${n}</p>`)
        .join('');
    });
    Ответ написан
    1 комментарий
  • Как добавить общую обёртку дочерним узлам?

    0xD34F
    @0xD34F Куратор тега JavaScript
    оборачивается не полностью

    Почему так: childNodes представляет собой динамическую коллекцию, т.е., при добавлении или удалении узлов она обновляется без каких-либо действий с вашей стороны. Поэтому, когда вы добавляете в wrapper нулевой узел, он тут же пропадает из item.childNodes, а у оставшихся узлов позиция уменьшается на единицу - тот, что был первым, становится нулевым, второй первым и так далее. Так что когда for...of переходит к следующему узлу, им оказывается не тот, что изначально имел индекс 1, а расположенный за ним. Бывший первый, а теперь нулевой, оказывается пропущен. Аналогичным образом будут пропущены и все последующие узлы, изначально имевшие нечётные индексы.

    Что тут можно сделать:

    Вариант раз - вместо перебора узлов всегда работать с тем, что имеет нулевой индекс:

    for (let n; n = item.firstChild;) {
      wrapper.appendChild(n);
    }

    Два - перебирать childNodes от конца к началу:

    for (let i = item.childNodes.length; i--;) {
      wrapper.prepend(item.childNodes[i]);
    }

    Три - перебирать не childNodes, а массив:

    for (const n of [...item.childNodes]) {
      wrapper.insertBefore(n, null);
    }

    А вообще, нет необходимости работать с каждым узлом индивидуально, метод append может принимать несколько параметров, так что переносим сразу всё:

    document.querySelectorAll('.www').forEach(n => {
      const wrapper = document.createElement('div');
      wrapper.classList.add('red');
      wrapper.append(...n.childNodes);
      n.append(wrapper);
    });

    Или, можно и вовсе узлы не трогать, если перезаписывать разметку:

    for (const n of document.getElementsByClassName('www')) {
      n.innerHTML = `<div class="red">${n.innerHTML}</div>`;
    }
    Ответ написан
    Комментировать
  • Как отсортировать массив DOM-элементов в зависимости от значений атрибута вложенных элементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const sorted = arr
      .map(n => [
        n,
        +new URLSearchParams(n.querySelector('a').href.split('?').pop()).get('value') || Infinity,
      ])
      .sort((a, b) => a[1] - b[1])
      .map(n => n[0]);

    UPD. А точно массив? Если всё-таки сортировать надо элементы внутри их родителя, то

    parentEl.append(...Array
      .from(parentEl.querySelectorAll('a'), n => [
        n.parentNode,
        Number(n.getAttribute('href').match(/(?<=value=)\d+/)) || Infinity,
      ])
      .sort((a, b) => a[1] - b[1])
      .map(n => n[0])
    );
    Ответ написан
    4 комментария
  • Как заменить шесть "function" на одну?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сделать функцию, принимающую input, находящую соответствующий input'у span и обновляющую его содержимое:

    const updateValue = input =>
      input.previousElementSibling.querySelector('.p_value').innerText = input.value;

    У input'ов вырезать инлайновые обработчики, добавить общий класс, например: class="xxx".

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

    document.addEventListener('input', ({ target: t }) => {
      if (t.classList.contains('xxx')) {
        updateValue(t);
      }
    });

    Или назначить обработчик каждому input'у индивидуально:

    document.querySelectorAll('.xxx').forEach(function(n) {
      n.addEventListener('input', this);
    }, e => updateValue(e.target));
    Ответ написан
    4 комментария
  • Как задать класс элементам с одинаковыми порядковыми номерами?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const cols = document.querySelectorAll('.col');
    
    cols.forEach(n => {
      n.addEventListener('mouseover', onHover);
      n.addEventListener('mouseout', onHover);
    });
    
    function onHover(e) {
      const index = [...this.children].findIndex(n => n.contains(e.target));
      if (index !== -1) {
        const t = e.type === 'mouseover';
        cols.forEach(n => n.children[index].classList.toggle('hovered', t));
      }
    }
    Ответ написан
    Комментировать
  • Как можно отсортировать объект или map, чтобы после преобразовать в массив?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не надо пытаться заниматься ерундой, сортируют массивы, а не объекты.

    Object
      .entries(arr.reduce((acc, n) => (acc[n] = (acc[n] ?? 0) + 1, acc), {}))
      .sort((a, b) => b[1] - a[1])
      .forEach(n => console.log(n.join(': ')));
    Ответ написан
    Комментировать
  • Как пронумеровать ссылки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    О каких ссылках идёт речь:

    const links = document.querySelectorAll('.nav-about a');

    "Нумеруем":

    links.forEach((n, i) => n.attributes.href.value += i + 1);
    
    // или
    
    for (const [ i, n ] of links.entries()) {
      n.setAttribute('href', n.getAttribute('href').concat(-~i));
    }
    
    // или
    
    for (let i = 0; i < links.length;) {
      links[i].href = links[i].href.replace(/.*(#.*)/, `$1${++i}`);
    }
    Ответ написан
    1 комментарий
  • Как в select выставить первое значение по событию?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('button').click(() => $('select').prop('selectedIndex', 0));

    или, к чёрту jquery:

    document.querySelector('button').addEventListener('click', () => {
      document.querySelectorAll('select').forEach(n => {
        // Какие тут есть варианты:
    
        // 1. Установить индекс выбранного option'а
        n.selectedIndex = 0;
    
        // 2. Установить select'у значение option'а, который должен быть выбран
        //    (чтобы заработало, надо будет добавить value="" option'ам)
        n.value = '';
    
        // 3. Назначить true свойству selected того option'а, на который надо переключиться
        n[0].selected = true;
        // или
        // n.options[0].selected = true;
        // n.children[0].selected = true;
        // n.firstElementChild.selected = true;
        // n.querySelector('option').selected = true;
      });
    });
    Ответ написан
    Комментировать
  • Как объединить массив массивов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Массивы сложить в массив (const arrs = [ arr1, arr2 ];), дальше есть варианты:

    const result = arrs[0].map((_, i) => arrs.flatMap(arr => arr[i]));

    или

    const result = arrs.reduce((acc, arr) => (
      arr.forEach((n, i) => (acc[i] ??= []).push(...n)),
      acc
    ), []);

    или

    const result = [];
    
    for (const arr of arrs) {
      for (const [ i, n ] of arr.entries()) {
        if (!result[i]) {
          result[i] = [];
        }
    
        for (const m of n) {
          result[i][result[i].length] = m;
        }
      }
    }

    или

    function* zip(data, defaultValue = null) {
      const iterators = Array.from(data, n => n[Symbol.iterator]());
    
      for (let doneAll = false; doneAll = !doneAll;) {
        const values = [];
    
        for (const n of iterators) {
          const { value, done } = n.next();
          values.push(done ? defaultValue : value);
          doneAll &&= done;
        }
    
        if (!doneAll) {
          yield values;
        }
      }
    }
    
    const result = Array.from(zip(arrs), n => n.flat());
    Ответ написан
    1 комментарий
  • Как можно менять у элемента атрибут приоритета при drag'n'drop?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавить в обработчик dragend:

    box.querySelectorAll('.item').forEach((n, i) => n.dataset.priority = -~i);
    
    // или
    
    for (const [ i, n ] of box.querySelectorAll('.item').entries()) {
      n.setAttribute('data-priority', i + 1);
    }
    
    // или
    
    for (let i = box.children.length; i;) {
      const attr = document.createAttribute('data-priority');
      attr.value = i;
      box.children[--i].attributes.setNamedItem(attr);
    }
    
    // или
    
    (function next(i, n) {
      n && next(n.attributes['data-priority'].value = ++i, n.nextElementSibling);
    })(0, box.firstElementChild);
    Ответ написан
    Комментировать
  • Как вывести длину самого большого вложенного массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    где ошибка?

    Скобки пересчитайте. Фигурные. Сколько закрывающих, сколько открывающих.

    Ну и конечно не надо никаких циклов в явном виде:

    const maxlen = Math.max(...arr.map(n => n.length));
    
    // или
    
    const maxlen = arr.reduce((max, { length: n }) => max > n ? max : n, -Infinity);
    Ответ написан
    Комментировать
  • Как в ссылки добавить значения title?

    0xD34F
    @0xD34F Куратор тега JavaScript
    fetch('https://gorest.co.in/public/v1/posts')
      .then(r => r.json())
      .then(r => {
    
       // собираем разметку
        document.body.insertAdjacentHTML('beforeend', `
          <ul>${r.data.map(n => `
            <li>
              <a>${n.title}</a>
            </li>`).join('')}
          </ul>
        `);
    
        // или, создаём элементы напрямую
        const ul = document.createElement('ul');
        ul.append(...r.data.map(n => {
          const li = document.createElement('li');
          const a = document.createElement('a');
          a.textContent = n.title;
          li.append(a);
          return li;
        }));
        document.body.append(ul);
      });
    Ответ написан
    1 комментарий
  • Как узнать что экземпляр конкретного класса а не его прародителя?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Получаем тип данных (конструктор или само значение, если оно nullish):

    const type = x => x == null ? x : x.constructor;
    
    type() === undefined // true
    type(null) === null // true
    type(/./) === RegExp // true
    type(187) === Number // true
    type(type) === Function // true

    Получаем имя типа:

    const typename = x => x?.constructor.name ?? `${x}`;
    
    typename() // 'undefined'
    typename(null) // 'null'
    typename(false) // 'Boolean'
    typename('hello, world!!') // 'String'
    typename({}) // 'Object'
    typename([]) // 'Array'
    typename(document.body) // 'HTMLBodyElement'
    typename(document.getElementsByClassName('xxx')) // 'HTMLCollection'
    typename(new class XXX {}) // 'XXX'
    typename((c => new class YYY extends c {})(class XXX {})) // 'YYY'
    typename(typename) // 'Function'
    Ответ написан
    Комментировать
  • Как найти элементы, встречающиеся только в одном из двух массивов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Уникализируем массивы; объединяем в один; перебираем, отмечая, встречался ли текущий элемент ранее - если элемент встречен впервые, будет false, повторно (т.е., представлен в более чем одном из исходных массивов) будет true; хватаем элементы, которые false:

    const diff = (...arrs) => Array
      .from(arrs
        .flatMap(arr => [...new Set(arr)])
        .reduce((acc, n) => acc.set(n, acc.has(n)), new Map))
      .reduce((acc, n) => (n[1] || acc.push(n[0]), acc), []);

    Или, собираем Map, где ключами будут элементы вложенных массивов, а значениями множества вложенных массивов, где присутствует данный элемент. Получаем те ключи, где размер множества равен единице:

    const diff = (...arrs) => Array
      .from(arrs.reduce((acc, arr) => (
        arr.forEach(n => acc.set(n, acc.get(n) ?? new Set).get(n).add(arr)),
        acc
      ), new Map))
      .reduce((acc, n) => (n[1].size === 1 && acc.push(n[0]), acc), []);

    Или, никаких Map и Set - проверяем, что элемент вложенного массива отсутствует во всех других вложенных массивах и в результирующем массиве:

    const diff = (...arrs) =>
      arrs.reduce((acc, arr) => (
        arr.forEach(n =>
          arrs.every(m => m === arr || !m.includes(n)) &&
          !acc.includes(n) &&
          acc.push(n)
        ),
        acc
      ), []);
    Ответ написан
    1 комментарий
  • Как заполнить TextArea через JS (калькулятор)?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelector('.calc_container').addEventListener('input', e => {
      const block = e.target.closest('.calc_block');
      const price = +block.querySelector('.price span').innerText;
      const count = +e.target.value;
      block.querySelector('.summ span').innerText = price * count;
    
      const orderData = Array
        .from(e.currentTarget.querySelectorAll('.calc_block'), n => ({
          name: n.querySelector('label').innerText,
          count: +n.querySelector('.count').value,
          sum: +n.querySelector('.summ span').innerText,
        }))
        .filter(n => n.count);
    
      document.querySelector('.total_block span').innerText = orderData
        .reduce((acc, n) => acc + n.sum, 0);
    
      document.querySelector('textarea').value = orderData
        .map(n => `Название: ${n.name} | Количество: ${n.count}`)
        .join('\n');
    });
    Ответ написан
  • Как двумерный массив порезать на куски и превратить строки в столбцы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const chunkedAndTransposed = ([ headers, ...arr ], chunkSize) =>
      arr.reduce((acc, n, i) => (
        (i % chunkSize) || acc.push(headers.map(m => [ m ])),
        n.forEach((m, j) => acc.at(-1)[j].push(m)),
        acc
      ), []);
    
    const result = chunkedAndTransposed(arr, 2);

    или, если на последний кусок данных не хватает, а размеры вложенных массивов должны быть одинаковыми, можно добавить null'ов или чего-нибудь ещё:

    const chunkedAndTransposed = (arr, chunkSize, defautlValue = null) =>
      Array.from({ length: Math.ceil((arr.length - 1) / chunkSize) }, (_, iChunk) =>
        Array.from({ length: arr[0].length }, (_, iCol) =>
          Array.from({ length: chunkSize + 1 }, (_, iRow) =>
            iRow ? arr[iChunk * chunkSize + iRow]?.[iCol] ?? defautlValue : arr[0][iCol]
          )
        )
      );
    
    const result = chunkedAndTransposed(arr, 5);
    Ответ написан
    4 комментария