Meteor Autoform - 禁用Object字段数组中的选择选项

时间:2014-12-02 21:45:56

标签: javascript meteor meteor-autoform

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

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

},

1 个答案:

答案 0 :(得分:0)

概念证明

我知道这篇文章大约3岁。但是,我遇到了同样的问题,并想为所有那些偶然发现这篇文章的人提供答案。

这个答案只是一个概念证明,并没有提供可用于生产应用程序的完整通用和高性能解决方案。

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


一些先前的注释。

我正在使用Autoform> = 6,它提供a good API即可在SimpleSchema中立即获取字段和表单值,而不会遇到更多麻烦。 SimpleSchema包含在npm包中,Tracker必须传递给它,以确保流星反应性。

AutoForm.getFieldValue这样的函数是被动的,这是一个真正伟大的改进。但是,基于无效值反应性地更改选择选项会导致大量更新周期并降低性能(我们将在后面看到)。

在Object字段的选项中使用AutoForm.getFormValues时,使用here不起作用。在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),它们的选项将由外部函数计算。

此功能需要满足某些要求:

  • 如果选择nothin,则不会过滤选项
  • 不会选择由当前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,
        }
    ]
};

关于此概念的一些注释

○: -有用 - 您基本上可以扩展并扩展到您想要的复杂程度(选择组,samples上的更多字段,与其他字段检查其他字段等。)

为: - 表现 - 绑定到给定(或最近的)表单上下文(请参阅Here) - 要编写的代码要多于数组代码。