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

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('#cityFilter').on('input', function() {
      const value = this.value.toLowerCase();
    
      $('#city-list .city')
        .hide()
        .filter((i, n) => $(n).text().toLowerCase().includes(value))
        .show();
    
      $('#city-list .state')
        .hide()
        .filter((i, n) => $(n).nextUntil('.state').is(':visible'))
        .show();
    });

    или

    document.querySelector('#cityFilter').addEventListener('input', e => {
      const value = e.target.value.toLowerCase();
    
      document.querySelectorAll('#city-list li').forEach(function(n) {
        if (n.matches('.state')) {
          this.splice(0, 2, n, true);
        } else {
          const hide = n.textContent.toLowerCase().indexOf(value) === -1;
          this[1] &&= hide;
          n.classList.toggle('hidden', hide);
          if (!n.nextElementSibling?.matches('.city')) {
            this[0].classList.toggle('hidden', this[1]);
          }
        }
      }, [ null, true ]);
    });
    Ответ написан
    1 комментарий
  • Как назначить класс всем ссылкам в блоке, кроме первой?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelectorAll('.col').forEach(n => {
      n.querySelectorAll('a').forEach((m, i) => m.classList.toggle('d-none', !!i));
    });

    или (если перед первыми ссылками других элементов нет, и сами ссылки ни во что дополнительно не обёрнуты)

    document.querySelectorAll('.col a').forEach(n => {
      n.classList.toggle('d-none', !!n.previousElementSibling);
    });
    Ответ написан
  • Как получить результаты нескольких первых выполненных Promise?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const getFisrtPromises = (promises, count) =>
      new Promise(resolve => {
        const results = [];
    
        const onResolve = result =>
          results.length < count &&
          [ count, promises.length ].includes(results.push(result)) &&
          resolve(results);
    
        promises.forEach(n => n.then(onResolve));
      });
    Ответ написан
    Комментировать
  • Как на Jquery добавлять и удалять идентичные значения (текст) в блок?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const filterSelector = '.js-filter';
    const itemSelector = '.dfth__item';
    const checkboxSelector = '.dfth__check:checked';
    const labelSelector = '.dfth__label';
    const resetSelector = '.dfth__reset';
    const selectedSelector = '.js-type-result';
    const defaultValue = 'ничего не выбрано';

    Вот jquery:

    const $filter = $(filterSelector).change(function() {
      const selected = $(checkboxSelector, this)
        .closest(itemSelector)
        .find(labelSelector)
        .get()
        .map(n => $(n).text())
        .join(', ');
    
      $(selectedSelector, this).text(selected || defaultValue);
    });
    
    $filter.find(resetSelector).click(() => {
      $filter.find(checkboxSelector).prop('checked', false);
      $filter.trigger('change');
    });

    А вот jquery нет:

    const filter = document.querySelector(filterSelector);
    
    filter.addEventListener('change', ({ currentTarget: ct }) => {
      const selected = Array
        .from(
          ct.querySelectorAll(checkboxSelector),
          n => n.closest(itemSelector).querySelector(labelSelector).textContent)
        .join(', ');
    
      ct.querySelector(selectedSelector).textContent = selected || defaultValue;
    });
    
    filter.querySelector(resetSelector).addEventListener('click', () => {
      filter.querySelectorAll(checkboxSelector).forEach(n => n.checked = false);
      filter.dispatchEvent(new Event('change'));
    });
    Ответ написан
    1 комментарий
  • Как проверить что в коллекции map содержатся два одинаковых элемента?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Проверяем факт наличия дубликатов:

    const hasDuplicates = map.size > new Set(Array.from(map, n => n[1].id)).size;

    Смотрим, кто конкретно повторяется:

    const duplicates = Array
      .from([...map].reduce((acc, [ , { id } ]) => acc.set(id, acc.has(id)), new Map))
      .reduce((acc, n) => (n[1] && acc.push(n[0]), acc), []);

    Вычисляем, кто сколько раз представлен в исходных данных:

    const count = Array
      .from(map.values())
      .reduce((acc, { id }) => acc.set(id, -~acc.get(id)), new Map);
    Ответ написан
    2 комментария
  • Как назначать класс активному элементу внутри блока независимо от других блоков?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где элементы находятся, что за элементы, какой класс у них надо переключать:

    const containerSelector = '.block-btn';
    const itemSelector = `${containerSelector} [data-cost]`;
    const activeClass = 'active';

    Какие тут возможны варианты:

    Обработчик клика назначается каждому элементу индивидуально. Перебираем всех соседей (чтобы их получить, надо подняться к контейнеру и внутри него выполнить поиск нужных элементов), переключаем класс в зависимости от равенства текущего и кликнутого элемента:

    const onClick = ({ currentTarget: t }) => t
      .closest(containerSelector)
      .querySelectorAll(itemSelector)
      .forEach(n => n.classList.toggle(activeClass, n === t));
    
    document.querySelectorAll(itemSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });

    Делегированный обработчик клика назначается контейнерам. Проверяем, что кликнут был интересующий нас элемент (пробуем до него подняться от элемента, на котором случилось событие). Если да, ищем внутри контейнера активный элемент, снимаем класс. Кликнутому элементу класс добавляем:

    for (const n of document.querySelectorAll(containerSelector)) {
      n.addEventListener('click', onClick);
    }
    
    function onClick(e) {
      const item = e.target.closest(itemSelector);
      if (item) {
        this.querySelector(`.${activeClass}`)?.classList.remove(activeClass);
        item.classList.add(activeClass);
      }
    }

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

    document.addEventListener('click', ({ target: t }) => t
      .closest(itemSelector)
      ?.closest(containerSelector)
      .querySelectorAll(itemSelector)
      .forEach(n => n.classList.toggle(activeClass, n.contains(t)))
    );
    Ответ написан
    2 комментария
  • Как получить разделитель даты?

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

    const delimiter = str.match(/\D/)[0];
    
    // или
    
    const delimiter = str[str.search(/\D/)];
    
    // или
    
    const [ delimiter ] = str.replace(/^\d+/, '');
    
    // или
    
    const delimiter = Array.prototype.find.call(str, n => Number.isNaN(+n));
    
    // или
    
    const delimiter = [...str].filter(n => !'0123456789'.includes(n)).shift();
    Ответ написан
    Комментировать
  • Как добавить класс всем блокам, которые выводятся после 3го блока?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где элементы находятся, какой класс надо добавить и начиная с какого по счёту элемента:

    const parent = document.querySelector('.container');
    const className = 'green';
    const startFrom = 4;

    Добавляем:

    parent
      .querySelectorAll(`:scope > :nth-child(n + ${startFrom + 1})`)
      .forEach(n => n.classList.add(className));
    
    // или
    
    for (const n of Array.prototype.slice.call(parent.children, startFrom)) {
      n.classList.add(className);
    }
    
    // или
    
    for (let el = parent.children[startFrom]; el; el = el.nextElementSibling) {
      el.classList.add(className);
    }
    
    // или, также удаляем класс (если вдруг есть) у тех, кому он не должен быть добавлен
    
    for (let i = 0; i < parent.children.length; i++) {
      parent.children[i].classList.toggle(className, i >= startFrom);
    }
    Ответ написан
    1 комментарий
  • Как сгенерировать массив только из уникальных чисел определенной длины?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Какие есть способы создания массива:

    • Создавать случайные числа, пока не наберётся сколько надо.
    • Создать массив, состоящий из всех чисел интервала, выдернуть из него сколько надо случайных.
    • Создать массив, состоящий из всех чисел интервала, перемешать его, взять из начала сколько надо.

    Что делать при попытке создать массив с длиной больше указанного интервала:

    • Кидать ошибку.
    • Создавать массив с длиной меньше указанной.

    Вот как-то так:

    function createRandomArr(length, min, max) {
      if (length > max - min + 1) {
        throw 'такого массива быть не может';
      }
    
      const values = new Set;
      for (; values.size < length; values.add(min + Math.random() * (max - min + 1) | 0)) ;
      return [...values];
    }

    const createRandomArr = (length, min, max) => Array
      .from({ length }, function() {
        return this.splice(Math.random() * this.length | 0, 1);
      }, Array.from({ length: max - min + 1 }, (n, i) => i + min))
      .flat();

    function createRandomArr(length, min, max) {
      const arr = Array.from({ length: max - min + 1 }, (n, i) => min + i);
    
      for (let i = arr.length; --i > 0;) {
        const j = Math.random() * (i + 1) | 0;
        [ arr[i], arr[j] ] = [ arr[j], arr[i] ];
      }
    
      return arr.slice(0, length);
    }
    Ответ написан
    Комментировать
  • Как можно сократить запись создания одинаковых элементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Значения собрать в массив: const values = [ id, sum, system, date ];.

    Дальше есть варианты:

    payment.innerHTML = values.map(n => `<td>${n}</td>`).join('');
    
    // или
    
    values.forEach(n => payment.insertCell().textContent = n);
    
    // или
    
    payment.append(...values.map(n => {
      const td = document.createElement('td');
      td.innerText = n;
      return td;
    }));

    Или, то же самое, но с массивом ключей вместо значений:

    - function createPayment({id, sum, system, date}) {
    + function createPayment(data) {

    - const values = [ id, sum, system, date ];
    + const keys = [ 'id', 'sum', 'system', 'date' ];

    - values.forEach(n => payment.insertCell().textContent = n);
    + keys.forEach(n => payment.insertCell().textContent = data[n]);
    Ответ написан
    Комментировать
  • Как рекурсивно обойти древовидный объект?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const getKeys = obj =>
      obj instanceof Object
        ? Object.entries(obj).flatMap(n => [ n[0], ...getKeys(n[1]) ])
        : [];
    Ответ написан
    Комментировать
  • Как оставить в объекте три самых больших числа?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сколько свойств должно быть в объекте: const propsCount = 3;.

    Собираем новый объект:

    const newObj = Object.fromEntries(Object
      .entries(obj)
      .sort((a, b) => a[1] - b[1])
      .slice(-propsCount)
    );

    Удаляем свойства существующего:

    Object
      .entries(obj)
      .sort((a, b) => b[1] - a[1])
      .slice(propsCount)
      .forEach(n => delete obj[n[0]]);
    Ответ написан
    3 комментария
  • Как вырезать текст с определенного символа и до конца цифр?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.match(/(?<=>)\d+/g) ?? []
    
    // или
    
    str.match(/>\d+/g)?.map(n => n.slice(1)) ?? []
    
    // или
    
    Array.from(str.matchAll(/>(\d+)/g), n => n[1])
    Ответ написан
    1 комментарий
  • Как удвоить каждый символ в строке?

    0xD34F
    @0xD34F Куратор тега JavaScript
    ''.concat(...Array.from(str, n => n.repeat(2)))
    // или
    str.replace(/./g, '$&$&')
    // или
    str.replace(/./g, m => Array(3).join(m))
    // или
    str.replace(/(?=.)/g, (m, i) => str[i])
    // или
    [...str].flatMap(n => Array(2).fill(n)).join('')
    // или
    [].map.call(str, n => `${n}${n}`).join``
    // или
    str.split('').reduce((acc, n) => acc + n + n, '')
    Ответ написан
    Комментировать
  • Как сложить и узнать среднее значение объекта?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сложить объекты в массив, и

    const averageAge = arr.reduce((acc, n) => acc + n.age, 0) / arr.length;

    Это если делать просто и ровно то, что спрошено. Но можно решить задачу и в более общем виде - сделаем функцию, вычисляющую среднее передаваемого ей итерируемого объекта:

    function avg(data, key = n => n) {
      const getVal = key instanceof Function ? key : n => n[key];
      let sum = 0;
      let count = 0;
    
      for (const n of data) {
        sum += getVal(n);
        count += 1;
      }
    
      return sum / count;
    }

    В вашем случае применять так: const averageAge = avg(arr, 'age');.

    Другие варианты использования:

    avg(Array(10).keys()) // 4.5
    avg('12345', Number) // 3
    avg(document.images, n => n.width) // сами посмотрите, сколько тут получится
    Ответ написан
    Комментировать
  • Как разбить массив на массивы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    arr.reduce((acc, n, i) => (
      (!i || n === 1) && acc.push([]),
      acc[acc.length - 1].push(n),
      acc
    ), [])
    Ответ написан
    2 комментария
  • Как найти и сделать первую букву заглавной самого короткого слова в массиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Если надо изменить одно слово с минимальной длиной:

    const index = arr.reduce((min, n, i, a) => a[min]?.length <= n.length ? min : i, -1);
    if (index !== -1) {
      arr[index] = arr[index][0].toUpperCase() + arr[index].slice(1);
    }

    Если слов с минимальной длиной может быть несколько и надо изменить все:

    const [ indexes ] = arr.reduce((min, n, i) => (
      n.length < min[1] && (min = [ [], n.length ]),
      n.length === min[1] && min[0].push(i),
      min
    ), [ [], Infinity ]);
    
    indexes.forEach(n => arr[n] = arr[n].replace(/./, m => m.toUpperCase()));
    Ответ написан
    Комментировать
  • Как распарсить время для понимания JS?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const date = new Date(str.replace(/\S+/, m => m.split('.').reverse().join('-')));

    или

    const date = new Date(str.replace(/(\d+)\.(\d+)\.(\d+)/, '$3-$2-$1'));

    или

    const [ day, month, year, hours, minutes, seconds ] = str.split(/\D/);
    const date = new Date(year, month - 1, day, hours, minutes, seconds);

    или (day.js):

    const date = dayjs(str, 'DD.MM.YYYY HH:mm:ss').toDate();
    Ответ написан
    Комментировать
  • Как правильно отсортировать массив объектов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function sort([...arr]) {
      const max = arr.reduce((max, n) => max?.population > n.population ? max : n, null);
      return arr.sort((a, b) => a === max ? -1 : b === max ? 1 : a.city.localeCompare(b.city));
    }
    Ответ написан
    1 комментарий
  • Как перебрать все элементы с одним классом, выбрать у них тексты и добавить в одну переменную через запятую?

    0xD34F
    @0xD34F Куратор тега JavaScript
    О каком классе идёт речь: const className = 'model';

    Как получить элементы:

    const elements = document.querySelectorAll(`.${className}`);
    // или
    const elements = document.getElementsByClassName(className);

    Как извлечь из элемента его текст:

    const getText = el => el.textContent;
    // или
    const getText = el => el.innerText;
    // или (т.к. вложенных элементов нет, это тоже сработает как надо)
    const getText = el => el.innerHTML;

    Перебираем элементы, достаём тексты, склеиваем:

    const result = Array.from(elements, getText).join(', ');
    
    // или
    
    const result = ''.concat(...[...elements].flatMap((n, i) => (
      n = getText(n),
      i ? [ ', ', n ] : n
    )));
    
    // или
    
    const result = Array.prototype.reduce.call(
      elements,
      (acc, n, i) => acc + (i ? ', ' : '') + getText(n),
      ''
    );
    Ответ написан
    1 комментарий