Задать вопрос
  • Почему не получается добавить ещё одно событие?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Во-первых, события не добавляют - так говорить безграмотно. Добавляют обработчики событий.

    Во-вторых:

    Если зарегистрировано несколько одинаковых EventListener на одном EventTarget с одинаковыми параметрами, дублирующиеся обработчики игнорируются.
    Ответ написан
    Комментировать
  • Как правильно обработать клик на любой дочерний элемент?

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

    const container = document.querySelector('#element');
    const itemSelector = '.someclass';
    const key = 'id';
    const attr = `data-${key}`;
    const attrSelector = `[${attr}]`;

    Слушаем клики непосредственно на элементах:

    container.querySelectorAll(itemSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, function(e) {
      e.preventDefault();
      let el = this;
      while (!(el = el.parentNode).hasAttribute(attr)) ;
      console.log(el.getAttribute(attr));
    });

    Или, на обладателях data-атрибута:

    container.querySelectorAll(attrSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });
    
    function onClick(e) {
      if (e.target.matches(itemSelector)) {
        e.preventDefault();
        console.log(e.currentTarget.attributes[attr].value);
      }
    }

    Или, на контейнере:

    container.addEventListener('click', e => {
      const item = e.target.closest(itemSelector);
      if (item) {
        e.preventDefault();
        console.log(item.closest(attrSelector).dataset[key]);
      }
    });
    Ответ написан
    Комментировать
  • Vuelidate - как проверять 2 взаимозависимых чекбокса?

    0xD34F
    @0xD34F Куратор тега Vue.js
    По одному работает, если отметить оба, то "Error in v-on handler: "TypeError: Cannot convert undefined or null to object"

    Что возвращает validations, если оба значения true? Ничего. Пусть всегда будет объект:

    validations() {
      return {
        life: this.property ? {} : { required: v => v },
        property: this.life ? {} : { required: v => v },
      };
    },

    <div>STATUS: {{ $v.$invalid ? 'ЖОПА' : 'OK' }}</div>
    Ответ написан
    1 комментарий
  • Как сортировать массив объектов по их паренту?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function sort(arr) {
      const obj = Object.fromEntries(arr.map(n => [ n.parent, n ]));
      const sorted = [];
    
      for (let item = obj['null']; item; item = obj[item.id]) {
        sorted.push(item);
      }
    
      return sorted;
    }

    или

    function sort(arr, parent = null) {
      const item = arr.find(n => n.parent === parent);
      return item
        ? [ item, ...sort(arr, item.id) ]
        : [];
    }
    Ответ написан
    Комментировать
  • Как конвертировать формат времени?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const formatDateStr = str =>
      new Date(str.split(' GMT', 1)[0])
        .toLocaleDateString('ru-RU')
        .split('.')
        .reverse()
        .join(', ');

    или

    const formatDateStr = function(str) {
      const [ , month, day, year ] = str.match(/(\S+) (\d+) (\d+)/);
      return [ year, this[month], day.padStart(2, 0) ].join(', ');
    }.bind(Object.fromEntries(Array.from({ length: 12 }, (_, i) => [
      new Date(0, i).toLocaleString('en', { month: 'short' }),
      `${i + 1}`.padStart(2, 0)
    ])));
    Ответ написан
    Комментировать
  • Как найти в тексте все таймкоды?

    0xD34F
    @0xD34F
    $newText = preg_replace('~\b\d+:\d+\b~', '<a href="#">$0</a>', $text);
    Ответ написан
    2 комментария
  • Как проверить содержит ли в массив массивов нужный мне массив?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Коротко:

    const includes = (arrs, search) =>
      arrs.some(arr => arr.length === search.length && arr.every((n, i) => n === search[i]));

    Длинно:

    function includes(arrs, search) {
    COMPARE_ARRAYS:
      for (const arr of arrs) {
        if (arr.length === search.length) {
          for (const [ i, n ] of arr.entries()) {
            if (!Object.is(n, search[i])) {
              continue COMPARE_ARRAYS;
            }
          }
    
          return true;
        }
      }
    
      return false;
    }
    Ответ написан
    4 комментария
  • Как вывести массив объектов в виде таблицы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Собираем массив столбцов:

    const columns = [ '#', ...new Set(persons.flatMap(Object.keys)) ];
    
    // или
    
    const columns = [ '#' ].concat(Object.keys(Object.assign({}, ...persons)));

    Собираем разметку таблицы:

    document.body.insertAdjacentHTML('beforeend', `
      <table>
        <thead>
          <tr>${columns.map(col => `
            <th>${col}</th>`).join('')}
          </tr>
        </thead>
        <tbody>${persons.map((person, i) => `
          <tr>${columns.map((col, j) => `
            <td>${j ? person[col] ?? '-' : i}</td>`).join('')}
          </tr>`).join('')}
        </tbody>
      </table>
    `);

    Или, создаём элементы напрямую:

    const table = document.createElement('table');
    
    table.createTHead().insertRow().append(...columns.reduce((acc, col) => (
      (acc[acc.length] = document.createElement('th')).textContent = col,
      acc
    ), []));
    
    persons.forEach(function(person, i) {
      columns.forEach(function(col, j) {
        this.insertCell().textContent = j ? person[col] ?? '-' : i;
      }, this.insertRow());
    }, table.createTBody());
    
    document.body.append(table);
    Ответ написан
    2 комментария
  • Как изменить input value vue.js компонента из другого js?

    0xD34F
    @0xD34F Куратор тега Vue.js
    $addres.val("Мои данные").change();

    Во-первых - события jquery и нативные не являются взаимозаменяемыми. Само собой, про первые Vue не в курсе.

    Во-вторых - по умолчанию Vue слушает событие input (change - это если v-model используется с модификатором lazy).

    Так что попробуйте заменить .change() на [0].dispatchEvent(new Event('input')).
    Ответ написан
    Комментировать
  • Как получить путь к каталогу из пути к файлу?

    0xD34F
    @0xD34F Куратор тега Регулярные выражения
    Получаем .+(?=\/[^\/]+), или удаляем \/[^\/]+$.
    Ответ написан
    Комментировать
  • Как заставить функцию ждать выполнения события click?

    0xD34F
    @0xD34F Куратор тега JavaScript
    async function Func() {
      console.log('START');
    
      await new Promise(r => {
        $('div').one('click', () => (console.log('CLICK'), r()));
      });
    
      console.log('END');
    }
    Ответ написан
    Комментировать
  • Как найти значение по ключу в объекте с неизвестной глубиной вложенности?

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

    const find = (data, test, key) =>
      test(key, data)
        ? data
        : data === Object(data)
          ? Object.entries(data).reduce((found, n) =>
              found !== null ? found : find(n[1], test, n[0])
            , null)
          : null;

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

    function find(data, test) {
      for (const stack = [ [ , data ] ]; stack.length;) {
        const [ k, v ] = stack.pop();
        if (test(k, v)) {
          return v;
        } else if (v instanceof Object) {
          stack.push(...Object.entries(v).reverse());
        }
      }
    
      return null;
    }

    Ищем:

    const value = find(вложенный_объект, k => k === 'ключ');
    Ответ написан
    Комментировать
  • Почему не срабатывает функция при нажатии?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Брехня, всё срабатывает.

    Бегом гуглить, что такое всплытие событий.

    Надо его останавливать:

    const $section = $('.section').on('click', () => $section.addClass('opened'));
    $section.find('.close').on('click', e => {
      e.stopPropagation();
      $section.removeClass('opened');
    });
    
    // или
    
    const section = document.querySelector('.section');
    section.addEventListener('click', () => section.classList.add('opened'));
    section.querySelector('.close').addEventListener('click', e => (
      e.stopPropagation(),
      section.classList.remove('opened')
    ));

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

    const $section = $('section').click(e => {
      $section.toggleClass('opened', !$(e.target).is('.close'));
    });
    
    // или
    
    document.querySelector('.section').addEventListener('click', e => {
      e.currentTarget.classList.toggle('opened', !e.target.matches('.close'));
    });
    Ответ написан
    1 комментарий
  • Как сгруппировать массив объектов по двум свойствам?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Object.values(orders.reduce((acc, n) => {
      const date = n.date.split(' ')[0];
    
      ((acc[date] ??= {
        date,
        documents: {},
      }).documents[n.docTypesName] ??= {
        date: n.date,
        docId: n.docId,
        docTypesName: n.docTypesName,
        products: [],
      }).products.push({
        name: n.name,
        price: n.price,
        image: n.image,
        qunatity: n.quantity,
      });
    
      return acc;
    }, {})).map(n => (n.documents = Object.values(n.documents), n))
    Ответ написан
  • Как избавиться от утечек памяти при самовызове промисов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    С каждым "неудачным" вызовом функции camel у вас добавляется ещё один промис, ждущий разрешения. 10 "неудачных" вызовов - 10 промисов в режиме ожидания. 1000 попыток - 1000 промисов. И т.д. Каждый съедает немного памяти.

    Не нужно вам тут никакого "самовызова". Вместо рекурсии сделайте цикл:

    async function test() {
      let result = null;
    
      do {
        result = await camel() || await new Promise(r => setTimeout(r, 1000));
      } while (!result);
    
      return result;
    }
    Ответ написан
    3 комментария
  • Как в Swiper Slider реализовать Lazy Load на React?

    0xD34F
    @0xD34F Куратор тега React
    Надо импортировать модуль Lazy: import { Lazy } from 'swiper';. Этого вы не сделали.

    Подключить его: SwiperCore.use([ Lazy ]);. Этого вы не сделали.

    Экземпляру слайдера указать, что необходима ленивая загрузка: <Swiper lazy={true}>. Этого вы не сделали.

    Изображениям добавить класс swiper-lazy, атрибут src заменить на data-src. Ну, хоть это у вас есть.
    Ответ написан
    1 комментарий
  • Как определить дату, отстоящую от другой даты на определённое количество дней?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const days = 46330;
    const date = new Date();
    date.setDate(date.getDate() + days);
    const dateStr = date.toLocaleDateString('ru-RU', {
      day: 'numeric',
      month: 'short',
      year: 'numeric',
    });
    
    console.log(dateStr);
    Ответ написан
    Комментировать
  • Почему мои вопросы блокируют?

    0xD34F
    @0xD34F
    Очевидно же - они правила нарушают. Будете продолжать в том же духе - заблокируют не только вопросы, но и вас самого. Так что на вашем месте, я бы сейчас перешел по ссылке и ознакомился с тем, как тут принято себя вести.

    И, кстати, здесь не форум.
    Ответ написан
    Комментировать
  • Как заставить работать пагинацию?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Пусть в сторе кроме собственно массива данных также хранятся текущая страница и общее количество страниц; действие fetchCharacters - пусть загружает не дефолтную первую страницу, а какую будет указано:

    state: {
      characters: [],
      page: 0,
      pages: 0,
    },
    mutations: {
      setCharacters: (state, { characters, pages, page }) =>
        Object.assign(state, { characters, pages, page }),
    },
    actions: {
      async fetchCharacters({ commit }, page = 1) {
        try {
          const { data: { info, results } } = await axios.get(`${BASE_URL}?page=${page}`);
          commit('setCharacters', {
            page,
            pages: info.pages,
            characters: results,
          });
        } catch (e) {
          console.error(e);
        }
      },
    },

    В компоненте, где используется пагинация, делаем вычисляемое свойство, которое будет отвечать за текущую страницу - геттер достаёт значение из стора, сеттер вызывает действие fetchCharacters:

    computed: {
      currentPage: {
        get() {
          return this.$store.state.page;
        },
        set(page) {
          this.$store.dispatch('fetchCharacters', page);
        },
      },
    },

    Привязываем это вычисляемое свойство к экземпляру компонента пагинации:

    <el-pagination
      v-model:current-page="currentPage"
      :page-count="$store.state.pages"
      layout="prev, pager, next"
      background
    />

    https://jsfiddle.net/qbjc9onm/
    Ответ написан
    Комментировать
  • Как превратить вложенный массив в плоский?

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

    const flatten = arr => [].concat(...arr.map(n => Array.isArray(n) ? flatten(n) : n));
    
    // или
    
    function flatten(arr) {
      const result = [];
    
      for (const n of arr) {
        if (n?.constructor === Array) {
          [].push.apply(result, flatten(n));
        } else {
          result.push(n);
        }
      }
    
      return result;
    }

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

    function flatten(arr) {
      const result = [];
      const stack = [];
    
      for (let i = 0; i < arr.length || stack.length; i++) {
        if (i === arr.length) {
          [ i, arr ] = stack.pop();
        } else if (arr[i] instanceof Array) {
          stack.push([ i, arr ]);
          [ i, arr ] = [ -1, arr[i] ];
        } else {
          result.push(arr[i]);
        }
      }
      
      return result;
    }
    
    // или
    
    function flatten([...arr]) {
      for (let i = 0; i < arr.length; i++) {
        const n = arr[i];
        if (n?.[Symbol.iterator] && typeof n !== 'string') {
          arr.splice(i--, 1, ...n);
        }
      }
    
      return arr;
    }
    Ответ написан
    Комментировать