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

    0xD34F
    @0xD34F Куратор тега JavaScript
    const $select = $('select').change(function() {
      const selected = $(':selected', this).get().map(n => n.value);
      const disabled = $(':disabled', this).get().map(n => n.value);
    
      $select
        .not(this)
        .find('option')
        .prop('disabled', function(i, val) {
          return disabled.includes(this.value) ? val : selected.includes(this.value);
        });
    });

    или

    const selects = [...document.querySelectorAll('select')];
    selects.forEach(n => n.addEventListener('change', onChange));
    
    function onChange() {
      const options = [...this];
      const selected = options.filter(n => n.selected).map(n => n.value);
      const disabled = options.filter(n => n.disabled).map(n => n.value);
    
      for (const n of selects.flatMap(m => m === this ? [] : [...m])) {
        n.disabled = disabled.includes(n.value) ? n.disabled : selected.includes(n.value);
      }
    }
    Ответ написан
    Комментировать
  • Как сделать чтобы в input можно было вводить только цифры кратные 100?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelector('input').oninput = function() {
      let val = parseInt(this.value) || 0;
      while (val % 100) {
        val *= 10;
      }
      this.value = val;
    };
    Ответ написан
    Комментировать
  • Замена onmousemove?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавляем pointer-events: none; элементу .bigImage - всё окей, никаких скачков.
    Ответ написан
    Комментировать
  • Как решить задачу с Promise?

    0xD34F
    @0xD34F Куратор тега JavaScript
    В конструкторе создаём promise, делаем его свойством экземпляра, также делаем свойством экземпляра функцию, разрешающую promise; метод then - вызываем метод then у сохранённого promise, пробрасывая ему полученный параметр, результат вызова кладём на место сохранённого promise:

    class deferred {
      constructor() {
        this.promise = new Promise(resolve => this.resolve = resolve);
      }
    
      then(f) {
        this.promise = this.promise.then(f);
      }
    }

    Но вообще, можно добиться того же поведения и без использования promise. Сохраняем в массив все передаваемые в then функции, при вызове resolve перебираем этот массив, вызываем функции, результат вызова предыдущий используем как параметр следующей:

    class deferred {
      constructor() {
        this.callbacks = [];
      }
    
      then(f) {
        this.callbacks.push(f);
      }
    
      resolve(val) {
        this.callbacks.reduce((res, f) => f(res), val);
      }
    }
    Ответ написан
    1 комментарий
  • Как манипулировать svg, который подключен через тэг object?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не получается обратиться к элементу по его id.

    А как вы это делаете? Вдруг неправильно? Почему не показали?

    Просто по id (или с помощью любого другого селектора) обращаться нельзя, у внешних SVG отдельное DOM-дерево, оно доступно через свойство contentDocument соответствующего object'а, т.е.:

    const svgDocument = document.querySelector('object').contentDocument;
    const element = svgDocument.querySelector('здесь указываете нужный id или что там вам надо');
    Ответ написан
    Комментировать
  • Как определить событие клика event.target элемента?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Замените click на mousedown. А то сейчас у вас получается так: нажали на выбранный пункт, фокус с .select-list ушёл, и к тому моменту, когда вы отпускаете кнопку мыши, список уже скрылся, соответственно, клик получается по элементу, который был под списком.
    Ответ написан
    Комментировать
  • Как скачать файлы по url?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Нет, так просто не получится - тянуть файлы со сторонних доменов через a[download] нельзя.

    Можно загрузить файл, перегнать его FileReader'ом в data url, и уже в таком виде подсунуть в ссылку. Как-то так.
    Ответ написан
    3 комментария
  • Как пронумеровать список в textarea?

    0xD34F
    @0xD34F Куратор тега JavaScript
    textareaEl.addEventListener('paste', function() {
      setTimeout(() => {
        this.value = this.value.split('\n').map((n, i) => {
          const line = i + 1;
          return `${line}. ${n.replace(RegExp(`^${line}\\. `), '')}`;
        }).join('\n');
      });
    });
    Ответ написан
    1 комментарий
  • Как эмулировать клик по элементу после того, как он отрендерился?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Элемент - представленный в примере - это FileInput (кликать нужно на него, что бы вызвать диалог выбора файлов)

    Нет, ничего у вас не получится. Этот диалог может быть открыт только в результате настоящих действий пользователя (и то не всех: клик, нажатие клавиши - окей; скролл, движение мыши, вызов контекстного меню - нет), а не их имитации. По крайней мере, в Хроме. В Фаерфоксе имитировать можно.
    Ответ написан
  • Как написать такое регулярное выражение?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не нужны здесь регулярные выражения:

    const imgs = document.querySelectorAll('img[src*="/test/"]');

    UPD. Оказывается, автор вопроса с первого раза не сумел рассказать, чего ему надо. Вынесено из комментариев:

    это не в dom, а в строке

    Всё равно регулярные выражения не нужны. Парсим строку, ищем нужные элементы, получаем их разметку:

    const div = document.createElement('div');
    div.innerHTML = str;
    const imgsStr = ''.concat(...[].map.call(
      div.querySelectorAll('img[src*="/test/"]'),
      n => n.outerHTML
    ));

    или

    const imgsStr = Array
      .from(
        new DOMParser().parseFromString(str, 'text/html').querySelectorAll('img[src*="/test/"]'),
        n => n.outerHTML)
      .join('');

    или

    const imgsStr = Array.prototype.reduce.call(
      document.createRange().createContextualFragment(str).querySelectorAll('img[src*="/test/"]'),
      (acc, n) => acc + n.outerHTML,
      ''
    );

    UPD. Нет, со второго раза тоже не получилось. Всплыли ещё подробности:

    мне нужно удалить из этой строки все картинки, которые...

    Удалить, так удалить:

    const div = document.createElement('div');
    div.innerHTML = str;
    const imgs = div.querySelectorAll('img[src*="/test/"]');
    for (let i = 0; i < imgs.length; i++) {
      imgs[i].outerHTML = '';
    }
    str = div.innerHTML;

    или

    const { body } = new DOMParser().parseFromString(str, 'text/html');
    body.querySelectorAll('img[src*="/test/"]').forEach(n => n.remove());
    str = body.innerHTML;

    или

    const fragment = document.createRange().createContextualFragment(str);
    for (const n of fragment.querySelectorAll('img[src*="/test/"]')) {
      n.parentNode.removeChild(n);
    }
    str = Array.from(fragment.childNodes, n => n.outerHTML || n.nodeValue).join('');
    Ответ написан
    6 комментариев
  • Как определить принадлежность элемента по data value?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function onlyOne({ value, dataset: { group } }) {
      document.querySelectorAll(`[data-group="${group}"]`).forEach(n => {
        n.checked = n.checked && n.value === value;
      });
    }
    Ответ написан
    2 комментария
  • Почему дублируется вывод массива?

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

    Замените

    todoList.forEach(function(element) {
      document.getElementById('out').innerHTML += '<p>'+element+'</p>';
    });

    на

    document.getElementById('out').innerHTML = todoList.map(n => `<p>${n}</p>`).join('');
    Ответ написан
    3 комментария
  • Как удалить определённые html теги из строки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Создать элементы на основе строки, найти и удалить ненужные, получить разметку оставшихся:

    const div = document.createElement('div');
    div.innerHTML = html;
    div.querySelectorAll('a[href*="/test/"]').forEach(n => n.outerHTML = '');
    html = div.innerHTML;

    или

    const { body } = new DOMParser().parseFromString(html, 'text/html');
    body.querySelectorAll('a[href*="/test/"]').forEach(n => n.remove());
    html = body.innerHTML;

    или

    const fragment = document.createRange().createContextualFragment(html);
    fragment.querySelectorAll('a[href*="/test/"]').forEach(n => n.parentNode.removeChild(n));
    html = Array.from(fragment.childNodes, n => n.outerHTML || n.nodeValue).join('');
    Ответ написан
    Комментировать
  • Как сортировать option по атрибуту?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Значения атрибутов - это строки. Надо при сравнении преобразовывать их в числа.

    UPD. Ну и в целом - многословно как-то у вас. Можно же гораздо короче:

    function sort(desc, attr) {
      const select = document.querySelector('#search-sort-field');
      select.append(...Array
        .from(select.children, n => [ n, n.getAttribute(attr) * (desc ? 1 : -1) ])
        .sort((a, b) => a[1] - b[1])
        .map(n => n[0])
      );
    }
    Ответ написан
    1 комментарий
  • Как создать таблицу из массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Куда будем добавлять строки:

    const tbody = document.querySelector('#table tbody');
    
    // или
    
    const [ tbody ] = document.getElementById('table').tBodies;

    Добавляем:

    tbody.innerHTML = arr
      .map(n => `
        <tr>
          <td><a href="${n.link}">${n.city}</a></td>
          <td>${n.country}</td>
        </tr>`)
      .join('');

    или

    for (const n of arr) {
      const tr = tbody.insertRow();
      const a = document.createElement('a');
      a.href = n.link;
      a.text = n.city;
      tr.insertCell().append(a);
      tr.insertCell().textContent = n.country;
    }
    Ответ написан
    Комментировать
  • Добавить/удалить дочерний элемент по клику?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не надо ничего добавлять/удалять - пусть будет одно окно для всех.
    Будете его показывать/скрывать при клике на ячейку. Например.
    Ответ написан
    Комментировать
  • Ошибка в коде при переключении месяца в календаре?

    0xD34F
    @0xD34F Куратор тега JavaScript
    В консоле выдает Uncaught TypeError: next is not a function

    Вы обработчики подключили инлайново, а по умолчанию jsfiddle оборачивает код в window.onload - вот они и отсутствуют в глобальной области видимости. Либо назначайте обработчики с помощью addEventListener; либо в верхней части окна с js кодом есть выпадающее меню, открываете его, находите пункт "load type", выставляете значение "No wrap - bottom of < body >".

    Как выделить при помощи класса текущее число, не выходит
    добавляю...

    Это безумие - currDay является датой, а вы пытаетесь работать с ней как с DOM нодой, classList.add, бред какой-то. Ну и само условие неправильное - год и месяц вы всегда при проверке используете одни и те же, где тут currDay? Должен быть. А проверка числа - ещё одно безумие, вы его сравниваете с объектом даты.

    Кроме того, есть ещё косяк с генерацией элементов календаря, у вас там условие currDay.getMonth() <= month. Представьте, что следующий месяц - январь, год кончается. Что будет с вашим условием? Правильно, оно останется истинным. Навсегда. Лучше сделать так: проверяете равенство, без "меньше", а while заменяете на do-while - тогда числа предыдущего месяца, формально не подходящие под условие, всё равно будут обработаны, так как тело цикла выполняется до проверки условия.

    исправлено
    Ответ написан
    2 комментария
  • Как пронумеровать уже назначенные ID?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelectorAll('.restab').forEach((n, i) => {
      n.id = `responsivetable${++i}`;
    });
    
    // или
    
    for (const [ i, n ] of document.querySelectorAll('.restab').entries()) {
      n.attributes.id.value = 'responsivetable' + (i + 1);
    }
    
    // или
    
    const elems = document.getElementsByClassName('restab');
    for (let i = 0; i < elems.length; i++) {
      elems[i].setAttribute('id', 'responsivetable'.concat(-~i));
    }
    Ответ написан
    Комментировать