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

    0xD34F
    @0xD34F Куратор тега JavaScript
    .card.show .text {
      display: block;
    }

    const containerSelector = '.card';
    const buttonSelector = 'button';
    const activeClass = 'show';

    document.addEventListener('click', e => {
      const button = e.target.closest(buttonSelector);
      const container = button && button.closest(containerSelector);
      container && container.classList.toggle(activeClass);
    });
    
    // или
    
    document
      .querySelectorAll(`${containerSelector} ${buttonSelector}`)
      .forEach(n => n.addEventListener('click', onClick));
    
    function onClick() {
      this.closest(containerSelector).classList.toggle(activeClass);
    }
    Ответ написан
    1 комментарий
  • Как из вложенных массивов достать объекты с известными значениями определённого свойства?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Идентификаторы объектов, которые хотим получить, сложим в массив:

    const ids = [ 9, 10 ];

    Вложенные массивы объектов соберём в один общий:

    const items = arr.flatMap(n => n.items);
    
    // или
    
    const items = Array.prototype.concat.apply([], arr.map(n => n.items));
    
    // или
    
    const items = arr.reduce((acc, n) => (acc.push(...n.items), acc), []);

    Извлечём объекты:

    const result = items.filter(n => ids.includes(n.id));
    
    // или
    
    const result = items.filter(function(n) {
      return this.has(n.id);
    }, new Set(ids));
    
    // или
    
    const itemsObj = Object.fromEntries(items.map(n => [ n.id, n ]));
    const result = ids.reduce((acc, n) => ((n = itemsObj[n]) && acc.push(n), acc), []);
    Ответ написан
    Комментировать
  • Проверить наличие prev(), next() элемента?

    0xD34F
    @0xD34F Куратор тега JavaScript
    <button data-step="+1">PREV</button>
    <button data-step="-1">NEXT</button>

    const sliderSelector = '.slider';
    const blockSelector = '.block';
    const buttonDataAttr = 'step';
    const buttonSelector = `[data-${buttonDataAttr}]`;
    const activeClass = 'active';
    const getActiveBlockIndex = () => ((-pos % len) + len) % len;
    const getSliderRotation = () => 'rotate(' + pos * 360 / len + 'deg)';
    let pos = 0;

    Вот jquery:

    const $slider = $(sliderSelector);
    const $blocks = $slider.find(blockSelector);
    const len = $blocks.length;
    
    $(buttonSelector).click(function() {
      $blocks.eq(getActiveBlockIndex()).removeClass(activeClass);
      pos += parseInt($(this).data(buttonDataAttr));
      $slider.css('transform', getSliderRotation());
      $blocks.eq(getActiveBlockIndex()).addClass(activeClass);
    });

    А вот jquery нет:

    const slider = document.querySelector(sliderSelector);
    const blocks = slider.querySelectorAll(blockSelector);
    const len = blocks.length;
    
    document.querySelectorAll(buttonSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, function() {
      blocks[getActiveBlockIndex()].classList.remove(activeClass);
      pos += +this.dataset[buttonDataAttr];
      slider.style.transform = getSliderRotation();
      blocks[getActiveBlockIndex()].classList.add(activeClass);
    });
    Ответ написан
    1 комментарий
  • Почему выходит ошибка в Search?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Метод search использует для поиска регулярные выражения, и если аргумент таковым не является, он будет в регулярку преобразован. Круглые скобки в регулярных выражениях являются спецсимволами, так что если хотите, чтобы скобка была просто скобкой, её надо экранировать. Поставьте перед ней два обратных слэша: .search('\\('). Или один, если замените строку на литерал регулярного выражения: .search(/\(/).
    Ответ написан
    3 комментария
  • Сдвинуть каждый последующий блок на +px?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кого надо подвинуть: const selector = '.test_wr .test_block';.

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

    const key = 'top'; // или 'margin-top'
    const getVal = i => (i * 100) + 'px';
    
    // или
    
    const key = 'transform';
    const getVal = i => `translateY(${i * 100}px)`;

    Вот так всё просто получается:

    $(selector).css(key, getVal);
    
    // или
    
    document.querySelectorAll(selector).forEach((n, i) => {
      n.style[key] = getVal(i);
      // или
      n.style.setProperty(key, getVal(i));
      // или
      n.style.cssText += [ key, ': ', getVal(i) ].join('');
      // или
      n.setAttribute('style', key.concat(': ', getVal(i)));
    });
    Ответ написан
    Комментировать
  • Как привести группу объектов к массиву?

    0xD34F
    @0xD34F Куратор тега JavaScript
    json.results.map(({ lists, volume }) => {
      return lists.map(({ tags, list }) => {
        return tags.map(tag => ({ volume, list, tag }));
      });
    }).flat(2)
    Ответ написан
    1 комментарий
  • Как убрать класс у родителя, если input не пуст?

    0xD34F
    @0xD34F Куратор тега JavaScript
    скрипт работает лишь тогда, когда ты что-то напишешь в поле

    Это как? В смысле - как вам удаётся что-либо написать в скрытый инпут?

    Но окей, вам виднее...

    Где инпуты находятся, что за инпуты, какой класс надо переключать:

    const blockSelector = '.ingredient-b';
    const inputSelector = 'input';
    const className = 'display_none';

    Переключаем класс у всех и сразу:

    $(blockSelector)
      .addClass(className)
      .filter((i, n) => $(inputSelector, n).val())
      .removeClass(className);
    
    // или
    
    document.querySelectorAll(blockSelector).forEach(n => {
      n.classList.toggle(className, !n.querySelector(inputSelector).value);
    });

    Или, ещё и при редактировании input'ов:

    $(`${blockSelector} ${inputSelector}`).on('input', ({ target: t }) => {
      $(t).closest(blockSelector).toggleClass(className, !$(t).val());
    }).trigger('input');
    
    // или
    
    document.querySelectorAll(`${blockSelector} ${inputSelector}`).forEach(function(n) {
      n.addEventListener('input', this);
      n.dispatchEvent(new Event('input'));
    }, ({ target: t }) => t.closest(blockSelector).classList.toggle(className, !t.value));
    Ответ написан
    Комментировать
  • Как вывести многоуровневый список?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сначала превращаем плоский массив во вложенный:

    function createTreeData(data, idKey, parentKey) {
      const tree = Object.fromEntries(data.map(n => [ n[idKey], { ...n, children: [] } ]));
    
      return Object
        .values(tree)
        .filter(n => !(tree[n[parentKey]] && tree[n[parentKey]].children.push(n)));
    }

    Затем из вложенного массива можно собрать разметку:

    const createTreeHTML = data =>
      Array.isArray(data) && data.length
        ? `<ul>${data.map(n => `
             <li>
               ${n.name}
               ${createTreeHTML(n.children)}
             </li>`).join('')}
           </ul>`
        : '';

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

    const createTreeElement = data =>
      data instanceof Array && data.length
        ? data.reduce((ul, n) => (
            ul.append(document.createElement('li')),
            ul.lastChild.append(n.name, createTreeElement(n.children)),
            ul
          ), document.createElement('ul'))
        : '';

    Вот так всё просто получается:

    const treeData = createTreeData(obj, 'id', 'parent_id');
    
    document.body.insertAdjacentHTML('beforeend', createTreeHTML(treeData));
    document.body.append(createTreeElement(treeData));

    Но вообще, можно ещё проще - без собирания вложенного массива:

    function createTreeElements(arr, idKey, parentKey) {
      const tree = arr.reduce((acc, { [parentKey]: n }) => (
        acc[n] = acc[n] || document.createElement('ul'),
        acc
      ), {});
    
      arr.forEach(n => (
        tree[n[parentKey]].append(document.createElement('li')),
        tree[n[parentKey]].lastChild.append(n.name, tree[n[idKey]] || '')
      ));
    
      return Object.values(tree).filter(n => !n.parentNode);
    }
    
    document.body.append(...createTreeElements(obj, 'id', 'parent_id'));
    Ответ написан
    1 комментарий
  • Как из массива массивов собрать массив вида [ { значение: массив индексов, по которым данное значение можно встретить в исходном массиве } ]?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const result = Object
      .entries(arr.reduce((acc, [ n ], i) => ((acc[n] = acc[n] || []).push(i), acc), {}))
      .map(n => ({ [n[0]]: n[1] }));
    Ответ написан
    Комментировать
  • Как сделать фильтрацию по датам?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function filterByMinMax(arr, [ min, max ], key = n => n) {
      const getVal = key instanceof Function ? key : n => n[key];
      return arr.filter(n => {
        const val = getVal(n);
        return (min == null || min <= val) && (max == null || val <= max);
      });
    }

    const d1 = filterByMinMax(chartPoints, [ new Date('2019-02-19') ], n => new Date(n.date));
    const d2 = filterByMinMax(chartPoints, [ , '2019-01-23' ], n => n.date);
    const d3 = filterByMinMax(chartPoints, [ '2019-02-12', '2019-02-26' ], 'date');
    Ответ написан
    2 комментария
  • Как расставить элементы в списке?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Object.values(arr.reduce((acc, row) => {
      row.forEach((n, i, a) => i && (acc[n] = acc[n] || [n]).push(a[0]));
      return acc;
    }, {}))
    Ответ написан
    Комментировать
  • Как передать текст из несколько contenteditable в один textarea?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $(document).on('input', '.editor', function() {
      const content = $('.editor')
        .get()
        .map(n => `\n  <li>${$(n).html()}</li>`)
        .join('');
    
      $('textarea').val(`<ul>${content}\n</ul>`);
    });
    Ответ написан
    2 комментария
  • Как подставлять "-" через каждые 4 символа?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.replace(/.{4}(?!$)/g, '$&-')
    
    // или
    
    str.match(/.{1,4}/g).join('-')
    
    // или
    
    str.split(/(?<=^(?:.{4})+)/).reduce((acc, n) => acc + (acc && '-') + n, '')
    
    // или
    
    ''.concat(...[...str].map((n, i) => !i || i % 4 ? n : `-${n}`))
    
    // или
    
    Array.from(
      { length: Math.ceil(str.length / 4) },
      (n, i) => str.slice(i * 4, (i + 1) * 4)
    ).join`-`
    Ответ написан
    Комментировать
  • Как упростить выравнивание высот нескольких элементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const items = document.querySelectorAll('.yourself-item__title');
    const height = `${Math.max(...Array.from(items, n => n.clientHeight))}px`;
    items.forEach(n => n.style.height = height);
    Ответ написан
  • Как сделать второй уровень аккордиона?

    0xD34F
    @0xD34F Куратор тега CSS
    При загрузке страницы вы прячете .accordion__grandchild__item, а переключаете видимость у родительских элементов - .accordion__grandchild__group. Надо как-то устранить это печальное несоответствие.
    Ответ написан
    5 комментариев
  • Как посчитать количество элементов jquery?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('select').change(function() {
      const v = this.value;
      $('.sum').text($(`.element${v === '*' ? '' : `.${v}`}`).length);
    });

    или

    document.querySelector('select').addEventListener('change', e => {
      const v = e.target.value;
      const s = '.element' + (v === '*' ? '' : '.' + v);
      document.querySelector('.sum').textContent = document.querySelectorAll(s).length;
    });
    Ответ написан
    Комментировать
  • Как изменять названия индексов массивов в атрибуте name поля input?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавляете элементам data-атрибуты, в зависимости от того, за какую часть имени отвечают их значения. Слушаете событие input - собираете значения, из значений собираете имена. Как-то так:

    <select data-prop="type">
      <option hidden></option>
      <option value="type1">hello, world!!</option>
      <option value="type2">fuck the world</option>
      <option value="type3">fuck everything</option>
    </select>
    <br>
    <input placeholder="name1" data-prop="name">
    <input placeholder="name2" data-prop="name">
    <input placeholder="name3" data-prop="name">
    <br>
    <input placeholder="url1" data-prop="url">
    <input placeholder="url2" data-prop="url">
    <input placeholder="url3" data-prop="url">
    <br>
    <input class="value" disabled>
    <input class="value" disabled>
    <input class="value" disabled>

    const getValues = prop =>
      Array.from(document.querySelectorAll(`[data-prop="${prop}"]`), n => n.value);
    
    
    document.addEventListener('input', e => {
      if (!e.target.dataset.prop) {
        return;
      }
    
      const type = getValues('type')[0];
      const names = getValues('name');
      const urls = getValues('url');
    
      document.querySelectorAll('.value').forEach((n, i) => {
        n.name = n.value = `xxx[${type}][${names[i]}][${urls[i]}]`;
      });
    });
    Ответ написан
    Комментировать
  • Как сделать чтобы активная страница подсвечивалась?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Достаточно добавить один символ... Или убрать. Вот здесь:

    if (item.innerText === currentPage) {

    Одно значение является строкой, другое числом. Число строке не может быть равно. Так что или выполняйте сравнение с приведением типов:

    item.innerText == currentPage

    Или превращайте строку в число явным образом:

    +item.innerText === currentPage

    Это если по-быстрому исправить то, что есть. Но вообще, я бы всё переписал:

    document.body.insertAdjacentHTML('beforeend', `
      <div class="container">
        <table>
          <thead>
            <tr>${keys.map(k => `
              <th>${k}</th>`).join('')}
            </tr>
          </thead>
          <tbody></tbody>
        </table>
        <div class="pagination"></div>
      </div>
    `);
    
    const tableEl = document.querySelector('.container table');
    const paginationEl = document.querySelector('.container .pagination');
    
    paginationEl.addEventListener('click', ({ target: t }) =>
      t.matches('a') && showPage(+t.textContent)
    );
    
    function showPage(page) {
      paginationEl.innerHTML = Array
        .from(
          { length: Math.ceil(data.length / rows) },
          (_, i) => `<a${-~i === page ? ' class="active"' : ''}>${-~i}</a>`)
        .join('');
    
      tableEl.tBodies[0].innerHTML = data
        .slice(~-page * rows, page * rows)
        .map(n => `
          <tr>${keys.map(k => `
            <td>${n[k]}</td>`).join('')}
          </tr>`)
        .join('');
    }
    
    showPage(1);
    Ответ написан
    Комментировать
  • Как проверить несколько input`ov с одинаковым классом на пустоту?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кого надо проверить: const $inputs = $('.input_1');.

    Проверяем:

    Array.from($inputs).forEach(n => console.log(n, n.value ? 'я заполнен' : 'я пуст'));
    
    console.log($inputs.get().some(n => n.value) ? 'кто-то заполнен' : 'все пустые');
    
    console.log($inputs.toArray().every(n => n.value) ? 'все заполнены' : 'кто-то пуст');
    
    console.log(Array.prototype.filter.call($inputs, n => n.value), 'мы заполнены');
    
    console.log([...$inputs.not((i, n) => n.value)], 'мы пустые');
    Ответ написан
    Комментировать
  • Как определить сегодняшнюю дату в Москве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function getDateInTimeZone(utcOffset, date = new Date()) {
      const utcTime = date.getTime() + date.getTimezoneOffset() * 60000;
      return new Date(utcTime + utcOffset * 3600000);
    }
    
    
    const moscowDate = getDateInTimeZone(3);
    const newYorkDate = getDateInTimeZone(-5);
    const tokyoDate = getDateInTimeZone(9);
    Ответ написан