分享到58表单提交

前提

最近新增一个表单提交的功能

实现

1.html页面使用form表单,表单监听了submit事件,只要有提交就会触发该submit事件。

如下面这段代码所示:

        <form [formGroup]="formGroup" (ngSubmit)="submitForm()">

2.接收服务器的脚本配置如下:

<!--使用通用的表单标签-->
                <tag xsi:type="define:appGeneralFormTag" style="appGeneralFormTag" name="appGeneralFormTag"
                    xmlns:define="http://pupuwang.com/define"
                    xmlns:plugin="http://pupuwang.com/plugin"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" paramName="gatherForm">
                    <setting formName="opportunity_share"></setting>
                    <table name="opportunity" value="#opportunity">
                        <condition field="opportunity_id" valueStr=":opportunity_id"/>
                        <condition field="plugin_id" valueStr=":plugin_id"/>
                    </table>
                    <formObj formType="mobileInput" formKey="account_thos__mobile" placeHolder="请输入58手机号" label="" value="" showValue="">
                        <rules name="required" value="true" message="请正确填写58同城账号"/>
                        <rules name="pattern" value="^1[35789]\d{9}$" message="请填写11位手机号码"/>
                    </formObj>
                    <formObj formType="codebut" formKey="codebut" label="获取验证码" second="60" placeHolder="输入验证码">
                        <rules name="required" value="true" message="请填写验证码"/>
                        <rules name="pattern" value="^\d{4}$" message="请填写正确的验证码"/>
                        <submit id="verificationCode" type="code"></submit>
                    </formObj>
                    <formObj formType="passwordInput" formKey="account_thos_password" placeHolder="请输入密码" label="" value="" showValue="">
                        <rules name="required" value="true" message="请正确填写58同城密码"/>
                    </formObj>
                    <formObj formType="textInput" formKey="account_thos_nickname" placeHolder="输入显示昵称" label="" value="" showValue="">
                        <rules name="required" value="true" message="请填写正确的昵称"/>
                        <rules name="pattern" value="^[\u4e00-\u9fa5_a-zA-Z_\d_\w!#$%'*+/=?.^_`{|}~-]{2,12}$" message="请输入最多12个字符"/>
                    </formObj>
                    <formObj formType="grayItem"></formObj>
                    <updateTable name = "account_thos">
                        <column name="account_thos_id" value="##opportunity_share__account_thos_id"/>
                        <column name="mobile" value="##opportunity_share__mobile"/>
                        <column name="vcode" value="##opportunity_share__vcode"/>
                        <column name="password" value="##opportunity_share__password"/>
                        <column name="nickname" value="##opportunity_share__nickname"/>
                        <column name="creator" value=":currentUserId()"/>
                    </updateTable>
                </tag>

 

返回的json格式如下:

{
                    "type":"tag",
                    "style":"tag.AppGeneralFormTagLogic",
                    "name":null,
                    "linearLayout":"body",
                    "data":{
                        "htmlObj":[
                            {
                                "compare":false,
                                "formType":"mobileInput",
                                "showValue":"",
                                "canEqual":false,
                                "checkAll":false,
                                "expression":true,
                                "hidden":false,
                                "formKey":"account_thos__mobile",
                                "rules":[
                                    {
                                        "name":"required",
                                        "message":"请正确填写58同城账号",
                                        "value":"true"
                                    },
                                    {
                                        "name":"pattern",
                                        "message":"请填写11位手机号码",
                                        "value":"^1[35789]\d{9}$"
                                    }
                                ],
                                "label":"",
                                "value":"",
                                "placeHolder":"请输入58手机号"
                            }
                        ]
                    }
}

 

我们看上面这个json格式formType用于前端在html页面中展示不同的控件,例如手机号码formType就是mobileInput,验证码就是codeBut,

他有一个初始的显示值,用的是showValue这个字段,formKey则用于表单提交,rules则用于脚本配置这个输入框需要校验是选填还是必填,

并且可以使用正则表达式等展示校验过后的信息,placeHolder则表示表单没有输入的时侯,输入框的提示。

<div class="form-page-bg" (click)="closeClick()" *ngIf="tagData">
  <div class="section">
    <div class="title" [ngStyle]="titleStyle">{{title}}</div>
    <div class="content">
      <p class="sub-title">{{subTitle}}</p>
      <div class="login-form" *ngIf="this.formTagData&&this.formTagData.data" (click)="formClick($event)">
        <form [formGroup]="formGroup" (ngSubmit)="submitForm()">
          <List *ngFor="let item of this.formTagData.data.htmlObj,let i = index" [ngSwitch]="item.formType">
            <ng-container *ngSwitchCase="'mobileInput'">
              <ion-item class="post-item" lines="inset">
                <ion-input type="text" [(ngModel)]="item.value" [placeholder]="item.placeHolder" maxLength="11"
                  [formControlName]="item.formKey">
                </ion-input>
                <button class="vccode" *ngIf="time>-1" [disabled]="time>-1" [ngClass]="{'lightgrey':time>-1}">({{time}})重新获取</button>
                <button [ngClass]="{'lightgrey':formGroup.get('account_thos__mobile').errors}" class="vccode"
                  *ngIf="time===-1" [disabled]="formGroup.get('account_thos__mobile').errors"
                  (click)="getVC(formGroup.get('account_thos__mobile').errors)">获取验证码</button>
              </ion-item>
            </ng-container>
            <ng-container *ngSwitchCase="'codebut'">
              <ion-item class="post-item" lines="inset">
                <ion-input type="text" [(ngModel)]="item.value" [placeholder]="item.placeHolder" maxLength="4"
                  [formControlName]="item.formKey">
                </ion-input>
              </ion-item>
            </ng-container>
            <ng-container *ngSwitchCase="'textInput'">
              <ion-item class="post-item" lines="inset">
                <ion-input type="text" [(ngModel)]="item.value" [placeholder]="item.placeHolder" maxLength="6"
                  [formControlName]="item.formKey">
                </ion-input>
              </ion-item>
            </ng-container>
            <ng-container *ngSwitchCase="'passwordInput'">
              <ion-item class="post-item" lines="inset">
                <ion-input required type="{{open?'text':'password'}}" [(ngModel)]="item.value"
                  [placeholder]="item.placeHolder" [formControlName]="item.formKey">
                </ion-input>
                <span (click)="item.value=''"
                  [ngClass]="{'close_r50': item.value!='','hideClose_r50':item.value===''}"></span>
                <span class="eye" (click)="open=!open" [ngClass]="{'eyeshow':open}"></span>
              </ion-item>
            </ng-container>
          </List>
          <ng-container *ngIf="submitBtn">
            <button class="btn-58" type="submit">{{submitBtn.data[0].label}}</button>
          </ng-container>
        </form>
      </div>
    </div>
  </div>
</div>

我们看到这个ngModal就是对字段做双向绑定的,placeholder就是占位符用于显示提示信息。

3.接下来我们看这个component里面是怎么处理表单的事情的:

按照生命周期,表单首先会创建,

我们看到表单是在初始化component组件的时候创建的。

export class ShareFormModalComponent implements OnInit {
  // 分享页面数据
  shareData = {
    icon: "share.png",
    layout: "right",
    submit: {
      content: {},
      id: "string"
    }
  };
  title = '分享到58';
  subTitle = '请先完善信息,无58账号请先行注册';
  @Input() tagData: any;
  formGroup: FormGroup = new FormGroup({});
  allLabel: any = {};
  formTagData: any;
  submitBtn: any;
  open: boolean;
  time = -1;
  text = "获取验证码";
  constructor(
    private eventService: EventService,
    private router: Router,
    private route: ActivatedRoute,
    private httpService: HttpService,
    private modalController: ModalController,
    private appGlobalService: AppGlobalService,
  ) { }

我们看上面这一段代码,formGroup: FormGroup = new FormGroup({});就是创建表单。

表单实例化之后需要往实例化之后的表单里面添加字段名称和值:

添加值我们这边的处理方式是在component接收tagData之后回到angular的声明周期方法ngOnInit()中调用:

例如:

  ngOnInit() {
    if (this.tagData && this.tagData.tags) {
      this.createFormGroup(this.tagData.tags);
    }
  }

在createFormGroup中我们做什么处理呢?我们添加字段,然后添加字段自定义校验:

createFormGroup(tags) {
    try {
      // tslint:disable-next-line:prefer-for-of
      for (let index = 0; index < tags.length; index++) {
        const element = tags[index];
        if (element.style === "tag.AppGeneralFormTagLogic") {
          this.formTagData = element;
          // tslint:disable-next-line:prefer-for-of
          for (let i = 0; i < this.formTagData.data.htmlObj.length; i++) {
            const formItem = this.formTagData.data.htmlObj[i];
            this.addFormCtrl(formItem);
          }
        } else if (element.style === "countTipsTag") {
          this.subTitle = element.data.tips;
        } else if (element.style === "tag.AppGeneralButtonTagLogic") {
          this.submitBtn = element;
        }
      }
    } catch (error) {

    }
  }

每个字段下可能有子字段也有可能有联动字段所以这里又使用函数addFormCtrl来处理

addFormCtrl(formItem) {
    const that = this;
    // 第一层
    this.addFormControl(formItem);
}

addFormControl(formItem) {
    const that = this;
    if (formItem.formKey && formItem.formKey.length > 1 && !this.formGroup.controls[formItem.formKey]) {
      this.formGroup.addControl(formItem.formKey, new FormControl(formItem.value, that.validators(formItem)));
    }
    if (formItem.rules && formItem.rules.length > 0) {
      const message: any = {};
      formItem.rules.forEach(rule => {
        // 将key 转小写
        message[rule.name.toLowerCase()] = rule.message;
      });
      message.label = formItem.label;
      this.allLabel[formItem.formKey] = message;
    }

    // 设置初始值
    if (formItem.formType === 'textInput' || formItem.formType === 'textInputLJ') {
      if (formItem.tags && formItem.tags.length > 0) {
        formItem.tags.forEach(e => {
          if (e.checked) {
            if (e.label.indexOf('自定义') > -1) {
              formItem.disabled = false;
            } else {
              formItem.disabled = true;
            }
            formItem.value = e.showValue;
            this.formGroup.patchValue({ [formItem.formKey]: e.showValue });
            this.formGroup.addControl(e.formKey, new FormControl(e.value));
          }
        });
      }
    }
  }

表单校验会调用如下方法:

首先是数据校验

  // 数据校验
  validators(item) {
    const validators = [];
    if (item.rules && item.rules.length) {
      item.rules.forEach(rule => {
        if (rule.name === 'required' && rule.value === 'true') {
          validators.push(Validators.required);
        } else if (rule.name === 'minLength') {
          validators.push(Validators.minLength(Number(rule.value)));
        } else if (rule.name === 'maxLength') {
          validators.push(Validators.maxLength(Number(rule.value)));
        } else if (rule.name === 'min') {
          validators.push(Validators.min(Number(rule.value)));
        } else if (rule.name === 'max') {
          validators.push(Validators.max(Number(rule.value)));
        } else if (rule.name === 'pattern') {
          validators.push(Validators.pattern(rule.value));
        }
      });
    }
    return validators;
  }

其次是获取错误信息

getErrors(form) {
    const errs = [];
    for (const name in form.controls) {
      // eg: controls[name] = phone
      if (form.controls[name].errors) {
        errs.push({ key: [name], err: form.controls[name].errors });
      }
    }
    if (errs.length) {
      const errItem = errs[0];

      const firstErrMsgKey = Object.keys(errItem.err)[0];
      console.log(errItem.key, '校验的字段名');
      const messageObj = this.allLabel[errItem.key];
      const showMessage = messageObj[firstErrMsgKey];
      this.appGlobalService.showToast(showMessage, 3000, 'top');
    }
  }

添加好上面这些就可以通过服务器返回的json控制输入框的值,正则表达式校验以及错误信息展示。

接下来我们看下触发表单提交动作的处理:

submitForm() {
    if (this.formGroup.valid) {
      // console.log(this.formGroup.value);
      // tslint:disable-next-line:no-shadowed-variable
      const params = this.formGroup.value;
      // tslint:disable-next-line:forin
      for (const prop in params) {
        if (Array.isArray(params[prop])) {
          params[prop] = params[prop].join(',');
        }
        // 删除无效值
        if (prop === '') {
          // delete params[prop];
        }

      }
      console.log(params);
      // this.onReset();
    } else {
      this.getErrors(this.formGroup);
      return;
      // alert('Validation failed');
    }

    const params = {
      content: {
        mobile: this.formGroup.get('account_thos__mobile').value,
        codebut: this.formGroup.get('codebut').value,
        passWord: this.formGroup.get('account_thos_password').value,
        nickName: this.formGroup.get('account_thos_nickname').value
      },
      id: this.submitBtn.data[0].submit.id,
      sessionId: localStorage.getItem("sessionId")
    };
    this.httpService.post("application/submit", params, res => {
      if (res.success) {
        this.formGroup.reset();
        this.modalController.dismiss();
      } else {
        this.appGlobalService.showToast(res.message, 1500, "middle");
      }
    });

  }

接下来我们看下这个获取验证码自动计时的方法的处理:

正常情况下,我们首先点击获取验证码,通过getVC接口,api后台向用户手机发送验证码,那什么时候可以点击这个获取验证码呢,当然是有条件的。

这个条件就是重来没有点击过,可以在component组件初始化的时候设置一个time变量初始值是-1。

页面就判断这个值是否是-1,如果是-1初始值name就可以点击。

<button [ngClass]="{'lightgrey':formGroup.get('account_thos__mobile').errors}" class="vccode"
                  *ngIf="time===-1" [disabled]="formGroup.get('account_thos__mobile').errors"
                  (click)="getVC(formGroup.get('account_thos__mobile').errors)">获取验证码</button>

其次,如果点击过了则需要展示多少秒之后重新获取,所以还需要在添加一个按钮用于显示重新获取

<button class="vccode" *ngIf="time>-1" [disabled]="time>-1" [ngClass]="{'lightgrey':time>-1}">({{time}})重新获取</button>

接下来我们看下调用api接口获取验证码时的处理:

getVC(invalid) {
    console.log(this.formGroup.get("account_thos__mobile"));
    if (invalid) {
      this.appGlobalService.showToast("请输入正确手机号码", 3000, "top");
    } else {
      let submitId = '';
      let second = 60;
      this.formTagData.data.htmlObj.forEach(element => {
        if (element && element.formType === 'codebut') {
          submitId = element.submit.id;
          second = element.second;
          const params = {
            content: {
              mobile: this.formGroup.value.account_thos__mobile
            },
            id: submitId,
            sessionId: localStorage.getItem("sessionId")
          };
          this.httpService.post("application/submit", params, data => {
            if (data.success) {
              this.appGlobalService.showToast(
                "验证码已发送、请注意查收",
                3000,
                "top"
              );
              if (data.data) {
                console.log('获取验证码:' + data.data.mvcode);
              }
            } else {
              this.appGlobalService.showToast(data.message, 3000, "top");
            }
            this.time = second;
            const timer = setInterval(() => {
              this.time = this.time - 1;
              if (this.time === -1) {
                clearInterval(timer);
                this.text = "获取验证码";
              }
            }, 1000);
          });
        }
      });
    }
  }

我们看到发送完验证码之后会有个timer用于对重新获取验证码进行计时。

总结

将这些知识像插件或者小标签一样拼装在一起使用,也可以单独使用,比较灵活。如果有更好的方法可以留言多谢

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值