Skip to content

Commit

Permalink
feat(module:transfer): add canMove property & make component using On…
Browse files Browse the repository at this point in the history
…Push (#824)
  • Loading branch information
cipchk authored and wilsoncook committed Dec 30, 2017
1 parent 1433644 commit d31c596
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 25 deletions.
97 changes: 74 additions & 23 deletions src/components/transfer/nz-transfer.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,47 @@
// tslint:disable:member-ordering
import { Component, ContentChild, EventEmitter, Input, OnChanges, Output, SimpleChanges, TemplateRef, ViewEncapsulation } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild,
ElementRef,
EventEmitter,
Input,
OnChanges,
Output,
SimpleChanges,
TemplateRef,
ViewEncapsulation
} from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { ArrayObservable } from 'rxjs/observable/ArrayObservable';
import { NzLocaleService } from '../locale/index';
import { toBoolean } from '../util/convert';
import { TransferItem } from './item';

export interface TransferCanMove {
direction: string;
list: TransferItem[];
}

export interface TransferChange {
from: string;
to: string;
list: TransferItem[];
}

export interface TransferSearchChange {
direction: string;
value: string;
}

export interface TransferSelectChange {
direction: string;
checked: boolean;
list: TransferItem[];
item: TransferItem;
}

@Component({
selector: 'nz-transfer',
template: `
Expand Down Expand Up @@ -54,7 +92,8 @@ import { TransferItem } from './item';
// tslint:disable-next-line:use-host-property-decorator
host: {
'[class.ant-transfer]': 'true'
}
},
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NzTransferComponent implements OnChanges {
private _showSearch = false;
Expand All @@ -70,6 +109,7 @@ export class NzTransferComponent implements OnChanges {
@Input() nzListStyle: object;
@Input() nzItemUnit = this._locale.translate('Transfer.itemUnit');
@Input() nzItemsUnit = this._locale.translate('Transfer.itemsUnit');
@Input() canMove: (arg: TransferCanMove) => Observable<TransferItem[]> = (arg: TransferCanMove) => ArrayObservable.of(arg.list);
@ContentChild('render') render: TemplateRef<void>;
@ContentChild('footer') footer: TemplateRef<void>;

Expand All @@ -88,10 +128,9 @@ export class NzTransferComponent implements OnChanges {
@Input() nzNotFoundContent = this._locale.translate('Transfer.notFoundContent');

// events
// TODO: use named interface
@Output() nzChange: EventEmitter<{ from: string, to: string, list: TransferItem[] }> = new EventEmitter();
@Output() nzSearchChange: EventEmitter<{ direction: string, value: string }> = new EventEmitter();
@Output() nzSelectChange: EventEmitter<{ direction: string, checked: boolean, list: TransferItem[], item: TransferItem }> = new EventEmitter();
@Output() nzChange: EventEmitter<TransferChange> = new EventEmitter();
@Output() nzSearchChange: EventEmitter<TransferSearchChange> = new EventEmitter();
@Output() nzSelectChange: EventEmitter<TransferSelectChange> = new EventEmitter();

// endregion

Expand Down Expand Up @@ -133,6 +172,7 @@ export class NzTransferComponent implements OnChanges {

handleFilterChange(ret: { direction: string, value: string }): void {
this.nzSearchChange.emit(ret);
this.cd.detectChanges();
}

// endregion
Expand All @@ -142,46 +182,57 @@ export class NzTransferComponent implements OnChanges {
leftActive = false;
rightActive = false;

private updateOperationStatus(direction: string, count: number): void {
this[direction === 'right' ? 'leftActive' : 'rightActive'] = count > 0;
private updateOperationStatus(direction: string, count?: number): void {
this[direction === 'right' ? 'leftActive' : 'rightActive'] = (typeof count === 'undefined' ? this.getCheckedData(direction).filter(w => !w.disabled).length : count) > 0;
this.cd.detectChanges();
}

moveToLeft = () => this.moveTo('left');
moveToRight = () => this.moveTo('right');

moveTo(direction: string): void {
const oppositeDirection = direction === 'left' ? 'right' : 'left';
this.updateOperationStatus(oppositeDirection, 0);
const datasource = direction === 'left' ? this.rightDataSource : this.leftDataSource;
const moveList = datasource.filter(item => item.checked === true && !item.disabled);
this.canMove({ direction, list: moveList })
.subscribe(
newMoveList => this.truthMoveTo(direction, newMoveList.filter(i => !!i)),
() => moveList.forEach(i => i.checked = false)
);
}

private truthMoveTo(direction: string, list: TransferItem[]): void {
const oppositeDirection = direction === 'left' ? 'right' : 'left';
const datasource = direction === 'left' ? this.rightDataSource : this.leftDataSource;
const targetDatasource = direction === 'left' ? this.leftDataSource : this.rightDataSource;
const moveList: TransferItem[] = [];
for (let i = 0; i < datasource.length; i++) {
const item = datasource[i];
if (item.checked === true && !item.disabled) {
item.checked = false;
moveList.push(item);
targetDatasource.push(item);
datasource.splice(i, 1);
--i;
}
for (const item of list) {
const idx = datasource.indexOf(item);
if (idx === -1) continue;
item.checked = false;
targetDatasource.push(item);
datasource.splice(idx, 1);
}
this.updateOperationStatus(oppositeDirection, 0);
this.updateOperationStatus(oppositeDirection);
this.nzChange.emit({
from: oppositeDirection,
to: direction,
list: moveList
list
});
// this.nzSelectChange.emit({ direction: oppositeDirection, list: [] });
}

// endregion

constructor(private _locale: NzLocaleService) {}
constructor(private _locale: NzLocaleService, private el: ElementRef, private cd: ChangeDetectorRef) {
}

ngOnChanges(changes: SimpleChanges): void {
if ('nzDataSource' in changes || 'nzTargetKeys' in changes) {
this.splitDataSource();
this.updateOperationStatus('left', this.leftDataSource.filter(w => w.checked && !w.disabled).length);
this.updateOperationStatus('right', this.rightDataSource.filter(w => w.checked && !w.disabled).length);
this.updateOperationStatus('left');
this.updateOperationStatus('right');
}
this.cd.detectChanges();
}
}
37 changes: 36 additions & 1 deletion src/components/transfer/nz-transfer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { async, fakeAsync, tick, ComponentFixture, ComponentFixtureAutoDetect, T
import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ArrayObservable } from 'rxjs/observable/ArrayObservable';
import { NzButtonModule } from '../button/nz-button.module';
import { NzTransferModule } from '../ng-zorro-antd.module';
import { TransferItem } from './item';
Expand Down Expand Up @@ -38,6 +39,17 @@ const RENDER = `
</nz-transfer>
`;

const CANMOVE = `
<nz-transfer [nzDataSource]="list" [canMove]="canMove">
<ng-template #render let-item>
[OK]{{item.title}}-{{item.description}}
</ng-template>
<ng-template #footer let-direction>
<button nz-button (click)="reload(direction)" [nzSize]="'small'" style="float: right; margin: 5px;">reload</button>
</ng-template>
</nz-transfer>
`;

const DATA = [];
for (let i = 0; i < 20; i++) {
DATA.push({
Expand Down Expand Up @@ -82,6 +94,7 @@ describe('NzTransferModule', () => {
spyOn(context, 'change');
spyOn(context, 'search');
spyOn(context, 'reload');
spyOn(context, 'canMove');
spyOn(context, 'nzFilterOption');
dl = fixture.debugElement;
el = fixture.nativeElement;
Expand Down Expand Up @@ -176,6 +189,23 @@ describe('NzTransferModule', () => {
});
});

describe('#canMove', () => {
beforeEach(() => {
createTestModule(CANMOVE);
});

it('should be', () => {
context.list = [ ...DATA ].map((item, idx) => {
if (idx <= 3) item.checked = true;
return item;
});
fixture.detectChanges();
(el.querySelectorAll(`.ant-transfer-operation .ant-btn`)[1] as HTMLButtonElement).click();
fixture.detectChanges();
expect(context.canMove).toHaveBeenCalled();
});
});

});

@Component({ template: '' })
Expand All @@ -186,12 +216,17 @@ class TestTransferComponent {
nzSearchPlaceholder = 'nzSearchPlaceholder';
nzNotFoundContent = 'nzNotFoundContent';
nzFilterOption(inputValue: string, option: TransferItem): boolean {
console.log(inputValue, option);
return option.description.indexOf(inputValue) > -1;
}

select(): void { }
change(): void { }
search(): void { }
reload(): void { }
canMove(arg: any) {
if (arg.direction === 'right' && arg.list.length > 0) arg.list.splice(0, 1);
// or
// if (arg.direction === 'right' && arg.list.length > 0) delete arg.list[0];
return ArrayObservable.of(arg.list);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Component, OnInit } from '@angular/core';
import { ArrayObservable } from 'rxjs/observable/ArrayObservable';
import { delay } from 'rxjs/operators';
import { NzMessageService } from '../../../index.showcase';

@Component({
selector: 'nz-demo-transfer-can-move',
template: `
<nz-transfer
[nzDataSource]="list"
[nzTitles]="['Source', 'Target']"
[canMove]="canMove"
(nzSelectChange)="select($event)"
(nzChange)="change($event)">
</nz-transfer>
`
})
export class NzDemoTransferCanMoveComponent implements OnInit {
list: any[] = [];
ngOnInit() {
for (let i = 0; i < 20; i++) {
this.list.push({
key: i.toString(),
title: `content${i + 1}`,
disabled: i % 3 < 1,
});
}

[ 2, 3 ].forEach(idx => this.list[idx].direction = 'right');
}

canMove(arg: any) {
if (arg.direction === 'right' && arg.list.length > 0) arg.list.splice(0, 1);
// or
// if (arg.direction === 'right' && arg.list.length > 0) delete arg.list[0];
return ArrayObservable.of(arg.list).pipe(delay(1000));
}

select(ret: any) {
console.log('nzSelectChange', ret);
}

change(ret: any) {
console.log('nzChange', ret);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export class NzDemoTransferComponent {
NzDemoTransferSearchCode = require('!!raw-loader!./nz-demo-transfer-search.component');
NzDemoTransferAdvancedCode = require('!!raw-loader!./nz-demo-transfer-advanced.component');
NzDemoTransferCustomItemCode = require('!!raw-loader!./nz-demo-transfer-custom-item.component');
NzDemoTransferCanMoveCode = require('!!raw-loader!./nz-demo-transfer-can-move.component');
}
14 changes: 14 additions & 0 deletions src/showcase/nz-demo-transfer/nz-demo-transfer.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ <h2>代码演示<i class="code-box-expand-trigger anticon anticon-appstore" titl
</div>
</nz-code-box>
</div>
<div nz-col [nzSpan]="24">
<nz-code-box [nzTitle]="'二次校验'" id="components-transfer-demo-can-move" [nzCode]="NzDemoTransferCanMoveCode">
<nz-demo-transfer-can-move demo></nz-demo-transfer-can-move>
<div intro>
<p>利用 <code>canMove</code> 允许在穿梭过程中二次校验;示例默认向右移时强制第一项不可穿梭。</p>
</div>
</nz-code-box>
</div>
</div>
<section class="markdown api-container">
<h2 id="API"><span>API</span>
Expand Down Expand Up @@ -129,6 +137,12 @@ <h2 id="API"><span>API</span>
<td>列表为空</td>
<td></td>
</tr>
<tr>
<td>canMove</td>
<td>穿梭时二次校验。<p><strong>注意:</strong>穿梭组件内部始终只保留一份数据,二次校验过程中需取消穿梭项则直接<strong>删除</strong>该项;具体用法见示例。</p></td>
<td></td>
<td></td>
</tr>
<tr>
<td>(nzChange)</td>
<td>选项在两栏之间转移时的回调函数</td>
Expand Down
3 changes: 2 additions & 1 deletion src/showcase/nz-demo-transfer/nz-demo-transfer.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import { NzDemoTransferBasicComponent } from './nz-demo-transfer-basic.component
import { NzDemoTransferSearchComponent } from './nz-demo-transfer-search.component';
import { NzDemoTransferAdvancedComponent } from './nz-demo-transfer-advanced.component';
import { NzDemoTransferCustomItemComponent } from './nz-demo-transfer-custom-item.component';
import { NzDemoTransferCanMoveComponent } from './nz-demo-transfer-can-move.component';

@NgModule({
imports : [ NzDemoTransferRoutingModule, CommonModule, NzCodeBoxModule, NgZorroAntdModule, FormsModule ],
declarations: [ NzDemoTransferComponent, NzDemoTransferBasicComponent, NzDemoTransferSearchComponent, NzDemoTransferAdvancedComponent, NzDemoTransferCustomItemComponent ]
declarations: [ NzDemoTransferComponent, NzDemoTransferBasicComponent, NzDemoTransferSearchComponent, NzDemoTransferAdvancedComponent, NzDemoTransferCustomItemComponent, NzDemoTransferCanMoveComponent ]
})
export class NzDemoTransferModule {

Expand Down

0 comments on commit d31c596

Please sign in to comment.