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

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelectorAll('tbody > tr').forEach(n => n.parentNode.prepend(n));
    
    // или
    
    const tbody = document.querySelector('tbody');
    tbody.append(...Array.from(tbody.children).reverse());
    
    // или
    
    for (const n of [...document.querySelector('tbody').rows].reverse()) {
      n.parentNode.appendChild(n);
    }
    
    // или
    
    const tbody = document.querySelector('tbody');
    for (let i = tbody.rows.length; i--;) {
      tbody.insertAdjacentElement('beforeend', tbody.rows[i]);
    }
    Ответ написан
    1 комментарий
  • Как работать с массивом в котором есть объект и вложенный массив?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как из этого массива, создать новый массив, и чтобы в нем были значения из массива user, что-то типа такого массива должно получиться res = [5,12,2,22,'5,23',cost,'5',numbers,1,5,33,count,props,4,area,7];

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

    const toArray = val =>
      val instanceof Object
        ? [].concat(...(val instanceof Array
            ? val
            : Object.entries(val)
          ).map(toArray))
        : [ val ];
    
    
    const res = toArray(user);
    Ответ написан
    Комментировать
  • Как реализовать выбор чекбоксов зажатием мыши как в Яндекс Почте?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Зажимайте.

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

    Есть ли способ для снятия чекбоксов таким же способом, если делать по аналогии выходит коряво ?

    вот аналогия и вот почему коряво
    https://codepen.io/sasha1998dmitalex/pen/OZbyYo

    Ну, тут разные варианты есть...

    Можно выставлять чекбокс по левой кнопке, снимать по правой, типа так.

    Можно инвертировать состояние чекбокса по событию mouseover, типа так.

    Можно выставлять чекбоксы по зажатой кнопке мыши, а убирать по зажатой кнопке мыши + зажатой клавише ctrl, типа так.
    Ответ написан
    7 комментариев
  • Как сихронизировать содержимое input и p?

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

    Подходит. Достаточно сразу после назначении обработчика сгенерировать событие самостоятельно - текст скопируется:

    $('input').on('input', function() {
      $('p').text($(this).val());
    }).trigger('input');
    
    // или
    
    const input = document.querySelector('input');
    const p = document.querySelector('p');
    input.addEventListener('input', e => p.textContent = e.target.value);
    input.dispatchEvent(new Event('input'));

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

    что делать, если параграф содержит текст по умолчанию, который должен отображаться пока в поле ввода не начали что-то вводить?

    Проще говоря, когда инпут пустой, надо отображать текст параграфа.

    Текст по умолчанию засунуть в data-атрибут: <p data-default-text="Текст по умолчанию"></p>.

    Если инпут пустой, хватаем значение этого атрибута:

    $('p').text($(this).val() || $('p').data('default-text'));
    
    // или
    
    p.textContent = e.target.value || p.dataset.defaultText
    Ответ написан
    3 комментария
  • Как сгруппировать данные?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const grouped = data
      .reduce((acc, n, i, a) => {
        if (i && n.id === a[i - 1].id + 1) {
          acc[acc.length - 1][1][1] = n.id;
        } else {
          acc.push([ [], [ n.id ] ]);
        }
        acc[acc.length - 1][0].push(n);
        return acc;
      }, [])
      .reduce((acc, n) => {
        acc[n[1].join('-')] = n[0];
        return acc;
      }, {});
    Ответ написан
    1 комментарий
  • Как при изменении значения input отследить что новое число меньше чем введенное ранее в этот же input?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('input').on('input', function() {
      const
        $this = $(this),
        newVal = +$this.val(),
        oldVal = +$this.data('oldVal') || 0;
    
      if (oldVal !== newVal) {
        console.log(`новое ${['больше', 'меньше'][+(oldVal > newVal)]}`);
      }
    
      $this.data('oldVal', newVal);
    });
    Ответ написан
  • Почему не работает калькулятор стоимости?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как я понимаю, при клике я каждый раз вызываю функцию и переменная val опять принимает значение равное нулю?

    Не совсем так. При каждом клике создаётся ещё один экземпляр val, подключаются ещё по одному обработчику клика к .value-btn-plus и .value-btn-minus, сами обработчики срабатывают в порядке подключения, поэтому в value-text последним будет записано значение val, к которому имеет доступ последний же подключенный обработчик - т.е. 0, или что там у вас.

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

    $(document).on('click', '.value-btn-plus, .value-btn-minus', function() {
      const $this = $(this);
      const change = $this.hasClass('value-btn-plus') ? 1 : -1;
    
      $this
        .closest('.input-box')
        .find('.value-text')
        .text((i, text) => Math.max(0, +text + change));
    });

    Или, к чёрту jquery:

    document.addEventListener('click', ({ target: t }) => {
      const change =
        t.classList.contains('value-btn-plus')  ?  1 :
        t.classList.contains('value-btn-minus') ? -1 :
                                                   0;
      if (change) {
        const valueEl = t.closest('.input-box').querySelector('.value-text');
        valueEl.innerText = Math.max(0, +valueEl.innerText + change);
      }
    });
    Ответ написан
    1 комментарий
  • Как проверить, что строка состоит исключительно из цифр?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Во первых - не нужны слэши в начале и конце, во-вторых - надо экранировать обратный слэш:

    new RegExp('^\\d+$')

    Ну или не надо использовать конструктор:

    const numberValidator = str => /^\d+$/.test(str);
    
    // можно и наоборот - вместо проверки, что все символы являются цифрами,
    // убедиться, что отсутствует хотя бы один не являющийся цифрой
    const numberValidator = str => !/\D/.test(str);
    Ответ написан
    Комментировать
  • Как правильно использовать js замыкание в примере?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Про let слышал, но нужно сделать без него

    Не нужно, но варианты есть такие:

    for (var i = 0; i < 10; i++) {
      (function(i) {
        setTimeout(function() { 
          console.log(i);
        }, 1000);
      })(i);
    }

    for (var i = 0; i < 10; i++) {
      setTimeout(function() { 
        console.log(+this);
      }.bind(i), 1000);
    }

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log, 1000, i);
    }

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function(`console.log(${i})`), 1000);
    }

    for (var i = 0; i < 10; i++) {
      setTimeout(function() {
        console.log(10 - i--);
      }, 1000);
    }
    Ответ написан
    Комментировать
  • Автоматическое изменение высоты textarea вверх?

    0xD34F
    @0xD34F Куратор тега CSS
    <div class="container">
      <div class="yellow"></div>
      <textarea></textarea>
    </div>

    .container {
      display: inline-flex;
      width: 200px;
      height: 400px;
      flex-direction: column;
      border: 10px solid red;
    }
    
    .yellow {
      background: yellow;
      flex-grow: 1;
    }
    
    textarea {
      background: #47f;
      line-height: 20px;
      resize: none;
    }

    const textarea = document.querySelector('textarea');
    
    textarea.addEventListener('input', function() {
      const maxHeight = 300;
      const height = 20 * this.value.split('\n').length;
      this.style.height = `${Math.min(height, maxHeight)}px`;
    });
    
    textarea.dispatchEvent(new Event('input'));
    Ответ написан
    4 комментария
  • Найти число на странице, выполнить сложение, и заменить на результат?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('.pups').each(function() {
      this.innerHTML -= -2;
    });
    
    // или
    
    $('.pups').text((i, text) => Number(text) + 2);
    
    // или
    
    document.querySelectorAll('.pups').forEach(n => {
      n.innerText = -~-~n.innerText;
    });
    
    // или
    
    for (const n of document.getElementsByClassName('pups')) {
      n.textContent = parseInt(n.textContent) + 2;
    }
    Ответ написан
    5 комментариев
  • Как при клике остановить видео?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Доступна ли вашему пониманию разница между $(this) и $(this).get(0)?
    Ну, в смысле - $(this).paused всегда будет undefined, а вовсе не true или false.

    Да и не нужно тут дёргать $, всё гораздо проще:

    if (this.paused) {
      this.play();
    } else {
      this.pause();
    }
    
    // или
    
    this[this.paused ? 'play' : 'pause']();
    Ответ написан
    Комментировать
  • Что добавить в счётчик js, который не досчитывает до нужного числа?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Косяков у вас тут целый ворох:
    • Многократные вызовы setInterval - при каждом событии scroll (из-за этого счётчики работают гораздо быстрее, чем запланировано)
    • Общая для всех счётчиков переменная текущего значения (вследствие чего шаг счётчиков вовсе не единица)
    • Неверное условие окончания работы счётчика; или неверное место увеличения текущего значения счётчика - после его перезаписи (отсюда несоответствие заданного и реального максимальных значений счётчиков)
    • После того как все счётчики завершили свою работу вы не прекращаете вызывать count (да, внешне это никак не проявляется, но всё равно - как-то небрежно)


    Как бы мог выглядеть исправленный вариант вашего кода?
    Например, так.

    let intervalId = null;
    
    $(window).on('scroll', function() {
      const scr = $(this).scrollTop();
      const elem = $('.count-wrapper').offset().top;
    
      if (scr > elem - 400 && !intervalId) {
        intervalId = setInterval(count, 10);
      }
    }).scroll();
    
    function count() {
      let countEnd = true;
    
      $('.count span').each(function() {
        const num = $(this).data('num');
        const currNum = $(this).text();
    
        if (currNum < num) {
          $(this).text(+currNum + 1);
          countEnd = false;
        }
      });
    
      if (countEnd) {
        clearInterval(intervalId);
      }
    }

    Ответ написан
    2 комментария
  • Как присвоить класс через n-ное количество одинаковых элементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $elems.not(i => i % N).addClass('xxx');
    
    // или
    
    elems.forEach((n, i) => n.classList.toggle('xxx', !(i % N)));
    
    // или
    
    for (let i = 0; i < elems.length; i += N) {
      elems[i].classList.add('xxx');
    }

    https://jsfiddle.net/5pbf7g92/
    Ответ написан
    Комментировать
  • Как расширить массив на основе другого массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    array2.forEach(n => {
      const obj = array1.find(m => m.name === n.name);
      if (obj) {
        Object.assign(obj, n);
      } else {
        array1.push({ ...n });
      }
    });
    Ответ написан
  • Как при клике на кнопки изменять состояния соответствующих им блоков?

    0xD34F
    @0xD34F Куратор тега JavaScript
    <div class="tab-headers">
      <button data-id="1">69</button>
      <button data-id="2">187</button>
      <button data-id="3">666</button>
    </div>
    
    <div class="tab-contents">
      <div data-id="1">hello, world!!</div>
      <div data-id="2">fuck the world</div>
      <div data-id="3">fuck everything</div>
    </div>

    .tab-contents div {
      display: none;
    }
    
    .tab-contents div.active {
      display: block;
    }
    
    .tab-headers button.active {
      background: red;
      color: white;
    }

    const headerSelector = '.tab-headers button';
    const contentSelector = '.tab-contents div';
    const activeClass = 'active';
    
    
    // делегирование, назначаем обработчик клика один раз для всех кнопок;
    // соответствие кнопок и блоков устанавливаем через равенство атрибутов
    document.addEventListener('click', e => {
      const header = e.target.closest(headerSelector);
      if (header) {
        const { id } = header.dataset;
        const toggle = n => n.classList.toggle(activeClass, id === n.dataset.id);
        document.querySelectorAll(headerSelector).forEach(toggle);
        document.querySelectorAll(contentSelector).forEach(toggle);
      }
    });
    
    // или, назначаем обработчик клика каждой кнопке индивидуально;
    // соответствие кнопок и блоков устанавливаем через равенство индексов
    const headers = document.querySelectorAll(headerSelector);
    const contents = document.querySelectorAll(contentSelector);
    
    headers.forEach(n => n.addEventListener('click', onClick));
    
    function onClick() {
      const index = Array.prototype.indexOf.call(headers, this);
      const toggle = (n, i) => n.classList.toggle(activeClass, i === index);
      headers.forEach(toggle);
      contents.forEach(toggle);
    }
    Ответ написан
    1 комментарий
  • Как заменить каждый второй или четный пробел в строке на ";"?

    0xD34F
    @0xD34F Куратор тега JavaScript
    '1 2 3 4 5 6 7 8 9 0'.replace(/([^ ]+ [^ ]+) /g, '$1;') // "1 2;3 4;5 6;7 8;9 0"
    Ответ написан
  • Почему изначально значение было числом, а потом стало NaN и как это исправить?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Math.sqrt - если аргумент отрицательный, возвращает NaN.

    Как исправить? - не пытаться вычислять корни квадратного уравнения при отрицательном дискриминанте. Кажется, этому учат классе так в 8. Или даже в 7. Ещё не прошли или уже успели забыть?
    Ответ написан
    1 комментарий
  • Как сделать копию элемента при нажатии на кнопку?

    0xD34F
    @0xD34F Куратор тега JavaScript
    <button data-step="-1">Prev</button>
    <button data-step="+1">Next</button>

    $(document).on('click', '[data-step]', function({ target: { dataset: { step } } }) {
      const $wrapper = $(this).closest('.wrapper');
      const $blocks = $wrapper.find('.wrapper-small-block .small-block');
      const $active = $blocks.filter('.active');
      const $nextActive = $blocks.eq(($active.index() + +step) % $blocks.length);
    
      $active.removeClass('active');
      $nextActive.addClass('active');
      $wrapper.find('.preview').html($nextActive.html());
    });
    
    // или
    
    document.addEventListener('click', ({ target: t }) => {
      const { step } = t.dataset;
      if (step) {
        const wrapper = t.closest('.wrapper');
        const blocks = wrapper.querySelector('.wrapper-small-block').children;
        const iActive = Array.prototype.findIndex.call(blocks, n => n.matches('.active'));
        const nextActive = blocks[(iActive + +step + blocks.length) % blocks.length];
    
        blocks[iActive].classList.remove('active');
        nextActive.classList.add('active');
        wrapper.querySelector('.preview').innerHTML = nextActive.innerHTML;
      }
    });
    Ответ написан
    1 комментарий
  • Как убрать из объекта пустые объекты, js?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Собрать новый объект:

    const newData = Object
      .entries(data)
      .reduce((acc, [ k, v ]) => (v.length && (acc[k] = v), acc), {});

    Удалить свойства существующего:

    Object.keys(data).forEach(n => data[n].length || delete data[n]);

    Можно использовать Lodash.

    const newData = _.pickBy(data, n => n.length);
    
    // или
    
    _.each(data, (v, k) => v.length || delete data[k]);
    Ответ написан
    1 комментарий