Задать вопрос
  • Как реализовать динамическое сравнение массивов на основе чекбоксов?

    0xD34F
    @0xD34F Куратор тега React
    Для хранения выбранных значений можно использовать объект, имена свойств которого соответствуют индексам групп чекбоксов, а значения будут массивами значений, соответствующих чекбоксам выбранной группы (вперемешку, без разделения по конкретным чекбоксам). В обработчике клика чекбокса в зависимости от его checked дописываете или выбрасываете значения группы.

    Для вывода значений, выбранных во всех группах берёте массив выбранных значений любой группы, и фильтруете его с условием, что элемент массива присутствует во всех массивах выбранных значений групп.

    Выглядеть это может так, например:

    class App extends React.Component {
      state = {
        selected: {},
        groups: [
          [
            [ 'value_a1', 'value_a2', 'value_a3' ],
            [ 'value_b1', 'value_b2', 'value_b3' ],
            [ 'value_c1', 'value_c2', 'value_c3' ],
          ],
          [
            [ 'value_a1', 'value_b1', 'value_c1' ],
            [ 'value_a2', 'value_b2', 'value_c2' ],
            [ 'value_a3', 'value_b3', 'value_c3' ],
          ],
        ],
      }
    
      onChange = (e, groupIndex, itemIndex) => {
        const selectedGroup = this.state.groups[groupIndex][itemIndex];
        const selectedInfo = this.state.selected[groupIndex] || [];
    
        this.setState({
          selected: {
            ...this.state.selected,
            [groupIndex]: e.target.checked
              ? selectedInfo.concat(selectedGroup)
              : selectedInfo.filter(n => !selectedGroup.includes(n))
          },
        });
      }
    
      render() {
        const { selected, groups } = this.state;
        const matched = (selected[0] || []).filter(n => {
          return groups.every((group, i) => (selected[i] || []).includes(n));
        });
    
        return (
          <div>
            {groups.map((group, groupIndex) => (
              <ul>
                {group.map((item, itemIndex) => (
                  <li>
                    <input
                      type="checkbox"
                      onChange={(e) => this.onChange(e, groupIndex, itemIndex)}
                    />
                    {item.map(val => <span>{val}</span>)}
                  </li>
                ))}
              </ul>
            ))}
            <div>
              {matched.map(val => <span>{val}</span>)}
            </div>
          </div>
        );
      }
    }
    Ответ написан
    1 комментарий
  • Как во Vue получать номер страницы, на которой нахожусь и запускать в зависимости от этого анимации?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Устанавливайте transition'у значение параметра name в зависимости от текущего маршрута:

    computed: {
      routeAnimation() {
        return что-то, зависящее от this.$route;
      },
    },

    <transition :name="routeAnimation">
      <div :key="routeAnimation"></div>
    </transition>

    https://jsfiddle.net/wac86yo0/1/
    Ответ написан
    Комментировать
  • Как встроить svg, используя Renderer2?

    0xD34F
    @0xD34F
    При создании SVG элементов надо указывать пространство имён. Т.е., замените
    this.renderer.createElement('svg');
    на
    this.renderer.createElement('svg', 'svg');

    Ну и соответственно
    this.renderer.createElement('circle');
    на
    this.renderer.createElement('circle', 'svg');
    Ответ написан
    2 комментария
  • Почему срабатывает EventEmitter?

    0xD34F
    @0xD34F
    Мне этот механизм не понятен.

    Обработка события selectedColorChange осуществляется автоматически - поскольку задана двусторонняя привязка для свойства selectedColor.

    Как это можно понять, это документированная возможность?

    Документированная.
    Ответ написан
    2 комментария
  • В чем ошибка reactJS JSON?

    0xD34F
    @0xD34F Куратор тега React
    Кривой json - проверьте кавычки вокруг ключа во второй строке.
    Компонент Comment - судя по имени и по коду, он должен рендерить один комментарий, а у вас массив. Наверное, тут нужен ещё один компонент - список комментариев.

    const Comment = ({ general, job, address }) => (
      <li>
        <div>first name: {general.firstName}</div>
        <div>last name: {general.lastName}</div>
        <div>company: {job.company}</div>
        <div>address: {address.country}, {address.city}, {address.street}</div>
      </li>
    );
    
    const CommentList = ({ comments }) => (
      <ul>
        {comments.map(n => <Comment {...n} />)}
      </ul>
    );
    
    ReactDOM.render(
      <CommentList comments={comments} />,
      document.getElementById('root')
    );
    Ответ написан
    Комментировать
  • Как сделать скрывающиеся блоки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('.button').click(function() {
      const $this = $(this);
      const $content = $this.closest('.item').find('.block');
    
      if ($this.hasClass('closed')) {
        $this.removeClass('closed').html('Скрыть &#8593;');
        $content.slideDown();
      } else {
        $this.addClass('closed').html('Показать &#8595;');
        $content.slideUp();
      }
    }).click();
    Ответ написан
    1 комментарий
  • Как реализовать кастомные радиобаттоны на react?

    0xD34F
    @0xD34F Куратор тега React
    Приходит массив объектов, и в объекте надо менять свойство enabled: true
    соответственно в другом объекте это свойство нужно заменить на false.

    А зачем такие сложности?

    Выбрана может быть только одна радиокнопка - вот и храните отдельно индекс/id/... выбранного элемента вместо enabled у каждого.
    Ответ написан
    Комментировать
  • Как при поиске изменить цвет у части слова?

    0xD34F
    @0xD34F Куратор тега React
    .highlighted {
      color: red;
      font-weight: bold;
      font-size: 1.5em;
    }

    class App extends React.Component {
      state = {
        items: [ 'aaa', 'aa1', 'ab1', 'zzz', '00!', 'lorem ipsum dolor...' ],
        search: '',
      }
    
      render() {
        const { items, search } = this.state;
        const regex = RegExp(search, 'g');
        const replacement = '<span class="highlighted">$&</span>';
    
        return (
          <div>
            <input value={search} onChange={e => this.setState({ search: e.target.value })} />
            {search &&
            <ul>
              {items.filter(n => n.includes(search)).map(n =>
                <li dangerouslySetInnerHTML={{ __html: n.replace(regex, replacement) }} />
              )}
            </ul>}
          </div>
        );
      }
    }
    Ответ написан
    1 комментарий
  • Как поменять местами данные у компонентов React?

    0xD34F
    @0xD34F Куратор тега React
    const Input = ({ label, ...props }) => (
      <div>
        <label>
          {label}
          <input {...props} />
        </label>
      </div>
    );
    
    class App extends React.Component {
      state = {
        from: 'Москва',
        to: 'Питер',
      }
    
      onChange = ({ target: { value, name } }) => {
        this.setState(() => ({
          [name]: value,
        }));
      }
    
      swap = () => {
        this.setState(({ from, to }) => ({
          from: to,
          to: from,
        }));
      }
    
      render() {
        return (
          <div>
            <button onClick={this.swap}>swap</button>
            <Input label="откуда" value={this.state.from} name="from" onChange={this.onChange} />
            <Input label="куда" value={this.state.to} name="to" onChange={this.onChange} />
          </div>
        );
      }
    }
    Ответ написан
    1 комментарий
  • Как при нажатии на блок с id="какой-то текст" добавить стили к блоку, у которого class="такой же текст"?

    0xD34F
    @0xD34F Куратор тега JavaScript
    По каким элементам надо кликать и где они находятся:

    const container = document.querySelector('ul');
    const itemSelector = 'li';

    Что касается стилей, то будем устанавливать как заранее неизвестные значения, так и предопределённые:

    const randomStyles = () => ({
      'background-color': `#${(Math.random() * 0xFFFFFF | 0).toString(16).padStart(6, 0)}`,
      'padding-left': `${Math.random() * 100 | 0}px`,
    });

    .active {
      border: 3px dashed blue;
    }

    const update = (el, styles) => (
      Object.assign(el.style, styles),
      el.classList.toggle('active')
    );

    Ловить клики можно непосредственно на интересующих нас элементах:

    container.querySelectorAll(itemSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, function() {
      document.querySelectorAll(`.${this.id}`).forEach(function(n) {
        update(n, this);
      }, randomStyles());
    });

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

    container.addEventListener('click', ({ target: t }) => {
      if ((t = t.closest(itemSelector)) && container.contains(t)) {
        const styles = randomStyles();
        for (const n of document.getElementsByClassName(t.getAttribute('id'))) {
          update(n, styles);
        }
      }
    });
    Ответ написан
    1 комментарий
  • Как запускать воспроизведение аудио только тогда, когда предыдущий звук был проигран полностью?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сделайте очередь:

    const audio = new Audio();
    const queue = [];
    
    audio.onended = function() {
      if (queue.length) {
        audio.src = queue.shift();
        audio.play();
      }
    };
    
    function play(srcArray) {
      queue.push(...srcArray);
    
      if (audio.paused) {
        audio.onended();
      }
    }
    
    play([ '1.mp3', '2.mp3', '3.mp3' ]);
    Ответ написан
    2 комментария
  • Почему строка не меняется?

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

    Ну и этот поиск индексов... Ерунда какая-то. Правильно так - сделать объект вида { 'символ': 'на что его надо заменить' }:

    const combine = (keys, values) =>
      keys.reduce((acc, n, i) => (acc[n] = values[i], acc), {});
    
    const enToRu = combine(trans[0], trans[1]);
    const ruToEn = combine(trans[1], trans[0]);

    Тогда "перевод" сведётся к чтению свойства объекта:

    const translate = (str, charset) => Array
      .from(str, n => charset[n] || n)
      .join('');
    
    translate(';jgf', enToRu) // 'жопа'
    translate('руддщб цщкдв!!', ruToEn) // 'hello, world!!'
    Ответ написан
    Комментировать
  • Почему атрибут selected не срабатывает?

    0xD34F
    @0xD34F
    Неправильно задаёте начальное значение. Вырезаем [selected], а в методе createSubForm вместо массива всех возможных значений в конструктор FormControl передаём одно. Типа так.
    Ответ написан
    Комментировать
  • Как отследить изменение свойства объекта?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вешаю на него сеттер...

    Не-а, не на него. Созданное ранее свойство вы перетёрли вызовом defineProperty, кроме того, вы не определяете геттер - отсюда и undefined.

    Можно добавить геттер, само же значение сделать локальной переменной конструктора:

    function test(m) {
      let money = m;
    
      Object.defineProperty(this, 'money', {
        get() {
          return money;
        },
        set(val) {
          alert(`Значение свойства money меняется с ${money} на ${val}`);
          money = val;
        },
      });
    }

    Или можно воспользоваться Proxy:

    function test(m) {
      this.money = m;
    
      return new Proxy(this, {
        set(target, prop, val) {
          alert(`Значение свойства ${prop} меняется с ${target[prop]} на ${val}`);
          target[prop] = val;
          return true;
        },
      });
    }
    Ответ написан
    4 комментария
  • Можно ли вызывать хук из кода?

    0xD34F
    @0xD34F
    Есть ли причины так не делать?

    Уместнее спросить - есть ли причины так делать? Мне таковые не известны. Если хотите повторно выполнить какой-то код из хука в произвольный момент - вынесите его в отдельный метод, и вызывайте этот метод.

    А то, что вы показали в качестве примера, при назначении рейтинга дёргаете ngOnInit - это что же, компонент повторно инициализируется при изменении рейтинга? Нет, это не правда. Зачем же тогда вводить в заблуждение себя и тех людей, которые будут читать ваш код? Не просто же так переменным, методам, классам и т.д. дают человекопонятные имена, описывающие их назначение.
    Ответ написан
    1 комментарий
  • Пропал элемент в html после указания родителя в объекте el: '#app'?

    0xD34F
    @0xD34F Куратор тега Vue.js
    @click="pushNumbars() reader.push(*)"

    Вот из-за подобных художеств шаблон и не рендерится.

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

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вместо img класс лучше переключать у article - максимально дальних не общих предков картинок. Если вдруг захотите при кликах на кнопки стилизовать ещё что-то помимо картинок, или измените взаимное расположение элементов, то не придётся переписывать js-код. Стили, конечно, придётся немного поправить, вместо .active будет .active img.

    const container = document.querySelector('.container');
    const itemSelector = 'article';
    const buttonSelector = `${itemSelector} .btn`;
    const activeClass = 'active';

    Делегирование, назначаем обработчик один раз:

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

    Или каждой кнопке индивидуально:

    container.querySelectorAll(buttonSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, e => e.currentTarget.closest(itemSelector).classList.toggle(activeClass));
    Ответ написан
    Комментировать
  • Как исправить мерцание блока при наведении?

    0xD34F
    @0xD34F Куратор тега CSS
    Достаточно добавить :hover и самой кнопке тоже:

    .btn:hover {
      display: block;
    }
    Ответ написан
  • Как собрать слово из букв?

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

    Куда: <div id="container"></div>.

    Как анимировать появление элементов:

    #container span {
      display: inline-block;
      white-space: pre;
      font-size: 40px;
      animation: span .2s ease-out;
    }
    @keyframes span {
      from {
        transform: translateX(500px);
        opacity: 0;
      }
      to {
        transform: translateX(0);
        opacity: 1;
      }
    }

    Как перебирать с задержкой массивоподобный объект:

    const forEachWithDelay = (arr, delay, callback) =>
      (function next(i) {
        if (i < arr.length) {
          setTimeout(() => (callback(arr[i]), next(-~i)), delay);
        }
      })(0);
    
    // или
    
    async function forEachWithDelay(arr, delay, callback) {
      for (let i = 0; i < arr.length; i++) {
        await new Promise(r => setTimeout(r, delay));
        callback(arr[i]);
      }
    }

    Вот так всё просто получается:

    forEachWithDelay(
      'hello, world!!',
      69,
      n => document
        .querySelector('#container')
        .insertAdjacentHTML('beforeend', `<span>${n}</span>`)
    );
    
    // или
    
    forEachWithDelay(
      'fuck the world',
      187,
      function(n) {
        this.appendChild(document.createElement('span'));
        this.lastChild.textContent = n;
      }.bind(document.getElementById('container'))
    );
    Ответ написан
    2 комментария