步骤:

  1. 编写正常子组件一样,先编写好
  2. 实现相应的接口
  3. 调用相应表单控件
import {ChangeDetectionStrategy, Component, EventEmitter, forwardRef, Input, Output} from '@angular/core';
//引入相应的表单文件
import {ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR} from '@angular/forms';

@Component({
  selector: 'app-image-list-select',
  templateUrl: './image-list-select.component.html',
  styleUrls: ['./image-list-select.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ImageListSelectComponent),//向前引用
      multi: true, //多对一
    },
    {
      provide: NG_VALIDATORS, //验证器注册
      useExisting: forwardRef(() => ImageListSelectComponent),
      multi: true,
    }
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ImageListSelectComponent implements ControlValueAccessor {

  selected: string;
  @Input() title = '选择封面:';
  @Input() items: string[] = [];
  @Input() cols = 8;
  @Input() rowHeight = '64px';
  @Input() itemWidth = '80px';
  @Input() useSvgIcon = false;
  @Output('itemChange') itemChange = new EventEmitter<string>();

  // 这里是做一个空函数体,真正使用的方法在 registerOnChange 中
  // 由框架注册,然后我们使用它把变化发回表单
  // 注意,和 EventEmitter 尽管很像,但发送回的对象不同
  private propagateChange = (_: any) => {};

  // 写入控件值,调用者通过setValue写入的位置
  public writeValue(obj: any) {
    if (obj && obj !== '') {
      this.selected = obj;
    }
  }

  // 当表单控件值改变时,函数 fn 会被调用
  // 这也是我们把变化 emit 回表单的机制
  public registerOnChange(fn: any) {
    this.propagateChange = fn;
  }

  // 验证表单,验证结果正确返回 null 否则返回一个验证结果对象
  public validate(c: FormControl) {
    return this.selected ? null : {
      imageListSelect: {
        valid: false,
      },
    };
  }

  // 这里没有使用,用于注册 touched 状态
  public registerOnTouched() {
  }

  // 列表元素选择发生改变触发
  onChange(i) {
    this.selected = this.items[i];


    // 更新表单,这样表单通过get可以获取到最新值
    this.propagateChange(this.items[i]);
    this.itemChange.emit(this.items[i]);
  }
}

调用控件代码展示

<app-image-list-select 
    [useSvgIcon]="true"
    [cols]="6"
    [title]="'选择头像:'"
    [items]="items"
    formControlName="avatar"
></app-image-list-select>

IpList表单控件模板

import { Component, Input, OnInit, forwardRef } from "@angular/core";
import { compact, concat, uniq, difference } from "lodash";
import {
  ControlValueAccessor,
  NG_VALIDATORS,
  NG_VALUE_ACCESSOR
} from "@angular/forms";
@Component({
  selector: "agent-install-iplist",
  templateUrl: "./agent-install-iplist.component.html",
  styleUrls: ["./agent-install-iplist.component.scss"],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => AgentInstallIplistComponent), // 向前引用
      multi: true // 多对一
    },
    {
      provide: NG_VALIDATORS, // 验证器注册
      useExisting: forwardRef(() => AgentInstallIplistComponent),
      multi: true
    }
  ]
})
export class AgentInstallIplistComponent
  implements OnInit, ControlValueAccessor {
  @Input() allAgentIPArray; // agent 安装 ip 列表
  @Input() inputIpList;
  allIpList: string[] = []; // 全部Ip列表
  trueIpList: string[] = []; // 正确Ip列表
  falseIpList: string[] = []; // 错误IP列表
  hasFalseIp = false; // 控制是否有错误IP,如果有的话,隐藏安装按钮
  IpReg = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
  constructor() {}
  ngOnInit() {
    this.ipCheck(this.allAgentIPArray);
  }
  // 这里是做一个空函数体,真正使用的方法在 registerOnChange 中
  // 由框架注册,然后我们使用它把变化发回表单
  // 注意,和 EventEmitter 尽管很像,但发送回的对象不同
  private propagateChange = (_: any) => {};

  // 写入控件值,调用者通过setValue写入的位置
  public writeValue(obj: string | null) {
    if (obj !== null && obj !== "") {
      this.classIpMain(obj);
    }
  }

  // 当表单控件值改变时,函数 fn 会被调用
  // 这也是我们把变化 emit 回表单的机制
  public registerOnChange(fn: any) {
    this.propagateChange = fn;
  }

  // 验证表单,验证结果正确返回 null, 否则返回一个验证结果对象
  public validate() {
    return !this.hasFalseIp && this.trueIpList.length > 0
      ? null
      : {
          hasFalseIp: {
            valid: false
          }
        };
  }

  // 这里没有使用,用于注册 touched 状态
  public registerOnTouched() {}

  // IP分类函数,入口为字符串,输出是正确,错误,全部IP
  classIpMain(ipString: string) {
    const list = this.ipCut(ipString);
    const removeEmpty = compact(list);
    this.ipCheck(removeEmpty);
  }
  // IP分割
  ipCut(ipString: string) {
    return ipString.split(/[\s\n,]/);
  }
  // IP分类
  ipCheck(listArr: string[]) {
    listArr.forEach(current => {
      if (this.IpReg.test(current)) {
        this.addTrueList(current);
      } else {
        this.addFalseList(current);
      }
    });
    this.upDataAllIpList();
  }
  // 更新总IP列表 + 更新一些状态值
  upDataAllIpList() {
    this.allIpList = concat(this.trueIpList, this.falseIpList);
    this.hasFalseIp = this.falseIpList.length > 0;
    this.propagateChange(this.trueIpList);
  }
  // 清空IP列表
  clearAllIpList() {
    this.trueIpList = [];
    this.falseIpList = [];
    this.upDataAllIpList();
  }
  // 添加进正确列表
  addTrueList(ip: string) {
    this.trueIpList.unshift(ip);
    this.trueIpList = uniq(this.trueIpList);
  }
  // 添加进错误列表
  addFalseList(ip: string) {
    this.falseIpList.unshift(ip);
    this.falseIpList = uniq(this.falseIpList);
  }
  // 删除错误Ip
  deleteFalseIp(fIp: string) {
    this.falseIpList = difference(this.falseIpList, [fIp]);
    this.upDataAllIpList();
  }
  // 删除正确Ip
  deleteTrueIp(tIp: string) {
    this.trueIpList = difference(this.trueIpList, [tIp]);
    this.upDataAllIpList();
  }
  // 编辑错误Ip列表
  editIp(oldVal: string, newVal: string) {
    if (newVal === oldVal || newVal === "") {
      return false;
    }
    if (this.IpReg.test(newVal)) {
      this.addTrueList(newVal);
    } else {
      this.addFalseList(newVal);
    }
    this.deleteFalseIp(oldVal);
    this.deleteTrueIp(oldVal);
  }
}
Copyright © frankshi.com 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-06-04 07:53:15

results matching ""

    No results matching ""