我有一个带有嵌套表格的表格
Form 1
-- Form 1.1
-- Form 1.2
我需要保存表格1,然后使用从保存Id
中检索到的Form 1
保存表格1.1和表格1.2,然后发出所有子项都被保存的信息。
我必须动态地执行此操作,因为此表单的深度要大得多。
执行此操作的效果如何?
我试图在子组件的标签上放置指令,但是我无法读取这些组件。这些组件是不同的,并且可能是动态的,因此我不能在组件上使用@ViewChild
。
我想观察这些子组件,以便在告诉父组件一切准备就绪之前知道应该发出多少事件。
就目前而言,我只能想到某些服务,其中包含每个父母的计数。
这里是StackBlitz,是我所拥有的简化版本。在实际的应用程序中,存在动态组件以及动态参数名称(我必须从父级传递来连接子级的名称)和表单的嵌套级别。
我尝试用注释覆盖工作流程的详细信息。
TL; DR 我需要保存所有Person,然后使用personId作为附加参数保存每个Person的名称以在数据库中连接它们,在保存完所有表单部分后,我需要报告父表单,一切准备就绪。
答案 0 :(得分:1)
您拥有app.component.ts
级别所需的一切,可以递归遍历tree
并完成您的保存逻辑,而在子级别没有任何状态。
在
Observable
方法中使用submit()
逻辑来检索ID
从第一个保存开始,一旦收到该ID,就在下一个重复进行 降低表格中的值并完成下一次保存。一旦所有 在app.component.ts
级满足您的条件,请关闭 表格。
submit() {
// Here goes an initial form submit which returns an ID of saved form
console.log('submit a form');
let persons: Person[] = this.formGroup.value.persons;
for (let person of persons) {
console.log('Saving person with Birthdate: ' + person.birthDate)
for (let name of person.names) {
console.log('Saving nameObject: ' + JSON.stringify(name))
}
}
}
答案 1 :(得分:0)
使用事件发射器将子窗体中的窗体数据提交到父窗体中。然后,父表单将能够收集发出的数据,并且您可以根据需要对其进行处理,包括将其传递给您提到的Observable。
答案 2 :(得分:0)
最后,我用下一个代码解决了我的问题。希望这会帮助某人
// You should provide either "data" or "formGroup"
export interface RecForm {
/** Data to be saved */
data?: any;
/** Request URI */
request: string;
/** Params that should be used from accumulator */
useParams?: string[] | {
/** Parameter to be taken from accumulator */
use: string;
/** Parameter alias to use */
as: string;
}[];
/** Children forms to be saved */
children?: RecForm[];
/** FormGroup to take values from */
formGroup?: FormGroup;
/** Children forms grouped by name to be saved */
childrenGroups?: {
[index: string]: RecForm[];
};
/** Names to use for storing in accumulator. The array us being used for the
* sake of agility */
valAlias: string[];
}
这是我用来处理该对象的方法
public saveRecursively(obj: RecForm, accumulator?: any): Observable<any> {
// Variable to store form data
let req;
if (obj.data) {
req = {...obj.data};
} else {
req = {...obj.formGroup.value};
}
// If there are an accumulator and parameters to be used
// we add these parameters to the form data
if (obj.useParams && accumulator) {
(<any>obj.useParams).forEach(paramName => {
if (typeof paramName === 'string') {
req[paramName] = accumulator[paramName];
} else {
req[paramName.as] = accumulator[paramName.use];
}
});
}
return iif(
() =>
// We need to save only changed form
obj.formGroup.touched && obj.formGroup.dirty
// or the one that has children and does not
// have an Id to pass it to the children
|| (
obj.children && obj.children.length > 0
|| obj.childrenGroups && Object.keys(obj.childrenGroups).length > 0
) && !req.id
,
defer(() => this.ss.send(obj.request, {
data: req
})),
of(req.id || null)
).pipe(
pluck('data'),
map((id: string) => {
const acc = {...accumulator};
// Export returned ID with provided aliases adding them
// to the accumulator
obj.valAlias.forEach(alias => {
acc[alias] = id;
});
return acc;
}),
switchMap((acc): any => {
if (obj.children && obj.children.length > 0) {
return forkJoin(
obj.children.map(child => this.saveRecursively(child, acc))
);
}
// Save children forms if there any
else if (obj.childrenGroups && Object.keys(obj.childrenGroups).length > 0) {
return forkJoin(
flatten(Object.values(obj.childrenGroups)).map(item => this.saveRecursively(item, acc))
);
}
// If there is no children forms just return an accumulator
else {
return of(acc);
}
})
);
}
注意:flatten
来自Lodash,用于将按名称分组的表单和对象更改为单个数组。
this.ss.save
是服务的一种方法,它接受要进行计算的请求和主体并返回一个可观察对象。
然后,我只提供在根表单组件中创建实例的服务。
该服务包含object: RecForm
和用于动态创建和删除嵌套对象道具的Lodash方法。
有了这项服务,我正在通过组件树path
,在其中我扩展了其在树上的移动值,并使用此路径向我的对象添加了新的FormGroup
。
完成后,我只调用对象上的saveRecursively
并保存了所有内容。
此外,如果您要使用我的方法并在OnInit
中扩展对象,请不要忘记删除OnDestroy
中的值,以便将每个FormArray
拆分为每个控件不会有任何删除的值。