Задать вопрос
  • Как правильно клонировать 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 комментария
  • Как получить аттрибут ссылки во vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Пробовал указать и a.href и a.getAttribute('href') и т.д.

    Лучше бы попробовали документацию почитать.

    @click.prevent="toPage"

    toPage(e) {
      console.log(e.target.href)
    }
    Ответ написан
    Комментировать
  • Как "красиво" в методе компонента заменять надпись на каком-либо элементе?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Каким самым правильным способом можно это сделать?

    "Самых правильных" способов нет.

    Создавать еще один элемент в data()?

    Да.
    Ответ написан
    2 комментария
  • Выдает ошибку при переборе .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)
      );
    Ответ написан
    Комментировать
  • Как группировать каждые 3 элемента массива в foreach?

    0xD34F
    @0xD34F
    $arr = array_chunk(range(1, 12), 3);
    foreach ($arr as $chunk) {
      echo "<div>";
      foreach ($chunk as $value) {
        echo "<div>$value</div>";
      }
      echo "</div>";
    }
    Ответ написан
    1 комментарий
  • Как подсветить элементы, содержащие заданную подстроку, игнорируя регистр?

    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 комментарий
  • VueJs: не изменяются реактивные переменные на лету?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Если я правильно понял, должно быть так (в смысле - наблюдаемое поведение, а не код - тут уж вы сами думайте, как правильно надо). Реактивность тут не при чём, проблема в том, что вы сначала используете значение, а потом его меняете, предполагая при этом, что использовано будет изменённое значение.
    Ответ написан
  • При нажатии на плюс значение прибавляется, при нажатии на минус убавляется. Как сделать?

    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 комментарий
  • Vue lodash.shuffle для списка?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Использовать индекс в качестве key не надо никогда. Чтоб вот такого, как у вас сейчас, не было.

    Делаем нормальный key - всё окей.
    Ответ написан
    Комментировать
  • Как случайным образом добавлять элемент?

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

    const banners = [...document.querySelectorAll('.banner')];
    
    for (let i = banners.length; --i > 0;) {
      const j = Math.random() * (i + 1) | 0;
      [ banners[i], banners[j] ] = [ banners[j], banners[i] ];
    }
    
    document.querySelectorAll('.products--container').forEach((n, i) => n.append(banners[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 комментария
  • Chart with Axios?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Как можно с помощью axios подставить данные в массив chart?

    Это в принципе невозможно, axios - для выполнения запросов, а не работы с массивами.

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

    Не сказано ни слова о графике, что он отображает.

    Получение данных для графика осуществляется будто бы с помощью axios - но единственный показанный запрос про другое, там идёт получение данных для выпадающего списка. То есть, должен быть ещё какой-то запрос. Какой? - url, параметры, структура ответа - ничего не известно.

    Далее, "подставить данные" вы планируете в "массив chart" - но как следует из показанного огрызка кода, такого массива нет. Есть chartData. Это он? Или какой-то другой массив? Не знаю что и думать. Что до собственно "подставить" - у массивов есть метод push, неужели вы про него не слышали? Если не слышали - разговаривать тут не о чем, идите учить язык. А где-нибудь через полгодика, не раньше, можно будет и в сторону vue попробовать посмотреть. Если слышали - очевидно, сам по себе push проблемой быть не может, придётся констатировать, что о сути своих затруднений вы решили попросту умолчать.

    Компонент line-chart, который, надо полагать, ответственен за построение графика - что это такое? Едва ли вы его написали сами - это или сторонний компонент, или обёртка над сторонним компонентом. Почему нет ссылки на документацию/github/...? - насколько я понял, график успешно строится, но надо динамически докидывать в него данные, так что сведения о компоненте графика пришлись бы очень кстати. Отслеживает ли он изменения своих параметров? Или может у него есть метод, позволяющий принудительно обновить свой внешний вид? Но нет - и тут никакой информации.

    Вот так.

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

    График строится библиотекой chartkick.js

    есть запрос <...> необходимо подставить значения получаемых менеджеров в имена chartData. То есть в chartData:[{name:[сюда]}]

    Понятно.

    Не надо ничего "подставлять". Делаем отдельные свойства name и data, а chartData будет вычисляемым, причём собирать массив надо только в том случае, когда и name и data будут получены:

    computed: {
      chartData() {
        const { names, data } = this;
        return names && data && data.map((n, i) => ({
          name: names[i],
          data: n,
        }));
      },
    },

    Соответственно, график создаётся только в том случае, если удалось собрать chartData:

    <line-chart v-if="chartData" :data="chartData"></line-chart>

    https://jsfiddle.net/t5dovxL4/
    Ответ написан
    1 комментарий
  • Как узнать, что 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.
    Ответ написан
  • Как отключить валидацию для поля после onBlur с поля?

    0xD34F
    @0xD34F Куратор тега React
    Мне нужно чтобы валидация происходила только после нажатии на кнопку Submit.

    Я так понимаю, вы считаете чтение документации излишним. Это зря - там есть пример того, что вам надо.
    Ответ написан
    Комментировать
  • Где ошибка в маленьком компоненте React. Почему он не работает как в примере?

    0xD34F
    @0xD34F Куратор тега React
    Всё работает как надо. Просто у вас, в отличие от примера из документации, различаются значения полей key и title, поэтому при поиске вы проверяете не те значения, которые отображаете. Замените в методе generateList

    dataList.push({ key, title: key });

    на

    dataList.push({ key, title: node.title });
    Ответ написан