我想禁用一个选项,如果它已经在对象组之一中被选中。

因此,如果我选择“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}
             ]
            }
            ];
        }
    }

},

最佳答案

概念证明

我知道此职位大约3岁。但是,我遇到了同样的问题,并希望为所有也为这篇文章而迷迷糊糊的人提供答案。

该答案仅是概念证明,并未提供可在生产应用程序上使用的完整的通用解决方案。

完全通用的解决方案需要对AutoForm中如何生成和更新选择字段选项的代码进行深刻的更改。

一些先前的注意事项。

我正在使用Autoform> = 6,它提供a good API来立即获取SimpleSchema中的字段和表单值,而不会带来更多麻烦。 SimpleSchema包含在npm软件包中,并且Tracker必须传递给它,以确保Meteor反应性。

AutoForm.getFieldValue这样的函数是反应式的,这确实是一个很大的改进。但是,基于反应性值来反应性地更改选择选项会导致大量更新周期,并且会降低性能(我们将在后面看到)。

在对象字段的选项中使用AutoForm.getFormValues时不起作用。在“数组”字段中工作时,它将在“对象”字段中没有反应,因此不会更新对它们的过滤。

处理选择输入数组的选项(失败)

您不能将其与字段的数组类型一起使用。这是因为,如果更改选择选项,它将应用于数组中的所有选择实例。因此,它也将应用于您已经选择的值,并将它们也剥离掉。这使您的选择看起来总是“未选择”

您可以使用以下示例代码进行测试:

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选择的选项select
  • 过滤所有其他选项,如果它们是由另一个select
  • 选择的

    该函数的代码如下:
    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,
            }
        ]
    };
    

    有关此概念的一些注意事项

    好:
    -有用
    -您基本上可以将其扩展并扩展到所需的复杂度(optgroup,samples上的更多字段,与其他字段进行对照的其他字段等)

    坏:
    -表现
    -绑定(bind)到给定的(或最接近的)表单上下文(请参阅here)
    -比数组要写的代码要多得多。

    关于javascript - meteor 自动格式-禁用对象字段数组中的选择选项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27259586/

    10-10 21:58
    查看更多