Skip to content

Commit 872ff75

Browse files
committed
feat(FormStore): support nested structures in form data handling
Closes NEXT_BUILDER-5249
1 parent c0b0701 commit 872ff75

File tree

2 files changed

+320
-51
lines changed

2 files changed

+320
-51
lines changed

shared/form/src/FormStore.spec.ts

Lines changed: 247 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,12 @@ describe("FormStore", () => {
313313

314314
store.resetFields();
315315

316-
expect(store.getAllValues()).toEqual({});
316+
expect(store.getAllValues()).toStrictEqual({
317+
a: undefined,
318+
b: undefined,
319+
c: undefined,
320+
"validator-item": undefined,
321+
});
317322
});
318323

319324
it("scrollToField should work", () => {
@@ -334,4 +339,245 @@ describe("FormStore", () => {
334339

335340
expect(mockScrollTo).toHaveBeenCalledWith("a.scroll.to", null);
336341
});
342+
343+
test("support nested object and array structures", () => {
344+
const store = new FormStore();
345+
346+
store.setField("user.name", {
347+
name: "user.name",
348+
label: "用户名",
349+
validate: {
350+
required: true,
351+
},
352+
});
353+
store.setField("user.age", {
354+
name: "user.age",
355+
label: "年龄",
356+
validate: {
357+
type: "number",
358+
},
359+
});
360+
store.setField("items[0].name", {
361+
name: "items[0].name",
362+
label: "第一个项目名称",
363+
validate: {
364+
required: true,
365+
},
366+
});
367+
store.setField("items[1].name", {
368+
name: "items[1].name",
369+
label: "第二个项目名称",
370+
validate: {},
371+
});
372+
373+
// setInitValue
374+
store.setInitValue({
375+
user: {
376+
name: "test",
377+
age: 18,
378+
},
379+
items: [{ name: "item1" }, { name: "item2" }],
380+
});
381+
382+
// getFieldsValue
383+
expect(store.getFieldsValue("user.name")).toBe("test");
384+
expect(store.getFieldsValue("user.age")).toBe(18);
385+
expect(store.getFieldsValue("items[0].name")).toBe("item1");
386+
expect(store.getFieldsValue("items[1].name")).toBe("item2");
387+
388+
// getAllValues
389+
const allValues = store.getAllValues();
390+
expect(allValues).toEqual({
391+
user: {
392+
name: "test",
393+
age: 18,
394+
},
395+
items: [{ name: "item1" }, { name: "item2" }],
396+
});
397+
398+
// setFieldsValue
399+
store.setFieldsValue({
400+
user: {
401+
name: "updated",
402+
age: 20,
403+
},
404+
});
405+
406+
expect(store.getFieldsValue("user.name")).toBe("updated");
407+
expect(store.getFieldsValue("user.age")).toBe(20);
408+
409+
// validateFields
410+
const mockValidateFields = jest.fn();
411+
store.validateFields(mockValidateFields);
412+
413+
expect(mockValidateFields).toHaveBeenCalledWith(false, {
414+
user: {
415+
name: "updated",
416+
age: 20,
417+
},
418+
items: [{ name: "item1" }, { name: "item2" }],
419+
});
420+
421+
// resetFields
422+
store.resetFields("user.name");
423+
expect(store.getFieldsValue("user.name")).toBeUndefined();
424+
expect(store.getFieldsValue("user.age")).toBe(20);
425+
426+
store.resetFields();
427+
expect(store.getAllValues()).toStrictEqual({
428+
items: [
429+
{
430+
name: undefined,
431+
},
432+
{
433+
name: undefined,
434+
},
435+
],
436+
user: {
437+
age: undefined,
438+
name: undefined,
439+
},
440+
});
441+
});
442+
443+
test("handle notRender fields when reading and setting values", () => {
444+
const store = new FormStore();
445+
446+
store.setField("visible-field", {
447+
name: "visible-field",
448+
validate: {
449+
required: true,
450+
},
451+
});
452+
store.setField("hidden-field", {
453+
name: "hidden-field",
454+
notRender: true,
455+
validate: {
456+
required: true,
457+
},
458+
});
459+
460+
store.setInitValue({
461+
"visible-field": "visible",
462+
"hidden-field": "hidden",
463+
});
464+
465+
// getFieldsValue
466+
expect(store.getFieldsValue("visible-field")).toBe("visible");
467+
expect(store.getFieldsValue("hidden-field")).toBeUndefined();
468+
469+
// getAllValues
470+
expect(store.getAllValues()).toEqual({ "visible-field": "visible" });
471+
472+
// setFieldsValueByInitData
473+
store.setInitValue({
474+
"visible-field": "init-visible",
475+
"hidden-field": "init-hidden",
476+
});
477+
478+
store.resetFields("visible-field");
479+
expect(store.getFieldsValue("visible-field")).toBeUndefined();
480+
481+
store.setFieldsValueByInitData("visible-field");
482+
store.setFieldsValueByInitData("hidden-field");
483+
484+
expect(store.getFieldsValue("visible-field")).toBe("init-visible");
485+
expect(store.getFieldsValue("hidden-field")).toBeUndefined();
486+
487+
// validateField
488+
const validateResultVisible = store.validateField("visible-field");
489+
expect(validateResultVisible).toBeDefined();
490+
491+
const validateResultHidden = store.validateField("hidden-field");
492+
expect(validateResultHidden).toBeUndefined();
493+
});
494+
495+
test("onValuesChanged callback should receive correct changedValues", () => {
496+
const mockOnValuesChanged = jest.fn();
497+
const store = new FormStore({
498+
onValuesChanged: mockOnValuesChanged,
499+
});
500+
501+
store.setField("name", {
502+
name: "name",
503+
label: "Name",
504+
validate: {},
505+
});
506+
store.setField("age", {
507+
name: "age",
508+
label: "Age",
509+
validate: {},
510+
});
511+
store.setField("email", {
512+
name: "email",
513+
label: "Email",
514+
validate: {},
515+
});
516+
517+
store.setInitValue({
518+
name: "John",
519+
age: 30,
520+
521+
});
522+
523+
mockOnValuesChanged.mockClear();
524+
525+
store.setFieldsValue({
526+
name: "Jane",
527+
age: 25,
528+
});
529+
530+
expect(mockOnValuesChanged).toHaveBeenCalledTimes(1);
531+
expect(mockOnValuesChanged).toHaveBeenCalledWith({
532+
changedValues: {
533+
name: "Jane",
534+
age: 25,
535+
},
536+
allValues: {
537+
name: "Jane",
538+
age: 25,
539+
540+
},
541+
});
542+
543+
// test nested field update
544+
mockOnValuesChanged.mockClear();
545+
546+
store.setField("address.city", {
547+
name: "address.city",
548+
label: "City",
549+
validate: {},
550+
});
551+
store.setField("address.zip", {
552+
name: "address.zip",
553+
label: "Zip Code",
554+
validate: {},
555+
});
556+
557+
store.setFieldsValue({
558+
address: {
559+
city: "New York",
560+
zip: "10001",
561+
},
562+
});
563+
564+
expect(mockOnValuesChanged).toHaveBeenCalledTimes(1);
565+
expect(mockOnValuesChanged).toHaveBeenCalledWith({
566+
changedValues: {
567+
address: {
568+
city: "New York",
569+
zip: "10001",
570+
},
571+
},
572+
allValues: {
573+
name: "Jane",
574+
age: 25,
575+
576+
address: {
577+
city: "New York",
578+
zip: "10001",
579+
},
580+
},
581+
});
582+
});
337583
});

0 commit comments

Comments
 (0)