У keyval есть апи для редактирования элементов, удаления, добавления и т.д. Например orders.edit.add({id: 'coffee', amount: 2})
это эвент, который добавляет соответствующую запись в список
У keyval есть поддержка моделей для элементов, чтобы добавлять функциональность для конкретного элемента списка. Например у элемента могут быть дополнительные сторы создаваемые через createStore, вычисляемые поля, создаваемые через combine, эвенты и так далее. Если модель переданная в кейвал возвращает в одном из полей вложенный кейвал, то это означает, что в этом поле будет массив.
const menu = keyval({
key: 'dishId',
props: {
dishId: define.store<string>(),
price: define.store<number>(),
},
create({dishId: $dishId}) {
const additives = keyval({
key: 'additiveId',
props: {
additiveId: define.store<string>(),
price: define.store<number>(),
},
})
return {additives}
}
})
// Условно, получаем такой тип значений:
declare const menu.$items: Array<{
dishId: string
price: number
additives: Array<{
additiveId: string
price: number
}>
}>
Поле props в модели означает, что эти данные она получает в качестве входящих (как аргумент конструктора в классах) и на основе них с помощью create достраивает все необходимые вычисляемые поля и эвенты. Эти данные в этой статье называются Input
Подразумевается, что этих данных достаточно, чтобы создать новый инстанс модели, поэтому апи для заполнения данных принимает только их:
declare const menu.edit.add: EventCallable<{
dishId: string
price: number
}>
Как заполнять вложенный кейвал в таких условиях?
Можно вынести эвенты кейвала в return тела модели, после чего вручную вызывать все эти эвенты для каждого уровня сложности. Вариант крайне не удобный и не рассматривается, нужно иметь возможность заполнить весь кейвал в один вызов эвента
Можно задекларировать наличие кейвала в пропсах через define.keyval
(этот апи кстати в любом случае понадобится), но тогда мы лишаемся возможности создавать тело модели для вложенного кейвала. Тогда, как вариант, можно передавать сам кейвал в пропсы
const menu = keyval({
key: 'dishId',
props: {
dishId: define.store<string>(),
price: define.store<number>(),
additives: keyval({
key: 'additiveId',
props: {
additiveId: define.store<string>(),
price: define.store<number>(),
},
}),
},
})
Вариант хороший, но есть один существенный минус — добавлять в тело модели вложенного кейвала сторы из замыкания не выйдет. Например если вложенный кейвал опирается на стор dishId, то это становится невозможным
Вывод: такой подход подойдет для описания кейвалов без интерактивности, но кейс с интерактивными вложенными кейвалами им не охватывается
Можно сделать эдж кейс для кейвалов и когда они добавляются в return модели, то всё равно добавлять их в Input позволяя использовать их при заполнении модели
Но тогда возникает вопрос, а не стоит ли добавить в Input все не readonly сторы которые возвращает модель? У пользователя может быть $count внутри модели и эвент который делает инкремент для него, но возможность задать начальное значение для этого стора выглядит полезным
Такую автоматическую фильтрацию может запретить тайпскрипт, который и так уже находится на грани работоспособности с уже имеющимися в кейвале фичами, но тогда возможно стоит попробовать возвращать из модели объект, в котором сторы в поле {input: {foo: $foo}}
будут включены в Input модели