我正在使用角度和故事书。我的模型中有 FormGroup 和 FormArray,但它们不能与故事书一起使用。
a.stories.ts ->
import { CommonModule } from '@angular/common';
import { FormArray, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { Meta, moduleMetadata, Story } from '@storybook/angular';
export default {
title: 'Example/A',
component: AComponent,
decorators: [
moduleMetadata({
imports: [
CommonModule,
ReactiveFormsModule,
],
providers: [],
}),
],
} as Meta;
const Template: Story<AComponent> = (args: AComponent) => ({
props: args,
});
export const Costs = Template.bind({});
Costs.args = {
model: {
questions: [
{
...,
"question": "lorem ipsum",
"formGroup": new FormGroup({
answers: new FormArray([
new FormGroup({
"Q020_A001": new FormControl(null, [Validators.required]),
"Q020_A002": new FormControl(null, [Validators.required]),
}),
]),
}),
"answers": [
{
...,
"answerCode": "Q020_A001",
},
{
...,
"answerCode": "Q020_A002",
},
],
}
],
},
};
我在故事书中遇到错误 ->
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'FormGroup'
| property 'controls' -> object with constructor 'Object'
| property 'answers' -> object with constructor 'FormArray'
--- property '_parent' closes the circle
at JSON.stringify (<anonymous>)
如果“formGroup”为空,它就可以工作。 ->
"formGroup": new FormGroup({
}),
但是如果“formGroup”不为空,则不起作用。 ->
"formGroup": new FormGroup({
asd: new FormControl(''),
}),
我该如何解决这个问题?
我通过创建一个新的 ASstoryComponent 解决了这个问题。
// a-story.component.ts
@Component({
selector: 'a-component-story',
template: `<a-component [model]="model"></a-component>`,
})
export class AStoryComponent implements OnInit {
@Input() model!: any;
constructor() {}
ngOnInit() {
// Converts the "formGroup" property I specified in a.stories.ts to the real formGroup object.
convertStoryModelToRealModel(this.model);
}
}
// a.stories.ts
import { Validators } from '@angular/forms';
import { Meta, moduleMetadata, Story } from '@storybook/angular';
export default {
title: 'Example/A',
component: AStoryComponent,
decorators: [
moduleMetadata({
declarations: [AStoryComponent, AComponent],
imports: [
CommonModule,
ReactiveFormsModule,
],
}),
],
} as Meta;
const Template: Story<AStoryComponent> = (args: AStoryComponent) => ({
props: args,
});
export const Costs = Template.bind({});
Costs.args = {
model: {
questions: [
{
...,
"question": "lorem ipsum",
"formGroup": {
answers: [
{
"Q020_A001": [null, [Validators.required]],
"Q020_A002": [null, [Validators.required]],
},
],
},
"answers": [
{
...,
"answerCode": "Q020_A001",
},
{
...,
"answerCode": "Q020_A002",
},
],
}
],
} as any,
};
问题在于您向 Storybook 提供的每一个
args
,SB 都会打电话给 JSON.stringify
。这种设计是必需的,因为 SB 也在运行时使用您的 args
并允许您更改值。
在您的情况下,您创建了一个反应式表单模型,这会导致对象无法通过
JSON.stringify
转换为字符串。
要修复它,您需要:
AComponent
中的逻辑,以根据上面提供的数据创建模型示例代码:
/// a.stories.ts
Costs.args = {
model: {
questions: [
{
...,
"question": "lorem ipsum",
"formGroup": {
answers: [
{
"Q020_A001": null,
"Q020_A002": null,
}),
]),
},
"answers": [
{
...,
"answerCode": "Q020_A001",
},
{
...,
"answerCode": "Q020_A002",
},
],
}
],
},
};
/// A.component.ts
export class AComponent {
@Input() model;
constructor() {
// create your reactive forms here with data from model
this.form = new FormGroup(...)
}
}
我最近找到了一种非常简单的方法来避免此错误,几乎不需要付出任何努力。
Storybook 尝试对您传递给组件的任何参数进行字符串化。我们可以告诉我们的 formGroups 按照我们的规则进行字符串化。
通过在对象上设置 toJSON(),我们可以阻止 Storybook 尝试序列化循环结构。
const MY_FORM = new FormGroup({
a: new FormControl('A'),
b: new FormControl('B'),
})
// Tell JSON.stringify to serialize it as 'WHATEVER YOU WANT' > No circular dependency
MY_FORM['toJSON'] = () => 'WHATEVEVER YOU WANT';
export const FormStory: Story = {
name: 'FormStory',
args: {
form: MY_FORM
},
};
Storybook 将在控制面板中生成一个字符串控件,您可以像这样隐藏它(如上所述)
...
argTypes: {
form: { table: { disable: true } } // Disable form serialization in control panel
},
请注意,这适用于字符串化时循环的任何对象