---
order: 22
zh-CN:
	title: Model 模式动态增删表单项
	invalidContactType: 请选择联系方式
	invalidPhoneNumber: 手机号必须是 11 位数字
	invalidEmail: 邮箱不正确
	labelContactType: 联系方式
	labelPhone: 手机号码
	labelEmail: 电子邮箱
	preserveState: 切换联系方式时时保留 model 状态
	printValue: 打印表单值
en-US:
	title: Add/remove fields in Model mode
	invalidContactType: Contact type is required
	invalidPhoneNumber: Phone number is 11 digits
	invalidEmail: Invalid email address
	labelContactType: Contact type
	labelPhone: Phone
	labelEmail: Email
	preserveState: Preserve model state while switching contact type
	printValue: Print form value
---

```jsx
import {
	Form,
	Validators,
	FormRadioGroupField,
	FormNumberInputField,
	FormInputField,
	Checkbox,
} from 'zent';
import { merge } from 'rxjs';

const { form, field } = Form;

const ContactType = {
	Phone: 1,
	Email: 2,
};

const formBuilder = form({
	contactType: field(ContactType.Phone).validators(
		Validators.required('{i18n.invalidContactType}')
	),
	phone: field('').validators(
		Validators.pattern(/\d{11}/, '{i18n.invalidPhoneNumber}')
	),
	email: field('').validators(Validators.email('{i18n.invalidEmail}')),
});

function App() {
	const [preserveState, setPreserveState] = React.useState(false);
	const onPreserveStateChange = React.useCallback(
		evt => {
			setPreserveState(evt.target.checked);
		},
		[setPreserveState]
	);

	const form = Form.useForm(formBuilder);
	const removedModelRef = React.useRef(null);

	const swapModel = React.useCallback(
		(oldName, newName) => {
			const prevModel = removedModelRef.current;
			const oldModel = form.model.removeChild(oldName);
			if (oldModel !== null) {
				removedModelRef.current = oldModel;
			}
			if (!form.model.get(newName)) {
				const newModel = preserveState ? prevModel : prevModel.builder.build();
				form.model.registerChild(newName, newModel);
			}
		},
		[form, preserveState]
	);

	const contactTypeValue = Form.useModelValue(form.model.get('contactType'));

	React.useEffect(() => {
		if (contactTypeValue === ContactType.Phone) {
			swapModel('email', 'phone');
		} else {
			swapModel('phone', 'email');
		}
	}, [swapModel, contactTypeValue]);

	const getFormValue = React.useCallback(() => {
		console.log(form.getValue(), form.isValid());
	}, [form]);

	// `useNamedChildModel` will trigger a render whenever a model is removed or registered
	const phoneModel = Form.useNamedChildModel(form.model, 'phone');
	const emailModel = Form.useNamedChildModel(form.model, 'email');

	return (
		<Form className="demo-form" layout="horizontal" form={form}>
			<FormRadioGroupField
				model={form.model.get('contactType')}
				label="{i18n.labelContactType}"
				required
			>
				<Radio value={ContactType.Phone}>{i18n.labelPhone}</Radio>
				<Radio value={ContactType.Email}>{i18n.labelEmail}</Radio>
			</FormRadioGroupField>

			{contactTypeValue === ContactType.Phone && phoneModel && (
				<FormNumberInputField
					model={phoneModel}
					label="{i18n.labelPhone}"
					required
				/>
			)}

			{contactTypeValue === ContactType.Email && emailModel && (
				<FormInputField model={emailModel} label="{i18n.labelEmail}" required />
			)}

			<div style={{ marginTop: 16 }}>
				<Button type="primary" htmlType="submit" onClick={getFormValue}>
					{i18n.printValue}
				</Button>
				<Checkbox
					checked={preserveState}
					onChange={onPreserveStateChange}
					style={{ marginLeft: 16 }}
				>
					{i18n.preserveState}
				</Checkbox>
			</div>
		</Form>
	);
}

ReactDOM.render(<App />, mountNode);
```
