Ответы пользователя по тегу JavaScript
  • Как определить selected option?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('#sel1').change(function() {
      const min = +$(this).val();
    
      $('#sel2')
        .val((i, v) => Math.max(v, min))
        .children()
        .show()
        .filter((i, n) => +n.value < min)
        .hide();
    }).change();

    или

    const select1 = document.querySelector('#sel1');
    const select2 = document.querySelector('#sel2');
    
    select1.addEventListener('change', e => {
      const min = +e.target.value;
      select2.value = Math.max(select2.value, min);
      for (const n of select2.children) {
        n.hidden = +n.value < min;
      }
    });
    
    select1.dispatchEvent(new Event('change'));
    Ответ написан
  • Возможно ли посчитать количеств элементов в одном ряду?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const count = Array.prototype.reduce.call(
      document.querySelectorAll('.col'),
      (acc, n, i, a) => (
        n.offsetTop !== a[i - 1]?.offsetTop && acc.push(0),
        acc[acc.length - 1]++,
        acc
      ),
      []
    );
    Ответ написан
    Комментировать
  • Как удалять предыдущий DOM элемент при появлении нового элемента контейнера?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вместо filterInput.addEventListener('keyup',... пусть будет

    filterInput.addEventListener('input', function() {
      const value = this.value.toLowerCase();
    
      filterResult.innerHTML = resultArr
        .filter(n => n.toLowerCase().includes(value))
        .map(n => `<li>${n}</li>`)
        .join('');
    });

    или

    filterInput.addEventListener('input', e => {
      const value = e.target.value.toLowerCase();
    
      filterResult.replaceChildren(...resultArr.reduce((acc, n) => {
        if (n.toLowerCase().indexOf(value) !== -1) {
          (acc[acc.length] = document.createElement('li')).textContent = n;
        }
        return acc;
      }, []));
    });
    Ответ написан
    2 комментария
  • Как узнать, есть ли в массивах одинаковые значения?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Делаем просто, ровно то, что спрошено в вопросе:

    arr1.filter(n => arr2.includes(n)).length !== 0
    
    // или
    
    arr1.some(Set.prototype.has.bind(new Set(arr2)))
    
    // или
    
    new Set(arr1).size + new Set(arr2).size > new Set([ ...arr1, ...arr2 ]).size

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

    function intersection(data1, data2, key = n => n) {
      const getKey = key instanceof Function ? key : n => n[key];
      const keys = new Set(Array.from(data2, getKey));
      const result = [];
    
      for (const n of data1) {
        if (keys.has(getKey(n))) {
          result.push(n);
        }
      }
    
      return result;
    }
    
    
    // как применять в вашем случае
    !!intersection(arr1, arr2).length
    
    // другие примеры использования
    intersection(Array(5).keys(), Array(3).keys()) // [0, 1, 2]
    intersection('abcDe', 'cd', n => n.toLowerCase()) // ['c', 'D']
    intersection([{id: 1}, {id: 2}, {id: 3}], [{id: 2}, {id: 4}], 'id') // [{id: 2}]
    Ответ написан
    1 комментарий
  • Как сделать заблокированный button если checkbox пустой?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сначала пара замечаний:
    1. В select'е первому option'у добавьте атрибут value="". Соответственно, проверять надо будет value на пустоту, а не равенство тексту. Это и проще, и код не придётся переписывать, если вдруг завтра вам потребуется изменить текст по умолчанию.
    2. Не забывайте про всплытие событий. Обработчик события input можно добавлять один раз - общему предку (у вас это .element), а не каждому элементу индивидуально. Не придётся вписывать новый обработчик или удалять существующий, если изменится количество элементов в форме.


    Ну и собственно блокировка кнопки:

    button.disabled = ![
      inputMail.value,
      inputPhone.value,
      select.value,
      checkbox.checked,
    ].every(Boolean);

    https://jsfiddle.net/rmduyegf/
    Ответ написан
    Комментировать
  • Как вытащить из строки слово, заключенное в скобки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.match(/(?<=\{{2}).*?(?=\}{2})/g) ?? []
    
    // или
    
    Array.from(str.matchAll(/\{\{(.*?)\}\}/g), n => n[1])
    Ответ написан
    3 комментария
  • Как с помощью js удалить слова item и items?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где удалять: const className = 'cart__counter';.

    Как удалять:

    const remove = el => el.innerText = parseInt(el.innerText);
    // или
    const remove = el => el.innerHTML = el.innerHTML.match(/\d+/)[0];
    // или
    const remove = el => el.textContent = el.textContent.replace(/\D/g, '');
    // или
    const remove = el => [ el.firstChild.data ] = el.firstChild.data.split(' ');
    // или
    const remove = el => el.childNodes[0].nodeValue = parseFloat(el.childNodes[0].nodeValue);

    Удаляем:

    document.querySelectorAll(`.${className}`).forEach(remove);
    
    // или
    
    for (const n of document.getElementsByClassName(className)) {
      remove(n);
    }

    Но вообще, это конечно костыль. Вы бы посмотрели - может есть возможность настроить корзину так, чтобы лишние надписи изначально не выводились.
    Ответ написан
    1 комментарий
  • Как оптимизировать удаление параметров из url query string?

    0xD34F
    @0xD34F Куратор тега JavaScript
    [...params.keys()].forEach(n => whiteList.includes(n) || params.delete(n));
    Ответ написан
    6 комментариев
  • Как рекурсивно удалить текстовые узлы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Во-первых - вы передаёте в функцию строку и используете её в качестве селектора, непонятно, как вы намерены делать это рекурсивно? Пусть функция сразу получает элемент.

    Во-вторых - вы обходите childNodes, который представляет собой динамический NodeList и одновременно пытаетесь его модифицировать. Удаляя один элемент, вы пропускаете следующий - т.е., если несколько текстовых элементов идут подряд, то удалён будет только каждый второй; а те нетекстовые элементы, которые расположены после текстовых, тут никакой рекурсии не случится, их содержимое вообще никак не будет обработано. Надо делать копию childNodes, и перебирать её. Или вместо for-of использовать цикл со счётчиком, при удалении элемента счётчик увеличиваться не должен.

    В-третьих - какой-то бред с nextElementSibling, не знаю, как это комментировать. Надо было просто вызвать функцию, передав ей текущий элемент.

    В четвёртых.
    const deleteTextNodes = el =>
      el.nodeType === Node.TEXT_NODE
        ? el.remove()
        : [...el.childNodes].forEach(deleteTextNodes);
    Ответ написан
  • Как найти URL среди списка URL, если могут присутствовать динамические параметры?

    0xD34F
    @0xD34F Куратор тега JavaScript
    urlList.findIndex(n => RegExp(`^${n.replace(/:\w+/g, '\\w+')}$`).test(url))
    Ответ написан
    Комментировать
  • Как сделать выборку по шансу?

    0xD34F
    @0xD34F Куратор тега JavaScript
    if (total_sum >= rand) {

    Равенство лишнее, верхняя граница не должна учитываться. Из-за этого у вас перекос в результатах.

    Ну и конечно можно всё это записать гораздо короче:

    function getRandom(arr, key) {
      const rand = Math.random() * arr.reduce((acc, n) => acc + n[key], 0);
      let sum = 0;
      return arr.find(n => (sum += n[key]) > rand);
    }
    
    
    const obj = getRandom(data, 'weight');
    Ответ написан
    Комментировать
  • Как при клике на span вставлять его содержимое в инпут?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Перебираем предыдущие элементы относительно кликнутого, пока не встретится подходящий:

    document.addEventListener('click', ({ target: t }) => {
      if (t.matches('.oldValue')) {
        let input = t;
        while (!(input = input.previousElementSibling).matches('.value')) ;
        input.value = t.textContent;
      }
    });

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

    const inputs = document.querySelectorAll('.value');
    const spans = [...document.querySelectorAll('.oldValue')];
    const onClick = ({ target: t }) => inputs[spans.indexOf(t)].value = t.innerText;
    spans.forEach(n => n.addEventListener('click', onClick));

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

    document.addEventListener('click', ({ target: t }) => {
      if (t.classList.contains('oldValue')) {
        t.closest('селектор общей обёртки').querySelector('.value').value = t.innerHTML;
      }
    });
    Ответ написан
  • Почему появляются запятые после отработки цикла?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Потому что при преобразовании массива в строку, согласно спецификации, используется метод join. Который по умолчанию в качестве разделителя (опять же, согласно спецификации) использует запятую.

    "Как убрать" - очевидно, вызывать join самостоятельно, указывая пустую строку.
    Ответ написан
    Комментировать
  • Как обрабатывать клик на одном элементе только после клика по другому?

    0xD34F
    @0xD34F Куратор тега JavaScript
    let isBtn1Clicked = false;
    
    button1.addEventListener('click', () => isBtn1Clicked = true);
    button2.addEventListener('click', () => {
      if (isBtn1Clicked) {
        // ...
      }
    });

    или

    button1.addEventListener('click', e => e.target.classList.add('clicked'));
    button2.addEventListener('click', () => {
      if (button1.classList.contains('clicked')) {
        // ...
      }
    });

    или

    button2.disabled = true;
    
    button1.addEventListener('click', () => button2.disabled = false);
    button2.addEventListener('click', () => {
      // ...
    });

    или

    button2.hidden = true;
    
    button1.addEventListener('click', () => button2.hidden = false);
    button2.addEventListener('click', () => {
      // ...
    });

    или

    button1.addEventListener('click', () => {
      button2.addEventListener('click', () => {
        // ...
      });
    }, { once: true });
    Ответ написан
    1 комментарий
  • JS. Как из массива объектов сделать объект с параметрами из свойств?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const obj = Object.fromEntries(arr.map(n => [ n.name, n.number ]));
    // или
    const obj = arr.reduce((acc, n) => (acc[n.name] = n.number, acc), {});
    // или
    const obj = Object.assign({}, ...arr.map(n => ({ [n.name]: n.number })));

    Или, в более общем виде:

    function toObj(data, key, val = n => n) {
      const getKey = key instanceof Function ? key : n => n[key];
      const getVal = val instanceof Function ? val : n => n[val];
      const obj = {};
    
      for (const n of data) {
        obj[getKey(n)] = getVal(n);
      }
    
      return obj;
    }

    Пользоваться этим можно так (ваш случай):

    const obj = toObj(arr, 'name', 'number');
    // {Kolya: '5', Olga: '10'}

    А можно так:

    const charCodes = toObj('abc', n => n.charCodeAt());
    // {97: 'a', 98: 'b', 99: 'c'}

    И даже так тоже можно:

    <input name="xxx" value="69">
    <input name="yyy" value="187">
    <input name="zzz" value="666">

    const inputValues = toObj(document.querySelectorAll('input'), 'name', 'value');
    // {xxx: '69', yyy: '187', zzz: '666'}
    Ответ написан
    3 комментария
  • Как вывести сумму значений 2 select?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const prices = {
      'Москва': 100,
      'Санкт-Петербург': 200,
      'Казань': 300,
    };
    
    $('form').on('change', function() {
      const [ city1, city2 ] = $('select', this).get().map(n => n.value);
    
      const price = city1 === city2
        ? prices[city1]
        : prices[city1] + prices[city2];
    
      $('input', this).val(price);
    }).change();
    Ответ написан
    Комментировать
  • Как сделать последовательную анимацию блоков на чистом Js?

    0xD34F
    @0xD34F Куратор тега JavaScript
    button.addEventListener('click', async () => {
      for (const el of cards) {
        await el.animate([
          { transform: 'rotateX(0deg)' },
          { transform: 'rotateX(180deg)' },
        ], {
          duration: 1000,
          easing: 'linear',
          fill: 'forwards',
        }).finished;
      }
    });
    Ответ написан
    6 комментариев
  • Как получить только первый дочерний элемент в вложенности (event.target) без дополнительных условий?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где кнопки находятся, что за кнопки, что делать при клике:

    const container = document.querySelector('.buttons');
    const buttonSelector = '.button';
    const onButtonClick = button => console.log(button.id);

    Делегирование, обработчик клика добавляем контейнеру с кнопками. Пробуем найти у элемента, где случился клик, предка, который является кнопкой:

    container.addEventListener('click', e => {
      const button = e.target.closest(buttonSelector);
      if (button) {
        onButtonClick(button);
      }
    });

    Или, добавляем обработчик клика каждой кнопке индивидуально. В этом случае кнопка будет доступна без каких-либо дополнительных телодвижений, т.к. ссылка на элемент, к которому подключен обработчик события, является свойством объекта события:

    container.querySelectorAll(buttonSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, e => onButtonClick(e.currentTarget));
    Ответ написан
    Комментировать
  • Как уменьшить шаг в tooltip nouislider?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Никак.

    Например если число 200000

    А ширина экрана в пикселях - 2000, например. На два порядка меньше. Каким образом, по-вашему, одного пикселя должно хватить для отображения сотни различных положений ползунка?
    Ответ написан