Skip to content

Commit

Permalink
feat(module:form): refactor form to support better template driven
Browse files Browse the repository at this point in the history
  • Loading branch information
vthinkxie authored and vthinkxie committed Jun 21, 2019
1 parent 141bef8 commit 10d0e28
Show file tree
Hide file tree
Showing 24 changed files with 423 additions and 228 deletions.
90 changes: 77 additions & 13 deletions components/core/addon/string_template_outlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,114 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import {
Directive,
EmbeddedViewRef,
Input,
OnChanges,
SimpleChange,
SimpleChanges,
TemplateRef,
ViewContainerRef
} from '@angular/core';

@Directive({
selector: '[nzStringTemplateOutlet]',
exportAs: 'nzStringTemplateOutlet'
})
export class NzStringTemplateOutletDirective {
export class NzStringTemplateOutletDirective implements OnChanges {
private isTemplate: boolean;
private inputTemplate: TemplateRef<void> | null = null;
// tslint:disable-next-line:no-any
private inputTemplate: TemplateRef<any> | null = null;
private inputViewRef: EmbeddedViewRef<void> | null = null;
private defaultViewRef: EmbeddedViewRef<void> | null = null;

constructor(private viewContainer: ViewContainerRef, private defaultTemplate: TemplateRef<void>) {}
// tslint:disable-next-line:no-any
@Input() nzStringTemplateOutletContext: any | null = null;

@Input()
set nzStringTemplateOutlet(value: string | TemplateRef<void>) {
// tslint:disable-next-line:no-any
set nzStringTemplateOutlet(value: string | TemplateRef<any>) {
if (value instanceof TemplateRef) {
this.isTemplate = true;
this.inputTemplate = value;
} else {
this.isTemplate = false;
}
this.updateView();
}

updateView(): void {
recreateView(): void {
if (!this.isTemplate) {
/** use default template when input is string **/
if (!this.defaultViewRef) {
this.viewContainer.clear();
this.inputViewRef = null;
if (this.defaultTemplate) {
this.defaultViewRef = this.viewContainer.createEmbeddedView(this.defaultTemplate);
this.defaultViewRef = this.viewContainer.createEmbeddedView(
this.defaultTemplate,
this.nzStringTemplateOutletContext
);
}
}
} else {
/** use input template when input is templateRef **/
if (!this.inputViewRef) {
this.viewContainer.clear();
this.defaultViewRef = null;
if (this.inputTemplate) {
this.inputViewRef = this.viewContainer.createEmbeddedView(this.inputTemplate);
this.inputViewRef = this.viewContainer.createEmbeddedView(
this.inputTemplate,
this.nzStringTemplateOutletContext
);
}
}
}
}

private shouldRecreateView(changes: SimpleChanges): boolean {
const { nzStringTemplateOutletContext, nzStringTemplateOutlet } = changes;
return (
!!nzStringTemplateOutlet ||
(nzStringTemplateOutletContext && this.hasContextShapeChanged(nzStringTemplateOutletContext))
);
}

private hasContextShapeChanged(ctxChange: SimpleChange): boolean {
const prevCtxKeys = Object.keys(ctxChange.previousValue || {});
const currCtxKeys = Object.keys(ctxChange.currentValue || {});

if (prevCtxKeys.length === currCtxKeys.length) {
for (const propName of currCtxKeys) {
if (prevCtxKeys.indexOf(propName) === -1) {
return true;
}
}
return false;
} else {
return true;
}
}

// tslint:disable-next-line:no-any
private updateExistingContext(ctx: any): void {
for (const propName of Object.keys(ctx)) {
// tslint:disable-next-line:no-any
(this.inputViewRef!.context as any)[propName] = this.nzStringTemplateOutletContext[propName];
}
}

constructor(private viewContainer: ViewContainerRef, private defaultTemplate: TemplateRef<void>) {}

ngOnChanges(changes: SimpleChanges): void {
const recreateView = this.shouldRecreateView(changes);

if (recreateView) {
if (this.viewContainer) {
this.viewContainer.clear();
this.defaultViewRef = null;
this.inputViewRef = null;
}
this.recreateView();
} else {
if (this.inputViewRef && this.nzStringTemplateOutletContext) {
this.updateExistingContext(this.nzStringTemplateOutletContext);
}
}
}
}
15 changes: 12 additions & 3 deletions components/form/demo/advanced-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
template: `
<form nz-form [formGroup]="validateForm" class="ant-advanced-search-form">
<div nz-row [nzGutter]="24">
<div nz-col [nzSpan]="8" *ngFor="let control of controlArray" [style.display]="control.show ? 'block' : 'none'">
<div nz-col [nzSpan]="8" *ngFor="let control of controlArray" [hidden]="!control.show">
<nz-form-item nzFlex>
<nz-form-label [nzFor]="'field' + control.index">Field {{ control.index }}</nz-form-label>
<nz-form-control>
Expand All @@ -21,10 +21,10 @@ import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
</div>
</div>
<div nz-row>
<div nz-col [nzSpan]="24" style="text-align: right;">
<div nz-col [nzSpan]="24" class="search-area">
<button nz-button [nzType]="'primary'">Search</button>
<button nz-button (click)="resetForm()">Clear</button>
<a style="margin-left:8px;font-size:12px;" (click)="toggleCollapse()">
<a class="collapse" (click)="toggleCollapse()">
Collapse
<i nz-icon [type]="isCollapse ? 'down' : 'up'"></i>
</a>
Expand Down Expand Up @@ -62,6 +62,15 @@ import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
button {
margin-left: 8px;
}
.collapse {
margin-left: 8px;
font-size: 12px;
}
.search-area {
text-align: right;
}
`
]
})
Expand Down
2 changes: 1 addition & 1 deletion components/form/demo/coordinated.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 11
order: 12
title:
zh-CN: 表单联动
en-US: Coordinated Controls
Expand Down
10 changes: 2 additions & 8 deletions components/form/demo/coordinated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSpan]="5" nzRequired nzFor="note">Note</nz-form-label>
<nz-form-control [nzSpan]="12">
<nz-form-control [nzSpan]="12" nzErrorTip="Please input your username!">
<input id="note" type="text" nz-input formControlName="note" />
<nz-form-explain *ngIf="validateForm.get('note')?.dirty && validateForm.get('note')?.errors"
>Please input your username!</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="5" nzFor="gender" nzRequired>Gender</nz-form-label>
<nz-form-control [nzSpan]="12">
<nz-form-control [nzSpan]="12" nzErrorTip="Please select your gender!">
<nz-select
id="gender"
formControlName="gender"
Expand All @@ -26,9 +23,6 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
<nz-option nzValue="male" nzLabel="male"></nz-option>
<nz-option nzValue="female" nzLabel="female"></nz-option>
</nz-select>
<nz-form-explain *ngIf="validateForm.get('gender')?.dirty && validateForm.get('gender')?.errors"
>Please select your gender!</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
Expand Down
53 changes: 30 additions & 23 deletions components/form/demo/dynamic-form-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,31 @@ import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from
selector: 'nz-demo-form-dynamic-form-item',
template: `
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item *ngFor="let control of controlArray; let i = index">
<nz-form-item *ngFor="let control of listOfControl; let i = index">
<nz-form-label [nzXs]="24" [nzSm]="4" *ngIf="i == 0" [nzFor]="control.controlInstance"
>Passengers</nz-form-label
>Passengers
</nz-form-label>
<nz-form-control
[nzXs]="24"
[nzSm]="20"
[nzOffset]="i == 0 ? 0 : 4"
nzErrorTip="Please input passenger's name or delete this field."
>
<nz-form-control [nzXs]="24" [nzSm]="20" [nzOffset]="i == 0 ? 0 : 4">
<input
class="passenger-input"
nz-input
style="width: 60%; margin-right:8px;"
placeholder="placeholder"
[attr.id]="control.id"
[formControlName]="control.controlInstance"
/>
<i nz-icon type="minus-circle-o" class="dynamic-delete-button" (click)="removeField(control, $event)"></i>
<nz-form-explain
*ngIf="
getFormControl(control.controlInstance)?.dirty &&
getFormControl(control.controlInstance)?.hasError('required')
"
>
Please input passenger's name or delete this field.
</nz-form-explain>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzXs]="{ span: 24, offset: 0 }" [nzSm]="{ span: 20, offset: 4 }">
<button nz-button nzType="dashed" style="width:60%" (click)="addField($event)">
<i nz-icon type="plus"></i> Add field
<button nz-button nzType="dashed" class="add-button" (click)="addField($event)">
<i nz-icon type="plus"></i>
Add field
</button>
</nz-form-control>
</nz-form-item>
Expand All @@ -58,40 +56,49 @@ import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from
color: #777;
}
.passenger-input {
width: 60%;
margin-right: 8px;
}
[nz-form] {
max-width: 600px;
}
.add-button {
width: 60%;
}
`
]
})
export class NzDemoFormDynamicFormItemComponent implements OnInit {
validateForm: FormGroup;
controlArray: Array<{ id: number; controlInstance: string }> = [];
listOfControl: Array<{ id: number; controlInstance: string }> = [];

addField(e?: MouseEvent): void {
if (e) {
e.preventDefault();
}
const id = this.controlArray.length > 0 ? this.controlArray[this.controlArray.length - 1].id + 1 : 0;
const id = this.listOfControl.length > 0 ? this.listOfControl[this.listOfControl.length - 1].id + 1 : 0;

const control = {
id,
controlInstance: `passenger${id}`
};
const index = this.controlArray.push(control);
console.log(this.controlArray[this.controlArray.length - 1]);
const index = this.listOfControl.push(control);
console.log(this.listOfControl[this.listOfControl.length - 1]);
this.validateForm.addControl(
this.controlArray[index - 1].controlInstance,
this.listOfControl[index - 1].controlInstance,
new FormControl(null, Validators.required)
);
}

removeField(i: { id: number; controlInstance: string }, e: MouseEvent): void {
e.preventDefault();
if (this.controlArray.length > 1) {
const index = this.controlArray.indexOf(i);
this.controlArray.splice(index, 1);
console.log(this.controlArray);
if (this.listOfControl.length > 1) {
const index = this.listOfControl.indexOf(i);
this.listOfControl.splice(index, 1);
console.log(this.listOfControl);
this.validateForm.removeControl(i.controlInstance);
}
}
Expand Down
10 changes: 2 additions & 8 deletions components/form/demo/dynamic-rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,16 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSpan]="4" nzRequired nzFor="name">Name</nz-form-label>
<nz-form-control [nzSpan]="8">
<nz-form-control [nzSpan]="8" nzErrorTip="Please input your name">
<input type="text" nz-input formControlName="name" placeholder="Please input your name" />
<nz-form-explain *ngIf="validateForm.get('name')?.dirty && validateForm.get('name')?.errors"
>Please input your name</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="4" nzFor="nickname" [nzRequired]="validateForm.get('required')?.value"
>Nickname</nz-form-label
>
<nz-form-control [nzSpan]="8">
<nz-form-control [nzSpan]="8" nzErrorTip="Please input your nickname">
<input type="text" nz-input formControlName="nickname" placeholder="Please input your nickname" />
<nz-form-explain *ngIf="validateForm.get('nickname')?.dirty && validateForm.get('nickname')?.errors"
>Please input your nickname</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
Expand Down
16 changes: 4 additions & 12 deletions components/form/demo/horizontal-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,17 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
template: `
<form nz-form [nzLayout]="'inline'" [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-control>
<nz-input-group [nzPrefix]="prefixUser">
<nz-form-control nzErrorTip="Please input your username!">
<nz-input-group nzPrefixIcon="user">
<input formControlName="userName" nz-input placeholder="Username" />
</nz-input-group>
<nz-form-explain *ngIf="validateForm.get('userName')?.dirty && validateForm.get('userName')?.errors"
>Please input your username!</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control>
<nz-input-group [nzPrefix]="prefixLock">
<nz-form-control nzErrorTip="Please input your Password!">
<nz-input-group nzPrefixIcon="lock">
<input formControlName="password" nz-input type="password" placeholder="Password" />
</nz-input-group>
<nz-form-explain *ngIf="validateForm.get('password')?.dirty && validateForm.get('password')?.errors"
>Please input your Password!</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
Expand All @@ -31,8 +25,6 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
</nz-form-control>
</nz-form-item>
</form>
<ng-template #prefixUser><i nz-icon type="user"></i></ng-template>
<ng-template #prefixLock><i nz-icon type="lock"></i></ng-template>
`
})
export class NzDemoFormHorizontalLoginComponent implements OnInit {
Expand Down
10 changes: 2 additions & 8 deletions components/form/demo/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,14 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="isHorizontal ? 4 : null">Field A</nz-form-label>
<nz-form-control [nzSpan]="isHorizontal ? 14 : null">
<nz-form-control [nzSpan]="isHorizontal ? 14 : null" nzErrorTip="Please input your username!">
<input nz-input formControlName="fieldA" placeholder="input placeholder" />
<nz-form-explain *ngIf="validateForm.get('fieldA')?.dirty && validateForm.get('fieldA')?.errors"
>Please input your username!</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="isHorizontal ? 4 : null">Field B</nz-form-label>
<nz-form-control [nzSpan]="isHorizontal ? 14 : null">
<nz-form-control [nzSpan]="isHorizontal ? 14 : null" nzErrorTip="Please input your Password!">
<input nz-input formControlName="filedB" placeholder="input placeholder" />
<nz-form-explain *ngIf="validateForm.get('filedB')?.dirty && validateForm.get('filedB')?.errors"
>Please input your Password!</nz-form-explain
>
</nz-form-control>
</nz-form-item>
<nz-form-item>
Expand Down
Loading

0 comments on commit 10d0e28

Please sign in to comment.