在 Autoform 中使用对象作为选项
Using objects as options in Autoform
在我的 Stacks
架构中,我有一个 dimensions
属性 定义如下:
dimensions: {
type: [String],
autoform: {
options: function() {
return Dimensions.find().map(function(d) {
return { label: d.name, value: d._id };
});
}
}
}
这非常有效,并且使用 Mongol 我能够看到通过表单插入数据的尝试效果很好(在本例中我选择了两个维度来插入)
然而,我真正了解的是存储实际维度对象的数据,而不是它的键。像这样:
[
为了尝试实现这一点,我将 type:[String]
更改为 type:[DimensionSchema]
,将 value: d._id
更改为 value: d
。这里的想法是我告诉表单我期待一个对象,现在返回对象本身。
但是,当我 运行 这样做时,我的控制台出现以下错误。
Meteor does not currently support objects other than ObjectID as ids
四处寻找并将 type:[DimensionSchema]
更改为 type: DimensionSchema
我在控制台中看到了一些新错误(大概当 type
是数组时它们被掩埋了
看来 autoform 正在尝试获取我想要存储在数据库中的值并尝试将其用作 ID。关于执行此操作的最佳方法有什么想法吗?
参考这里是我的DimensionSchema
export const DimensionSchema = new SimpleSchema({
name: {
type: String,
label: "Name"
},
value: {
type: Number,
decimal: true,
label: "Value",
min: 0
},
tol: {
type: Number,
decimal: true,
label: "Tolerance"
},
author: {
type: String,
label: "Author",
autoValue: function() {
return this.userId
},
autoform: {
type: "hidden"
}
},
createdAt: {
type: Date,
label: "Created At",
autoValue: function() {
return new Date()
},
autoform: {
type: "hidden"
}
}
})
目前我唯一可以建议的(如果值不支持 object
类型),是将对象转换为 string
(即序列化字符串)并将其设置为"dimensions" 键(而不是对象)并将其保存到数据库中。
从数据库返回时,再次将该值 (string
) 反序列化为 object
。
根据我的经验和自己在 this issue 中的经验,autoform 对对象数组的字段不是很友好。
我通常建议不要以这种方式嵌入这些数据。如果将来修改 dimension
文档,这会使数据更难维护。
备选方案
- 您可以使用像 publish-composite 这样的包在发布中创建反应式连接,同时仅将
_id
嵌入到 stack
文档中。
- 您可以使用 PeerDB 包之类的东西为您进行反规范化,这也会为您更新嵌套文档。考虑到它带有学习曲线。
- 手动编码无法使用 AutoForm 轻松创建的特定表单。这给了你最大的控制权,有时它比所有的修补更容易。
如果你坚持使用AutoForm
虽然可以 create a custom input type(通过 AutoForm.addInputType()
),但我不推荐它。它需要您创建一个模板并在其 valueOut
方法中修改数据,并且生成编辑表单并不是一件容易的事。
由于这是一个特定的用例,我认为最好的方法是使用稍微 修改过的模式 并在 Meteor 方法中处理数据.
用字符串数组定义模式:
export const StacksSchemaSubset = new SimpleSchema({
desc: {
type: String
},
...
dimensions: {
type: [String],
autoform: {
options: function() {
return Dimensions.find().map(function(d) {
return { label: d.name, value: d._id };
});
}
}
}
});
然后,呈现一个 quickForm,指定模式和方法:
<template name="StacksForm">
{{> quickForm
schema=reducedSchema
id="createStack"
type="method"
meteormethod="createStack"
omitFields="createdAt"
}}
</template>
并定义适当的助手来传递模式:
Template.StacksForm.helpers({
reducedSchema() {
return StacksSchemaSubset;
}
});
并且在服务器上,定义方法并在插入之前改变 data
。
Meteor.methods({
createStack(data) {
// validate data
const dims = Dimensions.find({_id: {$in: data.dimensions}}).fetch(); // specify fields if needed
data.dimensions = dims;
Stacks.insert(data);
}
});
在我的 Stacks
架构中,我有一个 dimensions
属性 定义如下:
dimensions: {
type: [String],
autoform: {
options: function() {
return Dimensions.find().map(function(d) {
return { label: d.name, value: d._id };
});
}
}
}
这非常有效,并且使用 Mongol 我能够看到通过表单插入数据的尝试效果很好(在本例中我选择了两个维度来插入)
然而,我真正了解的是存储实际维度对象的数据,而不是它的键。像这样:
[
为了尝试实现这一点,我将 type:[String]
更改为 type:[DimensionSchema]
,将 value: d._id
更改为 value: d
。这里的想法是我告诉表单我期待一个对象,现在返回对象本身。
但是,当我 运行 这样做时,我的控制台出现以下错误。
Meteor does not currently support objects other than ObjectID as ids
四处寻找并将 type:[DimensionSchema]
更改为 type: DimensionSchema
我在控制台中看到了一些新错误(大概当 type
是数组时它们被掩埋了
看来 autoform 正在尝试获取我想要存储在数据库中的值并尝试将其用作 ID。关于执行此操作的最佳方法有什么想法吗?
参考这里是我的DimensionSchema
export const DimensionSchema = new SimpleSchema({
name: {
type: String,
label: "Name"
},
value: {
type: Number,
decimal: true,
label: "Value",
min: 0
},
tol: {
type: Number,
decimal: true,
label: "Tolerance"
},
author: {
type: String,
label: "Author",
autoValue: function() {
return this.userId
},
autoform: {
type: "hidden"
}
},
createdAt: {
type: Date,
label: "Created At",
autoValue: function() {
return new Date()
},
autoform: {
type: "hidden"
}
}
})
目前我唯一可以建议的(如果值不支持 object
类型),是将对象转换为 string
(即序列化字符串)并将其设置为"dimensions" 键(而不是对象)并将其保存到数据库中。
从数据库返回时,再次将该值 (string
) 反序列化为 object
。
根据我的经验和自己在 this issue 中的经验,autoform 对对象数组的字段不是很友好。
我通常建议不要以这种方式嵌入这些数据。如果将来修改 dimension
文档,这会使数据更难维护。
备选方案
- 您可以使用像 publish-composite 这样的包在发布中创建反应式连接,同时仅将
_id
嵌入到stack
文档中。 - 您可以使用 PeerDB 包之类的东西为您进行反规范化,这也会为您更新嵌套文档。考虑到它带有学习曲线。
- 手动编码无法使用 AutoForm 轻松创建的特定表单。这给了你最大的控制权,有时它比所有的修补更容易。
如果你坚持使用AutoForm
虽然可以 create a custom input type(通过 AutoForm.addInputType()
),但我不推荐它。它需要您创建一个模板并在其 valueOut
方法中修改数据,并且生成编辑表单并不是一件容易的事。
由于这是一个特定的用例,我认为最好的方法是使用稍微 修改过的模式 并在 Meteor 方法中处理数据.
用字符串数组定义模式:
export const StacksSchemaSubset = new SimpleSchema({
desc: {
type: String
},
...
dimensions: {
type: [String],
autoform: {
options: function() {
return Dimensions.find().map(function(d) {
return { label: d.name, value: d._id };
});
}
}
}
});
然后,呈现一个 quickForm,指定模式和方法:
<template name="StacksForm">
{{> quickForm
schema=reducedSchema
id="createStack"
type="method"
meteormethod="createStack"
omitFields="createdAt"
}}
</template>
并定义适当的助手来传递模式:
Template.StacksForm.helpers({
reducedSchema() {
return StacksSchemaSubset;
}
});
并且在服务器上,定义方法并在插入之前改变 data
。
Meteor.methods({
createStack(data) {
// validate data
const dims = Dimensions.find({_id: {$in: data.dimensions}}).fetch(); // specify fields if needed
data.dimensions = dims;
Stacks.insert(data);
}
});