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

    0xD34F
    @0xD34F Куратор тега JavaScript
    const uidValue = 100;
    
    const { id = 'нет такого элемента' } = document.querySelector(`[uid="${uidValue}"]`) || {};
    Ответ написан
    Комментировать
  • Как осуществить поиск объектов по многоуровнему массиву?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const key = 'prop';
    const val = 1;

    const result = array.flatMap(n => n.filter(m => m[key] === val));
    
    // или
    
    const result = array.reduce((acc, n) => (
      n.forEach(m => m[key] === val && acc.push(m)),
      acc
    ), []);
    
    // или
    
    const result = [];
    
    for (const n of [].concat(...array)) {
      if (n[key] === val) {
        result[result.length] = n;
      }
    }
    Ответ написан
    1 комментарий
  • Jquery ui sortable, как запретить сортировку внутри блока?

    0xD34F
    @0xD34F Куратор тега JavaScript
    let list = null;
    
    $('.connectedSortable').sortable({
      connectWith: '.connectedSortable',
      over(e, ui) {
        list = this;
      },
      stop(e, ui) {
        if (list === this) {
          e.preventDefault();
        }
      },
      receive(e, ui) {
        $(this).append(ui.item);
      },
    });
    Ответ написан
    Комментировать
  • Как выбрать из объекта свойства по массиву?

    0xD34F
    @0xD34F Куратор тега JavaScript
    [...new Set(array.flatMap(n => n.columns).map(n => n.type).filter(n => !defaultTypes.includes(n)))]
    Ответ написан
    3 комментария
  • Как сгруппировать массив объектов по значениям одного из свойств?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const group = (arr, key) =>
      arr.reduce((acc, n) => {
        const k = n[key];
        (acc[k] = acc[k] || []).push(n);
        return acc;
      }, {});
    
    
    const result = Object.values(group(array, 'prop'));

    UPD. Код немного осовременим (на момент публикации ответа оператор ??= отсутствовал); пусть группировать можно будет не только массивы, а любые итерируемые объекты; также добавим возможность задавать имя группы через функцию (на тот случай, если в качестве имён групп должны будут выступать значения вложенных свойств, или не непосредственно значения свойства, а производные от них - например, есть свойство, представляющее дату, а нужен месяц; или есть имя, а нужна его первая буква и т.п.); ну и ещё в качестве значений групп пусть можно будет брать не исходные значения, а что-то другое:

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

    Теперь можно делать так:

    const groupedBySign = group([ 0, 1, 2, 3, -10, -20, -30, 0 ], Math.sign);

    Или так:

    const groupedByParity = group(Array(10).keys(), n => [ 'чётные', 'нечётные' ][n & 1]);

    Или так:

    const chars = group(
      'ABC123?!+',
      n =>
        n.toLowerCase() !== n.toUpperCase() ? 'буква' :
        Number.isInteger(+n)                ? 'цифра' :
                                              'другое'
    );

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

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

    const values = group(document.querySelectorAll('input'), 'name', 'value');

    UPD. Наконец-то дождались, и пяти лет не прошло:

    const result = Object.values(Object.groupBy(array, n => n.prop));
    Ответ написан
    1 комментарий
  • Поэтапная смена блоков jquery + fadeIn?

    0xD34F
    @0xD34F Куратор тега JavaScript
    <div class="block">hello, world!!</div>
    <div class="block">fuck the world</div>
    <div class="block">fuck everything</div>
    <button>click me</button>

    .block {
      display: none;
    }

    const $btn = $('button').click(function() {
      $btn.hide();
    
      $('.block').get().reduceRight((onComplete, el) => {
        return () => $(el).fadeIn(300).delay(1000).fadeOut(300, onComplete);
      }, () => $btn.show())();
    });
    Ответ написан
  • Как передавать правильное значение в функцию?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Можно прицепить значение к элементу в виде атрибута, и читать в обработчике значение атрибута.

    Можно прицепить значение к обработчику в виде this или параметра с помощью bind.

    Можно обернуть назначение обработчика в iife, передавать в него значение параметром.

    Можно с помощью new Function или eval создать обработчик с зашитой внутрь константой.

    Ну и ещё let есть.
    Ответ написан
    Комментировать
  • Как удалить динамически добавляемый класс?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Проблема в том, что код <...> не удаляет класс

    Удаляет. А потом событие продолжает всплывать, и обработчик клика по .js-contacts-form добавляет класс обратно. Останавливайте всплытие в обработчике клика по .detail-work__close; или проверяйте перед добавлением класса, где был клик и не добавляйте класс, если... ну, думаю понятно.
    Ответ написан
    1 комментарий
  • Почему асинхронная функция работает иначе?

    0xD34F
    @0xD34F Куратор тега JavaScript
    выполняются одновременно

    Всё-таки не одновременно. Поток выполнения один, так что... [разводит руками]

    Из-за чего у вас возникла иллюзия "одновременности" - вы результат работы синхронного кода (*) решили получать асинхронно. Вызвали первый раз showText - цикл открутился, замечательно, но демонстрации результата пока не происходит, потому что await. Вот когда поток выполнения освободиться, тогда да. А до того - надо второй вызов showText выполнить. Ну а когда вызовы showText отработают - вот тогда их результаты и показываются, сразу все.

    * Вы можете возразить - ...
    ...ну как же так, у меня там промис используется. А так. Недостаточно написать new Promise, чтобы получить желаемую асинхронность. Проведите небольшой эксперимент - откройте консоль, выполните

    console.log('щас будем создавать промис');
    new Promise(r => {
      console.log('создаём промис');
      setTimeout(() => {
        console.log('так, сейчас дёрнем резолв');
        r();
        console.log('резолв дёрнули');
      });
    }).then(() => console.log('зарезолвились, наконец-то'));
    console.log('промис создан');

    и посмотрите на порядок вывода сообщений. Потом то же самое ещё раз, но без оборачивания резолва в setTimeout. Подумайте. Подумав, можно будет сделать очевидный вывод: а промисы-то - синхронны (да-да, вот так), код внутри промисов выполняется сразу после вызова конструктора. Асинхронным является получение результата.
    Ответ написан
    5 комментариев
  • Как при наведении на блок изменить текст у вышестоящего блока?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const $block = $('.picture__text');
    const text = $block.text();
    const itemSelector = '.pictures__another';

    $(document).on('mouseover mouseout', itemSelector, function(e) {
      $block.text(e.type === 'mouseout' ? text : $(this).text());
    });
    
    // или
    
    $(itemSelector).hover(
      e => $block.text($(e.currentTarget).text()),
      () => $block.text(text)
    );
    Ответ написан
  • Игра застряла в интервале. Как можно решить?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Скорее всего я где-то не обнулил интервал или таймаут.

    Так точно. В методе gameOver. Должно быть. А вот нету. Надо добавить. Правда, это не сильно поможет. Потому что новый интервал создаётся при каждом клике. Так что надо ещё и обработчик клика снимать. Вы снимаете, но не там и не то (тут следует осознать такую вещь - в removeEventListener следует передавать ту же функцию, что передавалась в addEventListener). Исправлено.
    Ответ написан
  • События после динамического добавления контента. Есть ли решение на native JS?

    0xD34F
    @0xD34F Куратор тега JavaScript
    То, что вам нужно, называется делегирование.

    Надо только иметь в виду, что focus не всплывает, поэтому обрабатывать его следует на стадии захвата:

    document.addEventListener('focus', function(e) {
      if (e.target.tagName === 'INPUT') {
        // здесь ваш код
      }
    }, true);

    Или, вместо focus использовать focusin, который всплывает.
    Ответ написан
    Комментировать
  • Как сделать вывод чисел от 1900 до 2016 и выводил в консоль только високосные года?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const getLeapYears = (start, end) => Array
      .from({ length: end - start + 1 }, (n, i) => start + i)
      .filter(n => ((n % 100) && !(n % 4)) || !(n % 400));
    
    console.log(getLeapYears(1888, 2099));
    Ответ написан
    Комментировать
  • Как ограничить максимальное количество одновременно активных элементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const containerSelector = '.choose-buttons';
    const buttonSelector = '.btn';
    const activeClass = 'active';
    const maxActive = 3;

    $(containerSelector).on('click', buttonSelector, function(e) {
      const numActive = $(`${buttonSelector}.${activeClass}`, e.delegateTarget).length;
      const $this = $(this);
    
      if (numActive < maxActive || $this.hasClass(activeClass)) {
        $this.toggleClass(activeClass);
      }
    });
    
    // или
    
    document.querySelectorAll(containerSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });
    
    function onClick(e) {
      const button = e.target.closest(buttonSelector);
      if (button) {
        const active = [...this.querySelectorAll(`${buttonSelector}.${activeClass}`)];
        if (active.length < maxActive || active.includes(button)) {
          button.classList.toggle(activeClass);
        }
      }
    }
    Ответ написан
  • Как удалить класс, если scrollTop === 0?

    0xD34F
    @0xD34F Куратор тега JavaScript
    navbar.classList.toggle('fixed', (lastScroll - scrollTop > 0) && scrollTop);
    Ответ написан
    Комментировать
  • Почему в jQueryUI Datepicker событие onSelect, не видит setDate?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Во-первых,

    событие не срабатывает

    - так не говорят, это безграмотно. События никогда не срабатывают. Срабатывают обработчики событий.

    Во-вторых, давайте зайдём с другой стороны - откуда вы взяли, что установка даты должна иметь своим следствием возникновение события? Если задумаетесь над этим вопросом, то скорее всего обнаружите, что вы себе это нафантазировали. Это несерьёзно.

    Если откроете документацию, то увидите, что там вам никто не обещает вызов onSelect при вызове setDate. Так что формальный ответ на ваш вопрос прост - ну, вот так datepicker устроен. Отвечая на незаданный, но подразумевающийся вами вопрос (как добиться срабатывания onSelect при вызове setDate) - можно соорудить костыль, подменив метод setDate, где будет вызываться исходный метод, а затем выполняться какое-то действие, которое приведёт к вызову onSelect. Например:

    const oldSetDate = $.datepicker._setDate;
    $.datepicker._setDate = function(...args) {
      oldSetDate.apply(this, args);
      setTimeout(() => args[0].input.find('.ui-datepicker-current-day').click());
    };

    https://jsfiddle.net/7zge4jv9/1/

    UPD. Заявка на данный функционал появилась ещё семь лет назад, но так ничего и не сделали. И не сделают уже, надо полагать.
    Ответ написан
  • Как сделать счетчик со сменой цвета активного элемента по клику?

    0xD34F
    @0xD34F Куратор тега JavaScript
    p.process-block__stage-number.active I
    p.process-block__stage-number II
    p.process-block__stage-number III
    p.process-block__stage-number IV
    
    button.process-block__btn(data-change=-1)
      span
        b prev
    button.process-block__btn(data-change=+1)
      span
        b next

    document.addEventListener('click', function(e) {
      const button = e.target.closest('[data-change]');
      if (button) {
        const blocks = [...document.querySelectorAll('.process-block__stage-number')];
        let active = blocks.findIndex(n => n.classList.contains('active'));
    
        blocks[active].classList.remove('active');
        active = Math.max(0, Math.min(blocks.length - 1, active + +button.dataset.change));
        blocks[active].classList.add('active');
      }
    });

    https://codepen.io/anon/pen/bZryZQ?editors=1010
    Ответ написан
    3 комментария
  • Как сделать promise-заглушку вместо ajax-запроса к серверу?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const getData = (delay = 1000) =>
      new Promise(r => setTimeout(r, delay, сюда подставляете данные));
    Ответ написан
    Комментировать
  • Как задать фон первому элементу меню?

    0xD34F
    @0xD34F Куратор тега JavaScript
    проблема в том, что при клике по какому-либо элементу подМЕНЮ, первый, элемент который задавался по умолчанию не сбрасывает стиль

    Всё-таки стиль сбрасывается. А потом снова устанавливается. Потому что из-за всплытия события срабатывает обработчик клика основного меню. Отменяйте всплытие в обработчике клика подменю, и всё будет OK:

    $('ul#topnav li span a').click(function(e) {
      e.stopPropagation();
      ...
    Ответ написан
    1 комментарий
  • Почему при клике обработчик события срабатывает два раза?

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

    Какие есть варианты исправить ситуацию:
    1. Вешайте обработчик клика на инпут вместо лейбла
    2. Проверяйте целевой элемент, если не инпут - ничего делать не надо
    3. Обрабатывайте вместо click событие change
    Ответ написан
    Комментировать