In a Web project, we often encounter the requirement of form submission. When there are too many form items, our ordinary logical judgment will add additional if and else judgment, which makes the project very bloated. Next, I summarize the requirement of form submission recently encountered.
Introduction to Policy Mode
Real life example: If we want to travel somewhere, we can choose the route according to the actual situation.
- If you don’t have the time but don’t care about money, you can fly.
- If you don’t have money, you can choose buses or trains.
- If you are a little poorer, you can choose to fly by bike.
There are many ways to implement a function, and the strategy pattern is to encapsulate them one by one, and can achieve mutual substitution.
Next we talk about form validation. If we have a form, the validation logic looks like this:
- The user name is not empty
- The password must contain at least six characters
- The mobile phone number conforms to the format
const registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function() {
if(registerForm.userName ! ="") {
if (registerForm.password.length >= 6) {
if (/ ^ 1 [3 4 5 7 | | | | 8] [0-9] {9} $/.test(registerForm.phoneNumber)) {
alert('success');
} else {
alert('Please enter the correct phone number! ');
return false; }}else {
alert('Password must be no less than six characters');
return false; }}else {
alert("User name cannot be empty!");
return false; }}}Copy the code
The obvious drawback is that the registerForm. onSubmit function is quite large and contains many if-else statements that need to override all the validation rules. If we want to add a validation, we have to change it inside the submission function, which is very reusable.
Refactoring form validation
Next is my recent requirement improvement using the strategy mode. First, after getting a form, I split the components
<div class="fr-title"> Basic information </div><div class="fr__section">
<! - ticket ID -- -- >
<CouponId :couponId="actId" v-if="actId" :isModify="isModify"></CouponId>
<! -- Coupon name (see merchants) -->
<NameComponent ref="refName"></NameComponent>
<! -- Basic information -->
<BaseInfoEditor ref="refBaseInfo"></BaseInfoEditor>
</div><! -- Product selection --><ItemManage ref="refItemManage"></ItemManage>
<div class="fr__section">
<! -- Number of helpers && times -->
<Assistance ref="refAssistance"></Assistance>
</div>
<div class="fr__section">
<! -- power times -->
<Participate ref="refParticipate"></Participate>
</div><! -- Coupon selection --><CouponGive ref="refCouponGive"></CouponGive><! - placeholder - ><div class="mkt-area-inset-bottom"></div><! -- Add button --><div class="mkt-footer">
<div class="mkt-footer-c">
<div class="mkt-area-inset-bottom">
<a class="mkt-footer-btn" @click="handleSave">save</a>
</div>
</div>
</div>
</section>
Copy the code
Child components
_setData, _getData, and _verify methods are exposed in each child component to be called by the parent component.
// Data is backfilled
$_setData(_data) {
this.remarks = _data.remarks;
this.cacheRemarks = this.remarks;
},
// To submit data
$_getData() {
return {
remarks: this.remarks,
}
},
/ / check
$_verify() {
let res = this._checkRemarks();
return res;
},
// Specify the verification rule
_checkRemarks() {
let message = "";
if (!this.remarks) {
message = "Please enter the name of the coupon";
} else if (getTextLength(this.remarks) > MAX_LENGTH) {
message = The name of the coupon cannot exceed${MAX_LENGTH}Word `;
}
return { status: !message, message }
}
Copy the code
The parent component
The parent can use this.$refs to call the internal methods of each child, to save, evaluate, and validate the parent, and to call handleSave() after clicking the save button to commit.
// Create the required parameters
_getParamsByCreate() {
// Coupon name processing
Object.assign(formData,dataProcessing.nameTransferForInf(this.$refs.refName.$_getData()));
}
// Unified verification processing
_checkAll() {
// Determine whether to edit or create
let checkArr = this.isModify ? VALIDATE_ARR_MODIFY : VALIDATE_ARR_CREATE;
let res = { status: true.message: "" };
checkArr.forEach(name= > {
if(res.status && this.$refs[name]) {
res = this.$refs[name].$_verify(); }});/ / save
async handleSave() {
// Verify
let checkRes = this._checkAll();
if(! checkRes.status) {this.$$toast({ content: checkRes.message });
return false;
}
this._createAssistCoupon(); }},Copy the code
If the form changes and we need to backfill the data, then the _setData method of the child component will come in handy.
// Backfill the coupon name
this.$refs.refName.$_setData(dataProcessing.nameTransferForComponent(assistInfo));
Copy the code
One of the scenarios I encountered was that after filling in some data, I went to the commodity selection site and jumped to check some commodities. When I came back, I found that all the data I had filled in before had disappeared. When I printed this, I found that there was no such data. My solution is that the parent component calls the _getData() exposed by each sub-component before jumping to the commodity selection page, and then puts the data on this. After jumping back, the props in Vue are used to dynamically pass the data to each sub-component, and a complex value is performed in the Created hook function of each sub-component. It is important to understand the life cycles of the parent and child components about where the data flow is going. Avoid data loss during transmission.
The life cycle of parent and child components
Parent beforeCreate-> parent create -> child beforeCreate-> child Mounted -> Parent Mounted Child components are mounted, the parent component is not mounted. Therefore, when component data is displayed, API data is retrieved from the parent component mounted, but the child component mounted cannot be retrieved.