Задать вопрос
Ответы пользователя по тегу JavaScript
  • Как сделать, чтобы при смене select (плагин select2) карточка оставалась наведённой?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('select').select2({
      minimumResultsForSearch: Infinity,
      dropdownParent: $('.card-more'),
    });
    Ответ написан
    1 комментарий
  • Выключатель на jquery?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const $li = $('ul li').show().slice(8).hide();
    
    $('#loadMore').on('click', function(e) {
      e.preventDefault();
      $li.fadeToggle();
    });
    Ответ написан
  • Как сериализовать вложенный объект?

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

    const serialize = (obj, path) => Object
      .entries(obj)
      .map(([ k, v ]) => {
        const p = path ? `${path}[${k}]` : k;
        return v instanceof Object ? serialize(v, p) : `${p}=${v}`;
      })
      .join('&');

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

    function serialize(obj) {
      const result = [];
    
      for (const stack = [ [ obj, '' ] ]; stack.length;) {
        const [ n, path ] = stack.pop();
        if (n === Object(n)) {
          stack.push(...Object
            .keys(n)
            .map(k => [ n[k], path ? `${path}[${k}]` : k ])
            .reverse()
          );
        } else {
          result.push(`${path}=${n}`);
        }
      }
    
      return result.join('&');
    }
    Ответ написан
    Комментировать
  • Как проверить битую картинку?

    0xD34F
    @0xD34F Куратор тега JavaScript
    img.onload = () => images.appendChild(img);
    img.onerror = () => console.log('меня нет');
    Ответ написан
    Комментировать
  • Фильтр таблицы HTML по checkbox?

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

    0xD34F
    @0xD34F Куратор тега JavaScript
    Во-первых, get-age - это не data-атрибут. Меняйте на data-age.

    Во-вторых, сделайте значения селекторами, т.е. вместо age_3_6 будет .age_3_6, вместо age_7_10 будет .age_7_10 и т.д., ну а у элемента "все" будет data-age="*".

    const itemSelector = '.ped_holder .ped';
    const buttonSelector = '.ages a';
    const activeButtonClass = 'active';
    const selectorAttr = 'age';

    const $buttons = $(buttonSelector).click(function() {
      const selector = $buttons
        .removeClass(activeButtonClass)
        .filter(this)
        .addClass(activeButtonClass)
        .data(selectorAttr);
    
      $(itemSelector).hide().filter(selector).show();
    });
    
    // или, к чёрту jquery
    
    const buttons = document.querySelectorAll(buttonSelector);
    const items = document.querySelectorAll(itemSelector);
    
    buttons.forEach(n => n.addEventListener('click', onClick));
    
    function onClick({ target: t }) {
      const selector = t.dataset[selectorAttr];
      buttons.forEach(n => n.classList.toggle(activeButtonClass, n === t));
      items.forEach(n => n.style.display = n.matches(selector) ? '' : 'none');
    }
    Ответ написан
    Комментировать
  • Как сортировать даты только по дню и месяцу?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сортируем существующий массив:

    arr.sort((a, b) => {
      a = a.split('.', 2);
      b = b.split('.', 2);
      return (a[1] - b[1]) || (a[0] - b[0]);
    });

    Или, собираем отсортированный новый:

    const sortedArr = arr
      .map(n => n.split('.'))
      .sort((a, b) => (a[1] - b[1]) || (a[0] - b[0]))
      .map(n => n.join('.'));
    Ответ написан
    Комментировать
  • Возможно ли решить задачу без циклов?

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

    const sum = (val, index = 0) =>
      val instanceof Array
        ? val.length > index
          ? sum(val[index]) + sum(val, index + 1)
          : 0
        : val;
    Ответ написан
    Комментировать
  • Как правильно клонировать input[type=radio]?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Хотите, чтобы суффиксы у атрибутов name были правильные - оператор + вам в помощь, добавляйте сколько надо.

    Хотите, чтобы клонирование происходило не только по клику на кнопку, что существует изначально, но и по новым - клонируйте элементы вместе с обработчиками событий или делегируйте обработку клика контейнеру.

    // исправляем ваш код
    $('.add-attr').on('click', function() {
      const index = $('.radios').length + 1;
    
      const $lastRow = $(this).closest('.container').find('.item').last();
      const $newRow = $lastRow.clone(true).insertAfter($lastRow);
    
      $newRow.find('input[type="radio"]').prop('name', 'name-' + index);
    });
    
    // или переписываем его без использования jquery
    document.querySelector('.container').addEventListener('click', e => {
      if (e.target.classList.contains('add-attr')) {
        const row = e.currentTarget.firstElementChild.cloneNode(true);
        const name = `name-${e.currentTarget.children.length + 1}`;
        e.currentTarget.appendChild(row);
        row.querySelectorAll('[type="radio"]').forEach(n => n.name = name);
      }
    });
    Ответ написан
    6 комментариев
  • Как подсчитать количество блоков в блоке?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const count = document.querySelectorAll('.ablock [class*="bblock_"]').length;

    Если кроме .bblock_* других элементов внутри .ablock нет, то

    const count = document.querySelector('.ablock').children.length;
    Ответ написан
    Комментировать
  • Как клонировать селект с изменением id?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Очень странный способ клонировать select'ы - сохранить настройки плагина клонируемых элементов, деактивировать плагин на клонируемых элементах, клонировать элементы, инициализировать плагин у клонов и повторно у оригиналов, обновить настройки. Можно сделать попроще: в самом начале сделать клон элементов, и потом уже клонировать его; инициализацию плагина вынести в отдельную функцию, которая будет принимать набор элементов.

    Странный способ получать новые значения id - единица в качестве начального значения и постфиксный инкремент. В результате последовательность идентификаторов получается такая: 1, 2, 3,... Элементы с 1 и 2 уже есть. Начальным значением должно быть максимальное существующее значение плюс единица. Или просто максимум, но инкремент тогда префиксный.

    const $row = $('.b-items').clone();
    let ID = +$row.find('select').last().attr('id').split('-').pop();
    
    function selectize($el) {
      $el.selectize({
        allowEmptyOption: true,
        create: true,
      });
    }
    
    selectize($('select'));
    
    $('.btn-clone').on('click', function() {
      selectize($row
        .clone()
        .insertBefore(this)
        .find('select')
        .attr('id', () => `select-${++ID}`)
      );
    });
    Ответ написан
    3 комментария
  • Выдает ошибку при переборе .children. Что делать?

    0xD34F
    @0xD34F Куратор тега JavaScript
    У последнего элемента следующего нет, так что в качестве nextElementSibling вы получаете null, а у null нельзя читать свойства. Как победить возникающую ошибку? - проще всего будет вообще не трогать последний элемент, пусть цикл делает на одну итерацию меньше, для этого замените i < children.length на i < children.length - 1. Другой вариант - прежде чем пытаться читать свойства у следующего элемента, проверять, существует ли он, или не является ли текущий последним, или подсовывать вместо отсутствующего элемента пустой объект - актуально в том случае, если перебор элементов организован не через цикл со счётчиком, а с помощью for...of или методов.

    Ещё стоит разобраться, чем присваивание отличается от проверки на равенство (nodeName = 'P', ну да, ну да).

    Как может выглядеть исправленная (и переписанная) функция:

    function findAllPSiblings(el) {
      const result = [];
    
      for (const n of el.children) {
        if ((n.nextElementSibling || {}).tagName === 'P') {
          result.push(n);
        }
      }
    
      return result;
    }

    А вообще, зачем ограничиваться одними лишь p? Давайте решим задачу в чуть более общем виде - пусть функция кроме родительского элемента принимает ещё и селектор, которому должны соответствовать соседи справа:

    const getChildrenWithNext = (el, selector) =>
      Array.prototype.filter.call(
        el.children,
        ({ nextElementSibling: n }) => n && n.matches(selector)
      );
    Ответ написан
    Комментировать
  • Как подсветить элементы, содержащие заданную подстроку, игнорируя регистр?

    0xD34F
    @0xD34F Куратор тега JavaScript
    О каких элементах идёт речь: const className = 'intro';.

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

    function setHighlight(value) {
      value = value.toLowerCase();
    
      for (const n of document.getElementsByClassName(className)) {
        const matched = value && n.innerText.toLowerCase().includes(value);
        n.style.backgroundColor = matched ? 'silver' : '';
      }
    }

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

    .highlight {
      background-color: silver;
    }

    function setHighlight(value) {
      let test = () => false;
      if (value) {
        try {
          test = RegExp.prototype.test.bind(RegExp(value, 'i'));
        } catch (e) {}
      }
    
      document.querySelectorAll(`.${className}`).forEach(n => {
        n.classList.toggle('highlight', test(n.textContent));
      });
    }
    Ответ написан
    1 комментарий
  • При нажатии на плюс значение прибавляется, при нажатии на минус убавляется. Как сделать?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сколько предполагается таких элементов - один или несколько? Будем считать, что несколько.

    Общий принцип тут такой - поймали клик по кнопке; определили, что за кнопка (т.е., как должно будет измениться значение, плюс или минус единица); от кнопки поднялись до общего предка кнопки и элемента, содержащего значение, внутри общего предка нашли элемент со значением; обновили значение.

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

    function setOnClick(selector, change) {
      function onClick({ target: t }) {
        const el = t.closest('.style-item_count').querySelector('.style-count-number');
        el.innerText = el.innerText.replace(/\d+/, m => Math.max(0, +m + change));
      }
    
      document.querySelectorAll(selector).forEach(n => n.addEventListener('click', onClick));
    }
    
    setOnClick('.style-count-plus', 1);
    setOnClick('.style-count-minus', -1);
    
    // или
    
    function setOnClick(selector, change) {
      $(selector).on('click', e => {
        $(e.target)
          .closest('.style-item_count')
          .find('.style-count-number')
          .text((i, text) => `${Math.max(0, parseInt(text) + change)} шт`);
      });
    }

    Вариант два - делегирование, один обработчик на всех. Если не менять разметку, то

    document.addEventListener('click', ({ target: t }) => {
      const change = +t.matches('.style-count-plus') || -t.matches('.style-count-minus');
      if (change) {
        const el = t.closest('.style-item_count').querySelector('.style-count-number');
        el.innerText = `${Math.max(0, parseInt(el.innerText) + change)} шт`;
      }
    });
    
    // или
    
    $(document).on('click', '.style-count-plus, .style-count-minus', e => {
      const $target = $(e.target);
      const change = $target.hasClass('style-count-plus') ? 1 : -1;
    
      $target
        .closest('.style-item_count')
        .find('.style-count-number')
        .text((i, text) => text.replace(/\d+/, m => Math.max(0, +m + change)));
    });

    Но если кнопкам добавить data-атрибуты, которые будут указывать, на сколько надо изменить значение, а самому значению добавить обёртку (чтобы отделить его от единиц измерения), то код можно немного упростить:

    <div class="style-item_count">
      <div class="style-count-minus" data-change="-1">-</div>
      <div class="style-count-number"><span>1</span> шт</div>
      <div class="style-count-plus" data-change="+1">+</div>
    </div>

    document.addEventListener('click', ({ target: t }) => {
      const change = +t.dataset.change;
      if (change) {
        const el = t.closest('.style-item_count').querySelector('.style-count-number span');
        el.textContent = Math.max(0, +el.textContent + change);
      }
    });
    
    // или
    
    $(document).on('click', '[data-change]', function() {
      $(this)
        .closest('.style-item_count')
        .find('.style-count-number span')
        .text((i, text) => Math.max(0, +text + +this.dataset.change));
    });
    Ответ написан
    1 комментарий
  • Как случайным образом добавлять элемент?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Почему у блоков отсутствует общий класс? - добавьте, пусть будет class="banner".

    Кого и куда надо переместить:

    const containers = document.querySelectorAll('.products--container');
    const items = [...document.querySelectorAll('.banner')];

    Перемещаем:

    for (const n of containers) {
      n.appendChild(items.splice(Math.random() * items.length | 0, 1)[0]);
    }

    или

    for (let i = items.length; --i > 0;) {
      const j = Math.random() * -~i | 0;
      [ items[i], items[j] ] = [ items[j], items[i] ];
    }
    
    containers.forEach((n, i) => n.append(items[i]));
    Ответ написан
    Комментировать
  • Как объекты, состоящие из нескольких свойств, разделить на несколько объектов из одного свойства?

    0xD34F
    @0xD34F Куратор тега JavaScript
    arr.map(n => Object
      .entries(n)
      .reduce((acc, [ k, v ]) => (
        acc[k] = v
          .flatMap(Object.entries)
          .map(([ k, v ]) => ({ [k]: v })),
        acc
      ), {})
    )
    Ответ написан
    3 комментария
  • Как узнать, что ul список состоит из ссылок?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const isOnlyLinks = ul => Array
      .from(ul.querySelectorAll(':scope > li'))
      .every(({ childNodes: n }) => !~-n.length && n[0] instanceof HTMLAnchorElement);

    или

    const isOnlyLinks = ul =>
      Array.prototype.every.call(
        ul.children,
        ({ childNodes: [ a, b ] }) => a && a.tagName === 'A' && !b,
      );
    Ответ написан
    2 комментария
  • Как сравнить массив с объектами и если значение у этих объектов разные, то взять его id?

    0xD34F
    @0xD34F Куратор тега JavaScript
    arr1.filter((n, i) => arr2[i].num !== n.num).map(n => n.id)

    или

    arr1.reduce((acc, n, i) => (arr2[i].num === n.num || acc.push(n.id), acc), [])
    Ответ написан
    Комментировать
  • Почему перезагружается страница после отправки формы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Имитация клика по кнопке происходит до подключения обработчика submit.
    Ответ написан