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

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

    Значения отмеченных чекбоксов группируются в соответствии со значениями атрибута name.

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

    const columnIndex = {
      color: 0,
      fruit: 1,
    };
    
    function filter() {
      const filters = Object.entries(Array
        .from(document.querySelectorAll('.list-group :checked'))
        .reduce((acc, n) => ((acc[n.name] ??= []).push(n.value), acc), {})
      );
    
      document.querySelectorAll('table tbody tr').forEach(n => {
        n.style.display = filters.some(([ k, v ]) => !v.includes(n.cells[columnIndex[k]].innerText))
          ? 'none'
          : 'block';
      });
    }
    
    
    document.querySelectorAll('.list-group').forEach(n => n.addEventListener('change', filter));
    Ответ написан
    Комментировать
  • Как получить все вложенные элементы JS?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const getElementsWithDepth = (el, level = 0) =>
      [...el.children].reduce((acc, n) => {
        acc.push(...getElementsWithDepth(n, level + 1));
        return acc;
      }, [ { el, level } ]);
    Ответ написан
    Комментировать
  • Как получить все дни в месяце и подписать номер недели?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function getDays(year, month) {
      const days = [];
      const d = new Date(year, month, 1);
      let week = 1;
    
      while (d.getMonth() === month) {
        const date = d.getDate();
        const day = d.getDay();
    
        days.push({
          day: date,
          weeknumber: (day === 1 || date === 1) ? week : false,
          weekday: d.toLocaleString('en-US', { weekday: 'short' }),
        });
    
        d.setDate(date + 1);
        week += !day;
      }
    
      return days;
    }
    Ответ написан
    Комментировать
  • Как посчитать количество совпадений в тексте?

    0xD34F
    @0xD34F Куратор тега JavaScript
    text.match(RegExp(str, 'g'))?.length ?? 0

    или

    text.split(str).length - 1
    Ответ написан
    2 комментария
  • Как преобразовать объект со вложенными объектами в простой объект?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const flatObj = obj =>
      Object.entries(obj).reduce((acc, [ k, v ]) => (
        v instanceof Object && !Array.isArray(v)
          ? Object.assign(acc, flatObj(v))
          : acc[k] = v,
        acc
      ), {});
    Ответ написан
    2 комментария
  • Как задать элементам ID с условием первого не повторяющегося далее символа?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Такие варианты есть:

    document.querySelectorAll('h2').forEach(n => {
      const [ season, , episode ] = n.innerText.split(' ');
      if (+episode === 1) {
        n.id = `season-${season}`;
      }
    });

    [...document.querySelectorAll('h2')]
      .filter(n => n.innerText.endsWith(', 1 серия'))
      .forEach((n, i) => n.id = `season-${i + 1}`);

    document.querySelectorAll('h2').forEach((n, i, a) => {
      const prev = i && a[i - 1].innerText.match(/\d+/)[0];
      const curr = n.innerText.match(/\d+/)[0];
      if (curr !== prev) {
        n.id = `season-${curr}`;
      }
    });

    Array
      .from(document.querySelectorAll('h2'))
      .reduce((acc, n) => (acc[parseInt(n.innerText)] ??= n, acc), [])
      .forEach((n, i) => n.id = `season-${i}`);
    Ответ написан
    Комментировать
  • Как транспонировать матрицу?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Коротко:

    const transpose = matrix => Array.from(
      { length: matrix[0]?.length ?? 0 },
      (_, i) => matrix.map(n => n[i])
    );

    Длинно:

    function transpose(matrix) {
      const result = Array(matrix.length && matrix[0].length);
    
      for (let i = 0; i < result.length; i++) {
        result[i] = [];
    
        for (let j = 0; j < matrix.length; j++) {
          result[i][j] = matrix[j][i];
        }
      }
    
      return result;
    }
    Ответ написан
    Комментировать
  • Как последовательные числа сложить в отдельные массивы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const groupAdjacent = (arr, newGroup) =>
      arr.reduce((acc, n, i, a) => (
        (!i || newGroup(n, a[~-i])) && acc.push([]),
        acc[~-acc.length].push(n),
        acc
      ), []);
    
    
    const result = groupAdjacent(arr, (c, p) => c !== -~p);

    или (если гарантируется, что элементы массива образуют возрастающую последовательность)

    function group(data, key) {
      const grouped = new Map;
      let i = -1;
    
      for (const n of data) {
        const k = key(n, ++i);
        grouped.set(k, grouped.get(k) ?? []).get(k).push(n);
      }
    
      return grouped;
    }
    
    
    const result = [...group(arr, (n, i) => n - i).values()];
    Ответ написан
    Комментировать
  • Как обрезать строку после длинного слова?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('.js-cropped-word').text((i, text) => text.replace(/(?<=\S{19,}).+/, '...'));

    UPD. Вынесено из комментариев:

    В Сафари не работает

    Это из-за lookbehind. Делайте тогда так:

    document.querySelectorAll('.js-cropped-word').forEach(n => {
      n.textContent = n.textContent.replace(/(\S{19}).+/, '$1...');
    });

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

    const max = 19;
    
    for (const n of document.getElementsByClassName('js-cropped-word')) {
      const words = n.innerText.split(' ');
      const i = words.findIndex(n => n.length > max);
      if (i !== -1) {
        words.length = i + 1;
        words[i] = words[i].slice(0, max) + '...';
        n.innerText = words.join(' ');
      }
    }
    Ответ написан
    6 комментариев
  • Как сделать элемент дочерным для другого?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кого и во что надо обернуть:

    const elements = document.querySelectorAll('input[type="button"]');
    const wrapperTag = 'div';
    const wrapperClass = 'block';

    Оборачиваем:

    elements.forEach(n => {
      const wrapper = document.createElement(wrapperTag);
      n.replaceWith(wrapper);
      wrapper.classList.add(wrapperClass);
      wrapper.append(n);
    });

    или

    for (const n of elements) {
      n.after(document.createElement(wrapperTag));
      n.nextSibling.className = wrapperClass;
      n.nextSibling.appendChild(n);
    }

    или

    for (let i = 0; i < elements.length; i++) {
      const n = elements[i];
      n.outerHTML = `<${wrapperTag} class="${wrapperClass}">${n.outerHTML}</${wrapperTag}>`;
    }

    или

    (function wrap(i, n = elements[i]) {
      if (n) {
        const wrapper = document.createElement(wrapperTag);
        n.parentNode.replaceChild(wrapper, n);
        wrapper.classList.value = wrapperClass;
        wrapper.insertAdjacentElement('afterbegin', n);
        wrap(-~i);
      }
    })(0);
    Ответ написан
  • Как удалить option'ы с определёнными значениями?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Первым делом надо сложить значения удаляемых option'ов в массив:

    const values = [ '1', '2', '3' ];

    Дальше возможны варианты:

    [...selectEl].forEach(n => values.includes(n.value) && n.remove());

    или

    for (const n of selectEl.querySelectorAll(values.map(n => `[value="${n}"]`))) {
      selectEl.removeChild(n);
    }

    или

    for (let i = selectEl.options.length; i--;) {
      const n = selectEl.options[i];
      if (values.indexOf(n.value) !== -1) {
        n.outerHTML = '';
      }
    }
    Ответ написан
    Комментировать
  • Как совместить вставить цикл в constructor?

    0xD34F
    @0xD34F Куратор тега JavaScript
    constructor(el) {
      if (typeof el === 'string') {
        el = document.querySelectorAll(el);
      }
    
      if (typeof el[Symbol.iterator] === 'function') {
        return Array.from(el, n => new Select(n));
      }
    
      this.$select = el;
    
      // дальше всё по-старому
    Ответ написан
    Комментировать
  • Как синхронизировать работу нескольких range slider?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Классы calc__price и calc__payment заменить на общий calc.

    const $price = $('#price');
    const $firstPayment = $('#first-payment');
    
    function update($elem) {
      $elem.closest('.calc').find('output').text($elem.val());
      $('.payment-percent').html(Math.round($firstPayment.val() * 100 / $price.val()) + '%');
    }
    
    
    $price.closest('.calc').on('input', function() {
      const val = $price.val();
    
      $firstPayment
        .val((i, v) => Math.min(v, val))
        .attr('max', val)
        .rangeslider('update', true);
    
      update($firstPayment);
    });
    
    $price.add($firstPayment)
      .rangeslider({ polyfill: false })
      .closest('.calc')
      .on('input', e => update($(e.target)))
      .end()
      .trigger('input');
    Ответ написан
    1 комментарий
  • Как заменить все определенные значения в объекте с неизвестной структурой на другие?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Рекурсия есть:

    function walkNested(val, callback) {
      callback(val);
    
      if (val instanceof Object) {
        Object.values(val).forEach(n => walkNested(n, callback));
      }
    }
    
    
    walkNested(obj, n => n?.touched === true && (n.touched = false));

    Рекурсии нет:

    function walkNested(val, callback) {
      for (const stack = [ val ]; stack.length;) {
        const n = stack.pop();
        callback(n);
        stack.push(...Object.values(n ?? {}));
      }
    }
    Ответ написан
    Комментировать
  • Можно ли переименовать ключи в объектах находящихся в массиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Какие ключи хотелось бы иметь: const keys = [ 'city', 'country' ];.

    Собираем новый массив:

    const newArr = arr.map(n => Object.fromEntries(Object.values(n).map((v, i) => [ keys[i], v ])));

    Обновляем существующий:

    arr.forEach(n => Object.entries(n).forEach(([ k, v ], i) => (delete n[k], n[keys[i]] = v)));
    Ответ написан
    Комментировать
  • Как правильно обрезать уродливые строки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.replace(/\t.*/s, '')
    // или
    str.match(/^[^\t]*/)[0]
    // или
    str.slice(0, str.search(/\t|$/))
    // или
    str.split('\t', 1).pop()
    // или
    [...str].reduceRight((acc, n) => n === '\t' ? '' : n + acc, '')
    Ответ написан
    2 комментария
  • Как решить ошибку при преобразовании Json в Map?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Никаких ошибок нет, всё правильно, как и должно быть. Сколько есть уникальных ключей - столько записей в map'е и создаётся. Как по одному ключу может быть доступно несколько значений? Никак, это абсурд. Очевидно, вы плохо понимаете, чего хотите сделать.
    Ответ написан
  • Как в цикле получить ширину одних блоков и задать ее другим?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const $menuItems = $('#menu a');
    $('#submenu > ul').width(i => $menuItems.eq(i).width());
    Ответ написан
    1 комментарий
  • Слайдер jquery ui и дата, как сделать правильно?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const min = 7;
    const max = min + 21;
    
    function update(value) {
      value = Math.max(min, Math.min(max, value | 0));
    
      $('#spinner2').val(value);
      $('#slider2').slider('value', value);
    
      const date = new Date();
      date.setDate(date.getDate() + value);
      $('#amount').val(date.toLocaleString('en-US', {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
      }));
    }
    
    $('#slider2').slider({
      range: 'min',
      min,
      max,
      step: 1,
      slide: (e, ui) => update(ui.value),
    });
    
    $('#spinner2').spinner({
      min,
      max,
      spin: (e, ui) => update(ui.value),
    }).on('input', e => update(e.target.value)).trigger('input');
    Ответ написан
    1 комментарий
  • Как отсортировать табличные значения?

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

    const sort = {
      number: (a, b) => a - b,
      string: (a, b) => a.localeCompare(b),
    };

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

    function sortTable(table, colIndex) {
      if (typeof table === 'string') {
        table = document.querySelector(table);
      }
    
      const head = table.tHead.rows[0];
      const compare = sort[head.cells[colIndex].dataset.type] ?? sort.string;
      const value = row => row.cells[colIndex].innerText;
      const tbody = table.tBodies[0];
    
      tbody.append(...[...tbody.rows].sort((a, b) => compare(value(a), value(b))));
      [...head.cells].forEach((n, i) => n.classList.toggle('sorted', i == colIndex));
    }

    Стилизуем заголовок столбца, по которому выполнена сортировка:

    .sorted {
      background: #ccc;
    }
    .sorted::after {
      content: " \2193";
    }

    Всё, можно пользоваться:

    // просто дёргаем сортировку
    sortTable('#grid', 0);
    sortTable(document.querySelector('table'), 1);
    
    // или, сортируем по клику на заголовки столбцов
    document.querySelectorAll('#grid th').forEach(function(n) {
      n.addEventListener('click', this);
    }, ({ target: t }) => sortTable(t.closest('table'), t.cellIndex));
    Ответ написан
    Комментировать