3

如果已在其中一个对象组中选择某个选项,我想禁用该选项。

因此,如果我选择“2013”​​然后添加另一个样本,则“2013”​​在该组中将不可用,除非在原始组中更改了该选项。

有没有一种我想念的简单方法来做到这一点?进行选择时是否需要响应式更新架构?

samples:{
    type: Array,
    optional: true,
    maxCount: 5
},
"samples.$":{
    type: Object,
    optional: true
},

"samples.$.sample":{
    type:[String],
    autoform: {
        type: "select",
        options: function () {
            return [
            {
            optgroup: "Group",
            options: [
             {label: "2013", value: 2013},
             {label: "2014", value: 2014},
             {label: "2015", value: 2015}
             ]
            }
            ];
        }   
    }

},
4

1 回答 1

0

概念证明

我知道这篇文章大约有 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,检查其他字段与其他字段等)

坏: - 性能 - 绑定到给定的(或最近的)表单上下文(见这里) - 要编写的代码比数组多得多。

于 2018-02-24T21:27:12.020 回答