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

    0xD34F
    @0xD34F Куратор тега JavaScript
    Ответ написан
    Комментировать
  • Как превратить плоский массив в дерево?

    0xD34F
    @0xD34F Куратор тега JavaScript
    попытался решить все через рекурсию

    Рекурсией конечно можно:

    const createTree = (data, parentId = null) =>
      data.reduce((acc, n) => (
        parentId === n.parentId && (
          acc[acc.length] = Object.assign(
            { children: createTree(data, n.id) },
            n
          )
        ),
        acc
      ), []);

    Но вовсе не обязательно:

    function createTree({
      data,
      key = 'id',
      parentKey = 'parentId',
      childrenKey = 'children',
    }) {
      const tree = Object.fromEntries(data.map(n => [
        n[key],
        { ...n, [childrenKey]: [] },
      ]));
    
      return Object.values(tree).filter(n => !(
        tree[n[parentKey]] && tree[n[parentKey]][childrenKey].push(n)
      ));
    }
    Ответ написан
    Комментировать
  • Как заставить регулярку найти скобку?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Экранируйте скобку: text = '\\('.
    Ответ написан
    9 комментариев
  • Как найти в h1 текст и подсветить его?

    0xD34F
    @0xD34F Куратор тега JavaScript
    закрывающий тэг - на самом деле не закрывающий
    Ответ написан
    6 комментариев
  • Как обратиться к блоку, который в поле видимости?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Ответ написан
    Комментировать
  • Как при клике на button менять у ссылки data-rel=""?

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

    <button class="cve" data-rel="69c99408142132">S</button>
    <button class="cve" data-rel="69c99408143167">M</button>  
    <button class="cve" data-rel="69c99408143177">L</button>

    Дальше можно сделать делегированный обработчик клика, в котором будем пытаться подняться от целевого элемента к ссылке (в вашем случае было бы достаточно проверки наличия класса - if (t.classList.contains('cve')), но кто его знает, может, решите в будущем добавить внутрь кнопок ещё какие-то элементы):

    document.addEventListener('click', ({ target: t }) => {
      if (t = t.closest('.cve')) {
        document.getElementById('bodyone').dataset.rel = t.dataset.rel;
      }
    });

    Или, есть вариант назначать обработчик клика непосредственно каждой кнопке:

    const el = document.querySelector('#bodyone');
    const onClick = e => el.dataset.rel = e.currentTarget.dataset.rel;
    document.querySelectorAll('.cve').forEach(n => n.addEventListener('click', onClick));
    Ответ написан
    2 комментария
  • Как вложить элементы массива друг в друга начиная с конца?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const result = array
      .concat(obj)
      .reduceRight((acc, n) => ({
        ...n,
        children: acc ? [ acc ] : [],
        // или, если вдруг исходные массивы непустые,
        // и их содержимое надо сохранить
        // children: n.children.concat(acc || []),
      }), null);

    Непонятно только, зачем вложенные массивы из одного элемента? Можно класть в объект просто ссылку на следующий объект, получится обычный связный список:

    const result = [ ...array, obj ].reduceRight(
      (acc, { children, ...n }) => (n.next = acc, n),
      null
    );
    Ответ написан
    1 комментарий
  • Как проверить коллекцию input на пустоту?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const isEmpty = [...inputs].some(n => !n.value);
    
    // или
    
    const isEmpty = !Array.prototype.every.call(inputs, n => n.value);
    
    // или
    
    let isEmpty = false;
    for (const n of inputs) {
      if (!n.value) {
        isEmpty = true;
        break;
      }
    }
    
    // или
    
    let isEmpty = false;
    for (let i = -1; ++i < inputs.length && !(isEmpty = !inputs[i].value);) ;
    
    // или
    
    const isEmpty = (function isEmpty(i, n = inputs.item(i)) {
      return !!n && (!n.value || isEmpty(-~i));
    })(0);
    Ответ написан
    4 комментария
  • Как вывести массив ссылок, добавив заголовки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сначала группируете данные:

    const grouped = Object.entries(list.reduce((acc, n) => (
      (acc[n.part] = acc[n.part] || []).push(n.title),
      acc
    ), {}));

    Потом можно html собрать:

    document.body.insertAdjacentHTML('beforeend', grouped
      .map(([ k, v ]) => `<div>${k}</div>${v.map(n => `<div>${n}</div>`).join('')}`)
      .join('')
    );

    Или создать элементы напрямую:

    document.body.append(...grouped.flat(2).map(n => {
      const div = document.createElement('div');
      div.innerText = n;
      return div;
    }));
    Ответ написан
    4 комментария
  • Как наиболее оптимально скрыть элемент с определённым значением data-атрибута?

    0xD34F
    @0xD34F Куратор тега JavaScript
    О каких элементах, data-атрибуте и значениях идёт речь:

    const selector = '.form-group';
    const attr = 'data-property-id-row';
    const values = [ 10, 13, 15 ];

    Скрываем элементы с указанными значениями:

    const elementsToHide = document.querySelectorAll(values
      .map(n => `${selector}[${attr}="${n}"]`)
      .join(', ')
    );

    for (let i = 0; i < elementsToHide.length; i++) {
      elementsToHide[i].style.transform = 'scale(0)';
    }
    
    // или
    
    (function next(i, n = elementsToHide.item(i)) {
      n && (n.style.visibility = 'hidden', next(-~i));
    })(0);

    Или, кроме скрытия указанных, остальные показываем (если вдруг были скрыты):

    const elements = document.querySelectorAll(selector);

    for (const n of elements) {
      n.hidden = values.includes(Number(n.attributes[attr].value));
    }
    
    // или (в стили надо будет добавить .hidden { display: none; })
    
    elements.forEach(function(n) {
      n.classList.toggle('hidden', this.has(+n.getAttribute(attr)));
    }, new Set(values));
    Ответ написан
    Комментировать
  • Почему не срабатывает первый клик?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Всё срабатывает. Но вот из-за

    $("#changeCityInput").bind("keyup change",

    выпадающий список строится повторно: при клике на пункт списка после редактирования инпута последний теряет фокус, в результате возникает событие change.

    Слушайте событие input:

    $('#changeCityInput').on('input',
    Ответ написан
    1 комментарий
  • Цикл по объектам внутри объекта. Как сделать?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const getNestedData = (data, condition) => Object
      .values(data instanceof Object ? data : {})
      .reduce((acc, n) => (
        acc.push(...getNestedData(n, condition)),
        acc
      ), condition(data) ? [ data ] : []);
    
    
    const objects = getNestedData(data, x => x && x.value > 0);
    Ответ написан
    Комментировать
  • Как получить всех родителя и родителей родителя?

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

    function createTree(data, key, parentKey) {
      const nodesArr = data.map(n => ({ ...n, children: [], parents: [] }));
      const nodesObj = Object.fromEntries(nodesArr.map(n => [ n[key], n ]));
      const roots = nodesArr.filter(n =>
        !(nodesObj[n[parentKey]] && nodesObj[n[parentKey]].children.push(n))
      );
    
      nodesArr.forEach(n => {
        for (let p = n; p = nodesObj[p[parentKey]]; n.parents.push(p)) ;
      });
    
      return [ roots, nodesObj ];
    }

    Возвращает два значения - массив корневых узлов и объект вида { id: узел }.

    В вашем случае применять так:

    const [ roots, tree ] = createTree(data, 'structureId', 'parentId');
    Ответ написан
    Комментировать
  • Как отфильтровать по инпутам-чекбоксам массив элементов с помощью метода filter?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const checked = Array.from(document.querySelectorAll('.btn:checked'), n => n.value);
    const filtered = arr.filter(n => checked.includes(n));
    Ответ написан
    5 комментариев
  • Как создать связный список из массива?

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

    const createList = arr =>
      arr.reduceRight((acc, n) => ({
        val: n,
        next: acc,
      }), null);

    или

    function createList(arr) {
      let list = null;
    
      for (let i = arr.length; i--;) {
        list = {
          val: arr[i],
          next: list,
        };
      }
    
      return list;
    }

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

    const createList = (arr, i = 0) =>
      i < arr.length
        ? ({ val: arr[i], next: createList(arr, i + 1) })
        : null;
    Ответ написан
    6 комментариев
  • Что делают эти строки в коде?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Допустим, есть всего 10 слайдов.

    • Производится попытка установить в качестве текущего слайд номер 14. Что делать? Очевидно, установить в качестве текущего четвёртый - остаток от деления изначально указанного номера на количество слайдов.
    • Как установить минус второй (-2) слайд? - очевидно, это второй с конца, надо добавить количество слайдов, чтобы получить реальный номер.
    • Зачем одновременно добавляется количество слайдов и берётся остаток? - чтобы один и тот же код корректно обрабатывал переходы из конца в начало и из начала в конец.
    Ответ написан
    3 комментария
  • Как скопировать действие кнопки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вариант раз - кликнуть кнопку с помощью соответствующего метода:

    button.addEventListener('click', () => {
      anotherButton.click();
    });

    Вариант два - отправить кнопке событие клика (если обработчик клика висит не на самой кнопке, а выше, то надо сделать событие всплывающим):

    button.addEventListener('click', () => {
      anotherButton.dispatchEvent(new Event('click', { bubbles: true }));
    });
    Ответ написан
    Комментировать
  • Где может быть проблема в цикле?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Один и тот же массив помещаете в result. Делайте копию - замените .push(x) на .push([...x]).

    Или, вместо дополнения существующего массива собирайте на каждой итерации новый массив - уносим объявление внутрь цикла, вместо одного push'а выполняем несколько:

    function pyramid(n) {
      const result = [];
    
      for (let i = 0; ++i <= n;) {
        const x = [];
        for (let j = 0; ++j <= i; x.push(1)) ;
        result.push(x);
      }
    
      return result;
    }

    А вообще, можно и покороче:

    const pyramid = length => Array.from({ length }, (_, i) => Array(i + 1).fill(1));
    Ответ написан
    Комментировать
  • Как получить скобки внутри которой запятая (regex)?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.match(/\((?=[^()]*,)[^()]*\)/)
    Ответ написан
    Комментировать
  • Как отфильтровать объект по массиву значений свойств?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const filterObject = (obj, values) =>
      Object.entries(obj).reduce((acc, [ k, v ]) => (
        values.indexOf(v) !== -1 && (acc[k] = v),
        acc
      ), {});
    
    const result = filterObject(a, b);

    или

    const filterObject = (obj, filter) =>
      Object.fromEntries(Object.entries(obj).filter(n => filter(...n)));
    
    const result = filterObject(a, (k, v) => b.includes(v));
    Ответ написан
    Комментировать