This commit is contained in:
CHEVALLIER Abel
2025-11-13 16:23:22 +01:00
parent de9c515a47
commit cb235644dc
34924 changed files with 3811102 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<form nz-form [nzAutoTips]="autoTips" [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Username</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidatingTip="Validating...">
<input nz-input formControlName="username" placeholder="async validate try to write JasonWood" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Mobile</nz-form-label>
<nz-form-control [nzSpan]="12">
<input nz-input formControlName="mobile" placeholder="mobile" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>E-mail</nz-form-label>
<nz-form-control [nzSpan]="12">
<input nz-input formControlName="email" placeholder="email" type="email" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzDisableAutoTips nzErrorTip="Please input your password!">
<input nz-input type="password" formControlName="password" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Confirm Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzDisableAutoTips [nzErrorTip]="passwordErrorTpl">
<input nz-input type="password" formControlName="confirm" placeholder="confirm your password" />
<ng-template #passwordErrorTpl let-control>
@if (control.errors?.['required']) {
Please confirm your password!
}
@if (control.errors?.['confirm']) {
Password is inconsistent!
}
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzOffset]="7" [nzSpan]="12">
<button nz-button nzType="primary">Submit</button>
</nz-form-control>
</nz-form-item>
</form>

View File

@@ -0,0 +1,23 @@
import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';
describe('<%= classify(name) %>Component', () => {
let component: <%= classify(name) %>Component;
let fixture: ComponentFixture<<%= classify(name) %>Component>;
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
declarations: [ <%= classify(name) %>Component ]
})
.compileComponents();
;
fixture = TestBed.createComponent(<%= classify(name) %>Component);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,194 @@
import { Component, inject, OnDestroy, OnInit } from '@angular/core';
import {
AbstractControl,
NonNullableFormBuilder,
ReactiveFormsModule,
ValidationErrors,
ValidatorFn,
Validators
} from '@angular/forms';
import { Observable, Observer, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzInputModule } from 'ng-zorro-antd/input';
@Component({
selector: '<%= selector %>',
imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule],
<% if(inlineTemplate) { %>template: `
<form nz-form [nzAutoTips]="autoTips" [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Username</nz-form-label>
<nz-form-control [nzSpan]="12" nzValidatingTip="Validating...">
<input nz-input formControlName="username" placeholder="async validate try to write JasonWood" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Mobile</nz-form-label>
<nz-form-control [nzSpan]="12">
<input nz-input formControlName="mobile" placeholder="mobile" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>E-mail</nz-form-label>
<nz-form-control [nzSpan]="12">
<input nz-input formControlName="email" placeholder="email" type="email" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzDisableAutoTips nzErrorTip="Please input your password!">
<input nz-input type="password" formControlName="password" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzRequired>Confirm Password</nz-form-label>
<nz-form-control [nzSpan]="12" nzDisableAutoTips [nzErrorTip]="passwordErrorTpl">
<input nz-input type="password" formControlName="confirm" placeholder="confirm your password" />
<ng-template #passwordErrorTpl let-control>
@if (control.errors?.['required']) {
Please confirm your password!
}
@if (control.errors?.['confirm']) {
Password is inconsistent!
}
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzOffset]="7" [nzSpan]="12">
<button nz-button nzType="primary">Submit</button>
</nz-form-control>
</nz-form-item>
</form>
`<% } else { %>templateUrl: './<%= dasherize(name) %>.component.html'<% } %>,
<% if(inlineStyle) { %>styles: [`
[nz-form] {
max-width: 600px;
}
`]<% } else { %>styleUrls: ['./<%= dasherize(name) %>.component.<%= style %>']<% } %>
})
export class <%= classify(name) %>Component implements OnInit, OnDestroy {
private fb = inject(NonNullableFormBuilder);
private destroy$ = new Subject<void>();
validateForm = this.fb.group({
username: this.fb.control(
'',
[MyValidators.required, MyValidators.maxLength(12), MyValidators.minLength(6)],
[this.usernameAsyncValidator]
),
mobile: this.fb.control('', [MyValidators.required, MyValidators.mobile]),
email: this.fb.control('', [MyValidators.required, MyValidators.email]),
password: this.fb.control('', [MyValidators.required]),
confirm: this.fb.control('', [this.confirmValidator])
});
// current locale is key of the nzAutoTips
// if it is not found, it will be searched again with `default`
autoTips: Record<string, Record<string, string>> = {
'zh-cn': {
required: '必填项'
},
en: {
required: 'Input is required'
},
default: {
email: '邮箱格式不正确/The input is not valid email'
}
};
ngOnInit(): void {
this.validateForm.controls.password.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.validateForm.controls.confirm.updateValueAndValidity();
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
submitForm(): void {
if (this.validateForm.valid) {
console.log('submit', this.validateForm.value);
} else {
Object.values(this.validateForm.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
}
}
usernameAsyncValidator(control: AbstractControl): Observable<ValidationErrors | null> {
return new Observable((observer: Observer<MyValidationErrors | null>) => {
setTimeout(() => {
if (control.value === 'JasonWood') {
observer.next({
duplicated: { 'zh-cn': `用户名已存在`, en: `The username is redundant!` }
});
} else {
observer.next(null);
}
observer.complete();
}, 1000);
});
}
confirmValidator(control: AbstractControl): ValidationErrors | null {
if (!control.value) {
return { error: true, required: true };
} else if (control.value !== this.validateForm.controls.password.value) {
return { confirm: true, error: true };
}
return {};
}
}
// current locale is key of the MyErrorsOptions
export type MyErrorsOptions = { 'zh-cn': string; en: string } & Record<string, NzSafeAny>;
export type MyValidationErrors = Record<string, MyErrorsOptions>;
export class MyValidators extends Validators {
static override minLength(minLength: number): ValidatorFn {
return (control: AbstractControl): MyValidationErrors | null => {
if (Validators.minLength(minLength)(control) === null) {
return null;
}
return { minlength: { 'zh-cn': `最小长度为 ${minLength}`, en: `MinLength is ${minLength}` } };
};
}
static override maxLength(maxLength: number): ValidatorFn {
return (control: AbstractControl): MyValidationErrors | null => {
if (Validators.maxLength(maxLength)(control) === null) {
return null;
}
return { maxlength: { 'zh-cn': `最大长度为 ${maxLength}`, en: `MaxLength is ${maxLength}` } };
};
}
static mobile(control: AbstractControl): MyValidationErrors | null {
const value = control.value;
if (isEmptyInputValue(value)) {
return null;
}
return isMobile(value)
? null
: { mobile: { 'zh-cn': `手机号码格式不正确`, en: `Mobile phone number is not valid` } };
}
}
function isEmptyInputValue(value: NzSafeAny): boolean {
return value == null || value.length === 0;
}
function isMobile(value: string): boolean {
return typeof value === 'string' && /(^1\d{10}$)/.test(value);
}

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
const schematics_1 = require("@angular-devkit/schematics");
const build_component_1 = require("../../utils/build-component");
function default_1(options) {
return (0, schematics_1.chain)([
(0, build_component_1.buildComponent)(Object.assign({}, options), {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template'
})
]);
}
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../schematics/demo/form-auto-tips/index.ts"],"names":[],"mappings":";;AAQA,4BAUC;AAlBD,2DAGoC;AACpC,iEAA6D;AAI7D,mBAAwB,OAAe;IACrC,OAAO,IAAA,kBAAK,EAAC;QACX,IAAA,gCAAc,oBACP,OAAO,GACZ;YACE,QAAQ,EAAE,kFAAkF;YAC5F,UAAU,EAAE,uFAAuF;SACpG,CACF;KACF,CAAC,CAAC;AACL,CAAC"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=schema.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../schematics/demo/form-auto-tips/schema.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1 @@
{"$schema":"http://json-schema.org/schema","$id":"auto-tips-form","title":"NG-ZORRO auto-tips form","type":"object","properties":{"path":{"type":"string","format":"path","description":"The path to create the component.","visible":false},"project":{"type":"string","description":"The name of the project.","$default":{"$source":"projectName"}},"name":{"type":"string","description":"The name of the component.","$default":{"$source":"argv","index":0},"x-prompt":"What should be the name of the component?"},"inlineStyle":{"description":"When true, includes styles inline in the component.ts file. Only CSS styles can be included inline. By default, an external styles file is created and referenced in the component.ts file.","type":"boolean","default":false,"alias":"s"},"inlineTemplate":{"description":"When true, includes template inline in the component.ts file. By default, an external template file is created and referenced in the component.ts file.","type":"boolean","default":false,"alias":"t"},"standalone":{"description":"Whether the generated component is standalone.","type":"boolean"},"prefix":{"type":"string","description":"The prefix to apply to the generated component selector.","alias":"p","oneOf":[{"maxLength":0},{"minLength":1,"format":"html-selector"}]},"styleext":{"description":"The file extension to use for style files.","type":"string","default":"css","x-deprecated":"Use \"style\" instead."},"style":{"description":"The file extension or preprocessor to use for style files.","type":"string","default":"css","enum":["css","scss","sass","less","styl"]},"spec":{"type":"boolean","description":"When true (the default), generates a \"spec.ts\" test file for the new component.","default":true,"x-deprecated":"Use \"skipTests\" instead."},"skipTests":{"type":"boolean","description":"When true, does not create \"spec.ts\" test files for the new component."},"flat":{"type":"boolean","description":"Flag to indicate if a dir is created.","default":false},"skipImport":{"type":"boolean","description":"When true, does not import this component into the owning NgModule."},"selector":{"type":"string","format":"html-selector","description":"The selector to use for the component."},"module":{"type":"string","description":"Allows specification of the declaring module.","alias":"m"},"export":{"type":"boolean","default":false,"description":"When true, the declaring NgModule exports this component."},"entryComponent":{"type":"boolean","default":false,"description":"When true, the new component is the entry component of the declaring NgModule."},"classnameWithModule":{"type":"boolean","description":"When true, Use module class name as additional prefix for the component classname.","default":false}},"required":["name"]}