Skip to content

fix(options): keep all option group panels mounted to preserve state#230

Merged
biz87 merged 1 commit intobetafrom
fix/product-options-tab-state-loss
Apr 26, 2026
Merged

fix(options): keep all option group panels mounted to preserve state#230
biz87 merged 1 commit intobetafrom
fix/product-options-tab-state-loss

Conversation

@biz87
Copy link
Copy Markdown
Member

@biz87 biz87 commented Apr 26, 2026

Проблема

В карточке товара на вкладке «Опции товара», когда у товара несколько групп опций:

  1. Открываешь любую неактивную группу.
  2. Заполняешь поля, переключаешь чекбоксы — заметно меняешь состояние.
  3. Переходишь на другую группу и возвращаешься назад — все изменения сброшены в дефолты.

Это не визуальный баг — данные действительно теряются. Сохранение не помогает: значения неактивных табов вообще не доезжают на бэкенд.

Причина

Панель таба рендерила одну секцию с v-for по активной группе:

<section class="vtabs-panel" role="tabpanel">
  <ProductOptionField
    v-for="option in activeGroup?.options || []"
    :key="option.key"
    :option="option"
    @change="onOptionChange"
  />
</section>

Переключение activeGroupId → массив activeGroup.options меняется → Vue разрушает все ProductOptionField старого таба и создаёт новые для нового. Вместе с компонентом улетают:

  1. Локальный value = ref(...) каждого поля. Возврат на исходный таб → новый инстанс инициализируется снова из props.option.value (исходное значение с бэкенда). Видимый «сброс».
  2. Скрытые <input type="hidden"> внутри ProductOptionField (есть у всех типов кроме textfield/textarea). MODX/ExtJS BasicForm.getValues() собирает только те инпуты, что в DOM на момент сабмита. Поля неактивного таба в форму просто не попадают_validated на бэке для них пуст → сохраняются дефолты.

Именно поэтому предварительное сохранение не спасает: POST уходит без этих полей, сервер кладёт дефолты, при следующей загрузке мы их и видим.

Фикс

Рендерим все группы сразу, прячем неактивные через v-show. Каждый ProductOptionField создаётся один раз и живёт весь сеанс работы с карточкой:

  • локальное состояние полей не теряется при переключении таба;
  • hidden inputs всех групп остаются в DOM → форма собирает значения со всех табов при сабмите.

Также убран неиспользуемый activeGroup computed.

Чем платим

  • Все ProductOptionField создаются одномоментно при открытии вкладки. Если у товара 200+ опций в нескольких группах — лёгкое замедление первого рендера. На обычных товарах с десятками опций — незаметно.
  • PrimeVue-компоненты (DatePicker, Select, MultiSelect) в display: none ведут себя нормально.

Test plan

  • Открыть товар с двумя+ группами опций.
  • Заполнить поля разных типов в неактивной группе (text, number, checkbox, combo, multi-select, date).
  • Переключиться на другую группу и обратно — введённое на месте.
  • Сохранить товар — введённые значения попадают на бэкенд и видны после перезагрузки страницы.
  • DatePicker и MultiSelect в скрытом табе нормально открываются после переключения на их группу (не «застревают» в закрытом состоянии).
  • Если у товара одна группа — single-group ветка продолжает работать как раньше.

When the user switched between option group tabs in the product card,
all entered values reverted to defaults — even after clicking Save.

Cause: the panel rendered a single <section> with v-for over
activeGroup.options. Switching tabs swapped the array, Vue tore
down every ProductOptionField for the previous group and built
fresh ones for the new group. With them went:

  - the local "value" ref of each field (visible "reset");
  - the per-field hidden <input type="hidden"> that the MODX/ExtJS
    BasicForm.getValues() collects on submit — so the POST silently
    omitted everything that wasn't in the currently active tab.

That's why pre-saving didn't help: the form simply never sent those
fields, the server stored defaults, and on reload the user saw
defaults again.

Fix: render every group's panel up front and toggle visibility with
v-show instead of swapping activeGroup.options. Each
ProductOptionField is now built once, holds its local state across
tab switches, and its hidden input stays in the DOM so the form
collects values from every group at submit time.

Removes the now-unused activeGroup computed.
@biz87 biz87 merged commit df93963 into beta Apr 26, 2026
@biz87 biz87 deleted the fix/product-options-tab-state-loss branch April 26, 2026 11:59
@biz87 biz87 mentioned this pull request Apr 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants