Прежде всего вы должны знать о ситуации:
- Вы смешиваете классический рендеринг пользовательского интерфейса (ползунки) с рендерингом Blaze (выпадающий список).Это принесет вам много проблем с дизайном, и приведенное ниже решение - скорее хак, чем чистая аппроксимация с использованием Blaze API
- Поскольку ваши компоненты больше не являются просто ползунками, вам следует переименовать переменные.В противном случае постороннему человеку будет сложно декодировать контекст вашей переменной.
- В вашем раскрывающемся списке в настоящее время нет сохраненных значений, при переключении кнопки сбрасывается раскрывающийся список.
- Вы не можете уничтожить
noUiSlider
в раскрывающемся списке при нажатии на кнопку переключателя, что вызывает ошибку, описанную выше.
Поэтому я хочу дать вам несколько советов по реструктуризациисначала ваш код.
1.Переименование переменных
Вы можете использовать функцию рефакторинга в IDE, чтобы легко переименовывать все имена переменных.Если у вас нет такой функциональности в вашей IDE / редакторе, я настоятельно рекомендую вам запустить поисковую систему, чтобы получить ее.
Поскольку у вас больше типов ввода, чем у ползунков, вам следует использовать более общее имя, напримерinputs
, который указывает на более широкий диапазон возможных типов.
В вашем раскрывающемся списке также должна быть запись value
, при повторном рендеринге можно восстановить последнее состояние выбора:
Template.MyTemplate.onCreated(function () {
const inputs = [{
id: 'slider-a',
prio: 1,
type: 'NumberRange',
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
}, {
id: 'slider-b',
prio: 2,
type: 'NumberRange',
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
}, {
id: 'dropdown-c',
prio: 3,
type: 'Dropdown',
value: '', // default none
}, {
id: 'slider-d',
prio: 4,
type: 'NumberRange',
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
},]
const instance = this
instance.state = new ReactiveDict()
instance.state.set('values', {}) // mapping values by sliderId
instance.state.set('inputs', inputs)
})
Теперь вам также нужно переименовать ваших помощников, а помощник шаблона вызывает:
<template name="MyTemplate">
{{#each inputs}}
...
{{/each}}
</template>
Template.MyTemplate.helpers({
inputs () {
return Template.instance().state.get('inputs')
},
...
})
2.Обработка нескольких типов ввода в событии переключения
Вам также следует переименовать переменные в событии переключения.Более того, вам нужно обрабатывать различные типы ввода здесь.У раскрывающихся списков нет свойства .noUiSlider
, и они также получают не массив, а строковую переменную в качестве значения:
'click .test': function (event, templateInstance) {
let inputs = templateInstance.state.get('inputs')
const values = templateInstance.state.get('values')
// remove current rendered inputs
// and their events / prevent memory leak
inputs.forEach(input => {
if (input.type === 'Dropdown') {
// nothing to manually remove
// Blaze handles this for you
return
}
if (input.type === 'NumberRange') {
const target = templateInstance.$(`#${input.id}`).get(0)
if (target && target.noUiSlider) {
target.noUiSlider.off()
target.noUiSlider.destroy()
}
}
})
// assign current values as
// start values for the next newly rendered
// inputs
inputs = inputs.map(input => {
const currentValues = values[input.id]
if (!currentValues) {
return input
}
if (input.type === 'Dropdown') {
input.value = currentValues
}
if (input.type === 'NumberRange') {
input.options.start = currentValues.map(n => Number(n))
}
return input
}).reverse()
templateInstance.state.set('inputs', inputs)
},
3.Правильный вывод списка обновлений / обновлений
Теперь возникает проблема смешивания рендеринга Blaze с классическими обновлениями DOM: до этого момента вы столкнетесь с ошибкой.Это происходит главным образом потому, что сейчас наша функция createSliders
ожидает элемент div
с определенным идентификатором в том месте, где раскрывающийся список был отображен до нажатия переключателя.Этого не будет, потому что на этом этапе недействительность рендеринга Blaze не будет завершена.
Исправление этого с использованием autorun
в onCreated
или onRendered
легко увеличит сложность или даже испортит ваш код.Более простое решение - использовать короткий тайм-аут:
Template.MyTemplate.helpers({
// ...
slider (source) {
const instance = Template.instance()
setTimeout(()=> {
createSliders(source.id, source.options, instance)
}, 50)
},
// ...
})
4.Бонус: сохранение состояния раскрывающегося списка
Чтобы сохранить состояние раскрывающегося списка, необходимо подключиться к его событию change
.Поэтому вам необходимо назначить ему класс для сопоставления события независимо от id
:
<select id="{{this.id}}" class="dropdown" style="width: 200px;">...</select>
, для которого теперь вы можете создать событие:
'change .dropdown'(event, templateInstance) {
const $target = templateInstance.$(event.currentTarget)
const value = $target.val()
const targetId = $target.attr('id')
const valuesObj = templateInstance.state.get('values')
valuesObj[targetId] = value
templateInstance.state.set('values', valuesObj)
}
Теперь вы сохраниливаше текущее значение раскрывающегося списка, но для того, чтобы восстановить его при следующем рендеринге, вам необходимо расширить options
в html:
<select id="{{this.id}}" class="dropdown" style="width: 200px;">
<option value="a" selected="{{#if $eq this.value 'a'}}selected{{/if}}">a</option>
<option value="b" selected="{{#if $eq this.value 'b'}}selected{{/if}}">b</option>
<option value="c" selected="{{#if $eq this.value 'c'}}selected{{/if}}">c</option>
</select>
. Теперь это должно также отображать последнее выбранное состояние раскрывающегося списка.
Сводка
- Вы можете использовать этот шаблон для включения еще большего количества компонентов ввода.
- Имейте в виду, что смешивание рендеринга Blaze с традиционными манипуляциями с DOM может усложнитьВаш код много.То же самое относится ко многим другим системам рендеринга / библиотекам / инфраструктурам.
- Решение
setTimeout
должно быть последним подходом, который следует использовать, когда другие подходы еще менее осуществимы. - Переменная и методнаименование должно всегда представлять их контекст.Если контекст изменится -> переименовать / изменить факторы и методы.
- Пожалуйста, в следующий раз опубликуйте полный код здесь снова. Ваш другой пост может быть обновлен или удален, а полный код не будетбыть доступным здесь больше, мешая другим находить хорошее решение.