zoukankan      html  css  js  c++  java
  • 【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;  90%;height: 100%;overflow-x: hidden;" #dpyForm="ngForm">
            <div style="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="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="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="200px;float:left;padding-top:4px;">
                    <label>请选择级别</label>
                </div>
                <div style="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="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="200px;float:left;padding-top:4px;">
                    <label>端口号配置</label>
                </div>
                <div style="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=" 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=" 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="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="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="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="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="200px;float:left;padding-top:4px;">
                    <label>实例数</label>
                </div>
                <div style="90%">
                    <input type="number" min="1" pattern="^[1-9]+[0-9]*$" maxlength="5" (keyup)="onValid(null)" class="azc-input" style="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="90%;padding:5px 3px; font-size:12px;">
                <div style="100%;float:left;padding-top:4px;">
                    <label>描述</label>
                    <span class="note">(注:多个描述项之间请用英文分号“;”分隔)</span>
                </div>
                <div style="90%">
                    <textarea class="azc-input" style="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();
            }
        }
    }
  • 相关阅读:
    应用服务器安装
    datasnap的线程池
    压缩OLEVARIANT数据
    服务端日志记录
    提交主从表的多个已经修改的数据
    MySQL与PostgreSQL相比哪个更好?
    Vue入门常用指令详解
    Laravel模型事件的实现原理详解
    Git 遇到了 early EOF indexpack failed 问题
    Laravel 代码开发最佳实践
  • 原文地址:https://www.cnblogs.com/sybboy/p/8386154.html
Copyright © 2011-2022 走看看