angular5项目积累总结表单复杂校验

Posted sybboy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了angular5项目积累总结表单复杂校验相关的知识,希望对你有一定的参考价值。

view

技术分享图片

code

form.css

:host {
    display: flex;
    width: 100%;
    height:100%;
    border-left:1px solid #ccc;
}
.invalid-box {
    border: 1px solid #a94442;
}

.invalid-error-tip {
    color: #a94442;
}

.select-box {
    width:308px;
    height: 22px;
}
label {
    line-height:20px;
}
.note {
    color:#bbb;
    font-size:12px;
}
.small-input {
    width: 80%;
    height: 19px;
    line-height: 19px;
}
.small-input :-moz-placeholder,
.small-input :-ms-input-placeholder,
.small-input ::-webkit-input-placeholder {
    line-height: 10px;
    font-size: 10px;
}
.sm-textBox-wrapper {
    width: 80%;
}
.sm-textBox-wrapper [placeholder] {
    text-overflow: ellipsis;
    font-style: italic;
}
.sm-textBox-wrapper .azc-input {
    box-sizing: border-box;
    font-size: 12px;
    outline: 0;
    width: 100%;
}
.error-input {
    border-color: #e81123 !important;
    border-style: solid;
    border-width: 1px;
}
.edit-input-wrapper {
    display: inline-block;
    float: left;
}

.error-icon {
    height: 19px;
    width: 10px;
    line-height: 19px;
}

.tootip-balloon-w {
    width: 115px;
}
.fxc-grid2.fxc-grid-sorting a.fxc-sortable {
    height:35px;
}

form.html

<panel-component [menuItems]="menuItems" headerTitle="创建部署" initWidth="400px" (closeEvent)="onClose()">
    <form style="margin:25px; width: 90%;height: 100%;overflow-x: hidden;" #dpyForm="ngForm">
        <div style="width:90%;padding:5px 3px; font-size:12px;">
            <div style="padding-top:4px;">
                <label>App ID:</label>&nbsp;&nbsp;
                <span>{{currApp.name}}</span>
            </div>
        </div>
        <div style="width:90%;padding:5px 3px; font-size:12px;">
            <div style="padding-top:4px;">
                <label>Package ID:</label>&nbsp;&nbsp;
                <span>{{currPkg.version}}</span>
            </div>
        </div>
        <div style="width:90%;padding:5px 3px; font-size:12px;">
            <div class="azc-required-anchor" style="float:left;padding-top:4px;">
                <svg xmlns="http://www.w3.org/2000/svg" class=" fxs-portal-svg" role="presentation" aria-hidden="true" viewBox="0 0 6 6" focusable="false" xmlns:NS1="" NS1:xmlns:svg="http://www.w3.org/2000/svg">
                    <g>
                        <path class="msportalfx-svg-c22" d="M 3.543 2.352 l 2.08 -0.716 L 6 2.687 l -2.076 0.675 L 5.21 5.158 l -0.942 0.676 l -1.242 -1.867 l -1.264 1.867 l -0.97 -0.676 l 1.305 -1.796 L 0 2.687 L 0.38 1.63 l 2.058 0.743 V 0.233 h 1.105 v 2.119 Z" />
                    </g>
                </svg>
            </div>
            <div style="width:200px;float:left;padding-top:4px;">
                <label>请选择级别</label>
            </div>
            <div style="width:90%">
                <select (change)="onValid(null)" class="select-box" [(ngModel)]="currDpy.Level" required name="Level" #level="ngModel" [ngClass]="{‘invalid-box‘: (level.invalid && (level.dirty || level.touched))||showLevelError}">
                    <option *ngFor="let level of lstLevel" [value]=‘level.Key‘>{{level.Value}}</option>
                </select>
                <div *ngIf="(level.invalid && (level.dirty || level.touched))||showLevelError" class="invalid-error-tip">
                     级别为必填字段
                </div>
            </div>
        </div>
        <div style="width:90%;padding:5px 3px; font-size:12px;">
            <div class="azc-required-anchor" style="float:left;padding-top:4px;">
                <svg xmlns="http://www.w3.org/2000/svg" class=" fxs-portal-svg" role="presentation" aria-hidden="true" viewBox="0 0 6 6" focusable="false" xmlns:NS1="" NS1:xmlns:svg="http://www.w3.org/2000/svg">
                    <g>
                        <path class="msportalfx-svg-c22" d="M 3.543 2.352 l 2.08 -0.716 L 6 2.687 l -2.076 0.675 L 5.21 5.158 l -0.942 0.676 l -1.242 -1.867 l -1.264 1.867 l -0.97 -0.676 l 1.305 -1.796 L 0 2.687 L 0.38 1.63 l 2.058 0.743 V 0.233 h 1.105 v 2.119 Z" />
                    </g>
                </svg>
            </div>
            <div style="width:200px;float:left;padding-top:4px;">
                <label>端口号配置</label>
            </div>
            <div style="width:100%">
                <!--列表信息-->
                <div class="ext-hubs-browse-grid fxc-base fxs-grid-focus fxc-grid-sorting fxc-grid-scrolling fxc-grid-resizing fxs-grid-selection fxc-grid-contextMenu fxc-grid-grouping fxc-grid2 azc-control fxc-grid-verticalScroll" style="width: 100%;">
                    <div class="fxc-grid-container azc-br-muted">
                        <div class="fxc-grid-tableContainer azc-br-muted" style="padding-top: 42px;">
                            <div class="fxc-grid-tableScrollContainer azc-br-muted">
                                <table class="fxc-grid-tableHeader fxs-grid-multiselection" data-grid-activation="true">
                                    <thead>
                                        <tr>
                                            <th class="fxc-grid-sorting-header fxc-grid-column-header " style="width: 21%;">
                                                <div class="fxc-grid-header-wrapper">
                                                    <a aria-sort="none" class="fxc-sortable fxc-none">
                                                        <span class="fxc-grid-headerlabel">序号</span>
                                                    </a>
                                                    <div class="fxc-grid-resizableColumn-handle">
                                                        <div class="fxc-grid-resizableColumn-handle-line azc-bg-muted">
                                                        </div>
                                                    </div>
                                                </div>
                                            </th>
                                            <th class="fxc-grid-sorting-header fxc-grid-column-header ">
                                                <div class="fxc-grid-header-wrapper">
                                                    <a aria-sort="none" class="fxc-sortable fxc-none">
                                                        <span class="fxc-grid-headerlabel">Docker镜像</span>
                                                    </a>
                                                    <div class="fxc-grid-resizableColumn-handle">
                                                        <div class="fxc-grid-resizableColumn-handle-line azc-bg-muted">
                                                        </div>
                                                    </div>
                                                </div>
                                            </th>
                                            <th class="fxc-grid-sorting-header fxc-grid-column-header ">
                                                <div class="fxc-grid-header-wrapper">
                                                    <a aria-sort="none" class="fxc-sortable fxc-none">
                                                        <span class="fxc-grid-headerlabel">部署应用</span>
                                                    </a>
                                                    <div class="fxc-grid-resizableColumn-handle">
                                                        <div class="fxc-grid-resizableColumn-handle-line azc-bg-muted">
                                                        </div>
                                                    </div>
                                                </div>
                                            </th>
                                        </tr>
                                    </thead>
                                </table>
                                <div class="fxc-grid-tableContent" style="position: relative; overflow-x: hidden;" >
                                    <table class="fxc-grid-full fxs-grid-multiselection" data-grid-activation="true">
                                        <tbody class="fxc-grid-groupdata ">
                                            <tr class="fxc-grid-row fxs-portal-focus fxs-portal-hover" *ngFor="let port of lstPorts;let i = index">
                                                <td class="fxc-grid-cell azc-br-muted" style="width:10%">
                                                    <span class="fxc-grid-cellContent fxs-ellipsis">
                                                        <span class="msportalfx-gridcolumn-assetsvg-text">{{i}}</span>
                                                    </span>
                                                </td>
                                                <td class="fxc-grid-cell azc-br-muted" style="width:12%;">
                                                    <span class="fxc-grid-cellContent fxs-ellipsis">
                                                        <span class="msportalfx-gridcolumn-assetsvg-text">{{port.docker}}</span>
                                                    </span>
                                                </td>
                                                <td class="fxc-grid-cell azc-br-muted" style="width:20%;">
                                                    <div class="sm-textBox-wrapper" tabindex="-1">
                                                        <div class="edit-input-wrapper">
                                                            <input [(ngModel)]="port.app" (blur)="onValid(i)" (keyup)="onValid(i)" class="azc-input small-input" min="1" pattern="^[1-9]+[0-9]*$" maxlength="5" name="Ports" required type="number" placeholder="输入端口号" tabindex="0" [ngClass]="{‘error-input‘: !port.valid}">
                                                        </div>
                                                        <div *ngIf="!port.valid" class="fxc-base azc-control azc-dockedballoon azc-dockedballoon-validation azc-bg-default fxs-bg-error error-icon" (mouseenter)="toggleBalloonTip($event,true)" (mouseleave)="toggleBalloonTip($event,false)">
                                                            <div class="azc-dockedballoon-anchor">
                                                                <span>
                                                                    <svg height="100%" width="100%" aria-hidden="true" role="presentation" focusable="false">
                                                                        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#FxSymbol0-063"></use>
                                                                    </svg>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                </td>
                                            </tr>
                                        </tbody>
                                    </table>

                                </div>
                            </div>

                        </div>

                    </div>
                    <div [ngClass]="{‘azc-balloon-hidden‘:!isShowBalloon}" class="azc-dockedballoon-balloon azc-dockedballoon-validation azc-bg-default fxc-base azc-control azc-balloon azc-balloon-forcedisplayblock azc-balloon-position-alternate azc-balloon-box-top tootip-balloon-w" [ngStyle]="{‘top.px‘: balloonTop,‘left.px‘: balloonLeft}">
                        <div class="azc-br-muted-80-10 azc-balloon-pointer"></div>
                        <div class="azc-bg-muted-80-10 fxs-text-white azc-balloon-content"><div class="azc-balloon-text">此字段为必填项且长度不超过5位的正整数</div></div>
                    </div>
                </div>

            </div>
        </div>
        <div style="width:90%;padding:5px 3px; font-size:12px;">
            <div class="azc-required-anchor" style="float:left;padding-top:4px;">
                <svg xmlns="http://www.w3.org/2000/svg" class=" fxs-portal-svg" role="presentation" aria-hidden="true" viewBox="0 0 6 6" focusable="false" xmlns:NS1="" NS1:xmlns:svg="http://www.w3.org/2000/svg">
                    <g>
                        <path class="msportalfx-svg-c22" d="M 3.543 2.352 l 2.08 -0.716 L 6 2.687 l -2.076 0.675 L 5.21 5.158 l -0.942 0.676 l -1.242 -1.867 l -1.264 1.867 l -0.97 -0.676 l 1.305 -1.796 L 0 2.687 L 0.38 1.63 l 2.058 0.743 V 0.233 h 1.105 v 2.119 Z" />
                    </g>
                </svg>
            </div>
            <div style="width:200px;float:left;padding-top:4px;">
                <label>实例数</label>
            </div>
            <div style="width:90%">
                <input type="number" min="1" pattern="^[1-9]+[0-9]*$" maxlength="5" (keyup)="onValid(null)" class="azc-input" style="width:305px;" [(ngModel)]="currDpy.InstanceCount" name="InstanceCount" [ngClass]="{‘invalid-box‘: (instanceCount.invalid && (instanceCount.dirty || instanceCount.touched))||showInsCountError}" required  #instanceCount="ngModel" />
                <div *ngIf="(instanceCount.invalid && (instanceCount.dirty || instanceCount.touched))|| showInsCountError" class="invalid-error-tip">
                    实例数为必填字段且为有效数字
                </div>
            </div>
        </div>
        <div style="width:90%;padding:5px 3px; font-size:12px;">
            <div style="width:100%;float:left;padding-top:4px;">
                <label>描述</label>
                <span class="note">(注:多个描述项之间请用英文分号“;”分隔)</span>
            </div>
            <div style="width:90%">
                <textarea class="azc-input" style="width:305px;height:100px" [(ngModel)]="currDpy.Description" name="Description"></textarea>
            </div>
        </div>
    </form>
</panel-component>
<router-outlet></router-outlet>

form.ts

import { Component, ViewChild} from ‘@angular/core‘;
import { Router, ActivatedRoute, Params } from ‘@angular/router‘;
import { AppStoreService } from ‘../service/appStoreService‘;
import { CommonService } from ‘../../providers/commonService‘;

@Component({
    selector: ‘deploy-page‘,
    templateUrl: ‘./deploy.html‘,
    styleUrls: [‘./deploy.css‘]
})

export class DeployPage {

    @ViewChild(‘dpyForm‘) dpyForm;
    constructor(
        private router: Router,
        private actRouter: ActivatedRoute,
        private appStoreService: AppStoreService,
        private comService: CommonService) {
    }
    
    currDpy: any = {
        AppId: "",
        PackageId:"",
        Level:"",
        Description: "",
        InstanceCount: "",
        Ports:""
    };
    id: string;
    pkgId: any;
    currApp: any = {
        id: ‘‘,
        name:‘‘
    };
    currPkg: any = {
        id: ‘‘,
        version:‘‘
    };
    lstPorts: any = [];
    lstLevel: {} = [
        {
            "Key": 0,
            "Value": "高"
        },
        {
            "Key": 1,
            "Value": "中"
        },
        {
            "Key": 2,
            "Value": "低"
        }
    ];
    showLevelError: boolean;
    showInsCountError: boolean;
    isShowBalloon: boolean = false;
    balloonTop: any;
    balloonLeft: any;
    parentUrl: string;
    menuItems: any = [
        { title: "提交", icon: "#FxSymbol0-001", event: this.onSaveDpyInfo.bind(this) }
    ]
    ngOnInit(): void {
        this.actRouter.params.subscribe((params: Params) => {
            this.id = params["id"];
            this.pkgId = params["pkgId"];
        });
        this.appStoreService.GetPkgOne(this.pkgId, (rtv) => {
            this.currPkg = rtv;
            rtv.ports.split(‘,‘).forEach(p => {
                this.lstPorts.push({ ‘docker‘:p,‘app‘:‘‘,‘valid‘:true});
            });
        });
        this.appStoreService.GetAppOne(this.id, (rtv) => {
            this.currApp = rtv;
        });
        this.parentUrl = "/webAppStore/" + this.id + "/version";
    }
    onClose() {
        this.router.navigate([this.parentUrl, { id: this.id, pkgId: this.pkgId }]);
    }
    onValid(index: any) {
        this.showLevelError = this.currDpy.Level ? false : true;
        if (this.currDpy.InstanceCount && /^[1-9][0-9]{0,4}$/.test(this.currDpy.InstanceCount)) {
            this.showInsCountError = false;
        } else {
            this.showInsCountError = true;
        }
        if (index && this.lstPorts[index]) {
            this.validPort(this.lstPorts[index])
        } else {
            this.lstPorts.map(p => this.validPort(p))
        }
    }
    validPort(port: any) {
        port.app && /^[1-9][0-9]{0,4}$/.test(port.app) ? port.valid = true : port.valid = false;
    }
    onSaveDpyInfo() {
        this.onValid(null);
        let emptyItem = this.lstPorts.find(item => { return !item.app || item.valid == false });
        if (this.dpyForm.form.valid && !emptyItem && this.showLevelError == false && this.showInsCountError == false) {
            this.currDpy.AppId = this.currApp.id;
            this.currDpy.PackageId = this.currPkg.id;
            this.lstPorts.forEach(p => delete p.valid);
            this.currDpy.Ports = JSON.stringify(this.lstPorts);
            this.appStoreService.SaveAppDpyInfo(this.currDpy, () => { 
                var notifyBody = { action: ‘refreshWebDpy‘, pkgId: this.pkgId};
                this.comService.notifyOther(notifyBody);
                this.router.navigate([this.parentUrl, { id: this.id, pkgId: this.pkgId }]);
            });
        }
    } 
    toggleBalloonTip(event: any, isShow: boolean) {
        this.isShowBalloon = isShow;
        if (event) {
            this.balloonLeft = event.pageX - 110;
            this.balloonTop = event.pageY - 100;
            event.stopPropagation();
        }
    }
}

 

以上是关于angular5项目积累总结表单复杂校验的主要内容,如果未能解决你的问题,请参考以下文章

angular5项目积累总结消息订阅服务

angular5项目积累总结avatar组件

angular5项目积累总结侧栏菜单 navmenu

angular5项目积累总结breadcrumb面包屑组件

angular5项目积累总结列表多选样式框

angular5项目积累总结遇到的一些问题以及解决办法