概念证明
我知道这篇文章大约有 3 年的历史了。但是,我遇到了同样的问题,并想为所有也偶然发现这篇文章的人提供答案。
此答案仅是概念证明,并未提供可用于生产应用程序的完整通用和高性能解决方案。
一个完全通用的解决方案需要对如何在AutoForm
.
一些之前的笔记。
我正在使用 Autoform >=6,它提供了一个很好的 API,可以立即获取 SimpleSchema 中的字段和表单值,而不会有更大的麻烦。SimpleSchema
包含在 npm 包Tracker
中,必须传递给它以确保 Meteor 反应性。
像AutoForm.getFieldValue这样的函数是反应式的,这是一个真正的巨大改进。但是,根据反应值反应性地更改选择选项会导致大量更新周期并降低性能(我们将在后面看到)。
在 Object 字段的选项中使用AutoForm.getFormValues时不起作用。在 Array 字段中工作时,它不会在 Object 字段中反应,因此不会更新它们的过滤。
操作选择输入数组的选项(失败)
您不能将它与数组类型的字段一起使用。这是因为如果您更改选择选项,它将适用于阵列中的所有选择实例。因此,它也将适用于您已经选择的值并将它们剥离。这使您的选择看起来总是“未选择”
您可以使用以下示例代码自行测试:
new SimpleSchema({
samples:{
type: Array,
optional: true,
maxCount: 5
},
"samples.$":{
type: String,
autoform: {
type: "select",
options: function () {
const values = AutoForm.getFormValues('sampleSchemaForm') || {};
const samples = values && values.insertDoc && values.insertDoc.samples
? values.insertDoc.samples
: [];
const mappedSamples = samples.map(x => x.sample);
const filteredOpts = [
{label: "2013", value: "2013"},
{label: "2014", value: "2014"},
{label: "2015", value: "2015"}
].filter(y => mappedSamples.indexOf(y.value) === -1);
return [
{
optgroup: "Group",
options:filteredOpts,
}
];
}
}
},
}, {tracker: Tracker});
在对象字段上使用固定值
仔细查看架构时,我看到了该maxCount
属性。这让我想到,如果你有一个最大选项列表,你可以通过在samples
对象上设置固定属性来解决这个问题(顺便说一句:maxCount: 5
当只有三个选择选项时,这是没有意义的)。
这会导致每个选择都有自己的更新,不会干扰其他选择。它需要一个外部函数来跟踪所有选定的值,但这很容易。
考虑以下代码:
export const SampleSchema = new SimpleSchema({
samples:{
type: Object,
optional: true,
},
"samples.a":{
type: String,
optional:true,
autoform: {
type: "select",
options: function () {
const samples = AutoForm.getFieldValue("samples");
return getOptions(samples, 'a');
}
}
},
"samples.b":{
type: String,
optional:true,
autoform: {
type: "select",
options: function () {
const samples = AutoForm.getFieldValue("samples");
return getOptions(samples, 'b');
}
}
},
"samples.c":{
type: String,
optional:true,
autoform: {
type: "select",
options: function () {
const samples = AutoForm.getFieldValue("samples");
return getOptions(samples, 'c');
}
}
},
}, {tracker: Tracker});
上面的代码有三个示例条目(a、b 和 c),它们将让它们的选项由外部函数计算。
该功能需要满足一定的要求:
- 如果未选择任何选项,则不过滤任何选项
- 过滤不是由当前
samples
选择选择的选项
- 过滤所有其他选项,如果它们被另一个选择选择
该函数的代码如下:
function getOptions(samples={}, prop) {
// get keys of selections to
// determine, for which one
// we will filter options
const sampleKeys = Object.keys(samples);
// get sample values to
// determine which values
// to filter here
const sampleValues = Object.values(samples);
const filteredOptiond = [
// note that values are stored as strings anyway
// so instead of parsing let's make them strings
{label: "2013", value: "2013"},
{label: "2014", value: "2014"},
{label: "2015", value: "2015"}
].filter(option => {
// case 1: nothing is selected yet
if (sampleKeys.length === 0) return true;
// case2: this selection has a
// selected option and current option
// is the selected -> keep this option
if (sampleKeys.indexOf(prop) > -1 && option.value === samples[prop])
return true;
// case 3: this selection has no value
// but others may have selected this option
return sampleValues.indexOf(option.value) === -1;
});
return [
{
optgroup: "Group",
options: filteredOptiond,
}
]
};
关于这个概念的一些注释
好:-它有效-您基本上可以将其扩展和缩放到您想要的复杂性(optgroups,更多字段samples
,检查其他字段与其他字段等)
坏: - 性能 - 绑定到给定的(或最近的)表单上下文(见这里) - 要编写的代码比数组多得多。