Skip to content

Commit

Permalink
fix(module:mention): fix cannot to switch trigger (#3632)
Browse files Browse the repository at this point in the history
* fix(module:mention): fix cannot to switch trigger

close #3629

* test(module:mention): add test

* docs(module:mention): fix API
  • Loading branch information
hsuanxyz authored and vthinkxie committed Jun 26, 2019
1 parent d28fc49 commit c8b5b09
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 24 deletions.
6 changes: 2 additions & 4 deletions components/mention/demo/controlled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@ import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-label [nzSm]="6" nzFor="mention">Top coders</nz-form-label>
<nz-form-control [nzSm]="16">
<nz-form-control [nzSm]="16" nzErrorTip="More than one must be selected!">
<nz-mention #mentions [nzSuggestions]="suggestions">
<input id="mention" placeholder="input here" formControlName="mention" nzMentionTrigger nz-input />
</nz-mention>
<nz-form-explain *ngIf="validateForm.get('mention')?.dirty && validateForm.get('mention')?.errors">
More than one must be selected!
</nz-form-explain>
</nz-form-control>
</nz-form-item>
<nz-form-item nz-row style="margin-bottom:8px;">
Expand Down Expand Up @@ -55,6 +52,7 @@ export class NzDemoMentionControlledComponent implements OnInit {

submitForm(): void {
this.mention.markAsDirty();
this.mention.updateValueAndValidity();
if (this.mention.valid) {
console.log('Submit!!!', this.mention.value);
console.log(this.mentionChild.getMentions());
Expand Down
2 changes: 1 addition & 1 deletion components/mention/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { NzMentionModule } from 'ng-zorro-antd/mention';
| `[nzSuggestions]` | Suggestion content | `any[]` | `[]` |
| `[nzValueWith]` | Function that maps an suggestion's value | `(any) => string \| (value: string) => string` |
| `(nzOnSelect)` | Callback function called when select from suggestions | `EventEmitter<any>` | - |
| `(onSearchChange)` | Callback function called when search content changes| `EventEmitter<MentionOnSearchTypes>` | - |
| `(nzOnSearchChange)` | Callback function called when search content changes| `EventEmitter<MentionOnSearchTypes>` | - |

#### Methods

Expand Down
2 changes: 1 addition & 1 deletion components/mention/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import { NzMentionModule } from 'ng-zorro-antd/mention';
| `[nzSuggestions]` | 建议内容 | `any[]` | `[]` |
| `[nzValueWith]` | 建议选项的取值方法 | `(any) => string \| (value: string) => string` |
| `(nzOnSelect)` | 下拉框选择建议时回调 | `EventEmitter<any>` | - |
| `(onSearchChange)` | 输入框中 @ 变化时回调 | `EventEmitter<MentionOnSearchTypes>` | - |
| `(nzOnSearchChange)` | 输入框中 @ 变化时回调 | `EventEmitter<MentionOnSearchTypes>` | - |

#### 方法

Expand Down
27 changes: 20 additions & 7 deletions components/mention/nz-mention-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { forwardRef, Directive, ElementRef, EventEmitter, ExistingProvider, OnDestroy } from '@angular/core';
import {
forwardRef,
AfterViewInit,
Directive,
ElementRef,
EventEmitter,
ExistingProvider,
OnDestroy
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

import { Mention } from './nz-mention.component';
import { NzMentionService } from './nz-mention.service';

export const NZ_MENTION_TRIGGER_ACCESSOR: ExistingProvider = {
provide: NG_VALUE_ACCESSOR,
Expand All @@ -30,7 +39,7 @@ export const NZ_MENTION_TRIGGER_ACCESSOR: ExistingProvider = {
'(click)': 'onClick.emit($event)'
}
})
export class NzMentionTriggerDirective implements ControlValueAccessor, OnDestroy {
export class NzMentionTriggerDirective implements ControlValueAccessor, OnDestroy, AfterViewInit {
onChange: (value: string) => void;
onTouched: () => void;

Expand All @@ -41,11 +50,7 @@ export class NzMentionTriggerDirective implements ControlValueAccessor, OnDestro
readonly onClick: EventEmitter<MouseEvent> = new EventEmitter();
value: string;

constructor(public el: ElementRef) {}

ngOnDestroy(): void {
this.completeEvents();
}
constructor(public el: ElementRef, private nzMentionService: NzMentionService) {}

completeEvents(): void {
this.onFocusin.complete();
Expand Down Expand Up @@ -90,4 +95,12 @@ export class NzMentionTriggerDirective implements ControlValueAccessor, OnDestro
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}

ngAfterViewInit(): void {
this.nzMentionService.registerTrigger(this);
}

ngOnDestroy(): void {
this.completeEvents();
}
}
29 changes: 19 additions & 10 deletions components/mention/nz-mention.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { TemplatePortal } from '@angular/cdk/portal';

import { DOCUMENT } from '@angular/common';
import {
AfterContentInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Expand All @@ -29,19 +28,22 @@ import {
Input,
OnChanges,
OnDestroy,
OnInit,
Optional,
Output,
SimpleChanges,
TemplateRef,
ViewChild,
ViewContainerRef
} from '@angular/core';

import { fromEvent, merge, Subscription } from 'rxjs';

import { getCaretCoordinates, getMentions, DEFAULT_MENTION_POSITIONS, InputBoolean } from 'ng-zorro-antd/core';

import { NzMentionSuggestionDirective } from './nz-mention-suggestions';
import { NzMentionTriggerDirective } from './nz-mention-trigger';
import { NzMentionService } from './nz-mention.service';

export interface MentionOnSearchTypes {
value: string;
Expand All @@ -62,6 +64,7 @@ export type MentionPlacement = 'top' | 'bottom';
templateUrl: './nz-mention.component.html',
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [NzMentionService],
styles: [
`
.ant-mention-dropdown {
Expand All @@ -75,7 +78,7 @@ export type MentionPlacement = 'top' | 'bottom';
`
]
})
export class NzMentionComponent implements OnDestroy, AfterContentInit, OnChanges {
export class NzMentionComponent implements OnDestroy, OnInit, OnChanges {
@Input() nzValueWith: (value: any) => string = value => value; // tslint:disable-line:no-any
@Input() nzPrefix: string | string[] = '@';
@Input() @InputBoolean() nzLoading = false;
Expand All @@ -85,7 +88,7 @@ export class NzMentionComponent implements OnDestroy, AfterContentInit, OnChange
@Output() readonly nzOnSelect: EventEmitter<string | {}> = new EventEmitter();
@Output() readonly nzOnSearchChange: EventEmitter<MentionOnSearchTypes> = new EventEmitter();

@ContentChild(NzMentionTriggerDirective, { static: true }) trigger: NzMentionTriggerDirective;
trigger: NzMentionTriggerDirective;
@ViewChild(TemplateRef, { static: false }) suggestionsTemp: TemplateRef<void>;

@ContentChild(NzMentionSuggestionDirective, { static: false, read: TemplateRef })
Expand Down Expand Up @@ -118,9 +121,19 @@ export class NzMentionComponent implements OnDestroy, AfterContentInit, OnChange
@Optional() @Inject(DOCUMENT) private ngDocument: any, // tslint:disable-line:no-any
private changeDetectorRef: ChangeDetectorRef,
private overlay: Overlay,
private viewContainerRef: ViewContainerRef
private viewContainerRef: ViewContainerRef,
private nzMentionService: NzMentionService
) {}

ngOnInit(): void {
this.nzMentionService.triggerChanged().subscribe(trigger => {
this.trigger = trigger;
this.bindTriggerEvents();
this.closeDropdown();
this.overlayRef = null;
});
}

ngOnChanges(changes: SimpleChanges): void {
if (changes.hasOwnProperty('nzSuggestions')) {
if (this.isOpen) {
Expand All @@ -131,10 +144,6 @@ export class NzMentionComponent implements OnDestroy, AfterContentInit, OnChange
}
}

ngAfterContentInit(): void {
this.bindTriggerEvents();
}

ngOnDestroy(): void {
this.closeDropdown();
}
Expand All @@ -155,7 +164,7 @@ export class NzMentionComponent implements OnDestroy, AfterContentInit, OnChange
}

getMentions(): string[] {
return getMentions(this.trigger.value, this.nzPrefix);
return this.trigger ? getMentions(this.trigger.value, this.nzPrefix) : [];
}

selectSuggestion(suggestion: string | {}): void {
Expand Down Expand Up @@ -296,7 +305,7 @@ export class NzMentionComponent implements OnDestroy, AfterContentInit, OnChange
coordinates.top -
this.triggerNativeElement.getBoundingClientRect().height -
this.triggerNativeElement.scrollTop +
(this.nzPlacement === 'bottom' ? coordinates.height : 0);
(this.nzPlacement === 'bottom' ? coordinates.height - 11 : 0);
const left = coordinates.left - this.triggerNativeElement.scrollLeft;
this.positionStrategy.withDefaultOffsetX(left).withDefaultOffsetY(top);
if (this.nzPlacement === 'bottom') {
Expand Down
33 changes: 33 additions & 0 deletions components/mention/nz-mention.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { Injectable, OnDestroy } from '@angular/core';
import { Observable, Subject } from 'rxjs';

import { NzMentionTriggerDirective } from './nz-mention-trigger';

@Injectable()
export class NzMentionService implements OnDestroy {
private trigger: NzMentionTriggerDirective;
private triggerChange$ = new Subject<NzMentionTriggerDirective>();

triggerChanged(): Observable<NzMentionTriggerDirective> {
return this.triggerChange$.asObservable();
}

registerTrigger(trigger: NzMentionTriggerDirective): void {
if (this.trigger !== trigger) {
this.trigger = trigger;
this.triggerChange$.next(trigger);
}
}

ngOnDestroy(): void {
this.triggerChange$.complete();
}
}
36 changes: 35 additions & 1 deletion components/mention/nz-mention.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,32 @@ describe('mention', () => {
expect(overlayContainerElement.textContent).toEqual('');
expect(textarea.value).toEqual('@angular ');
}));

it('should support switch trigger', fakeAsync(() => {
fixture.componentInstance.inputTrigger = true;
fixture.detectChanges();
const input = fixture.debugElement.query(By.css('input')).nativeElement;
const mention = fixture.componentInstance.mention;

expect(fixture.debugElement.query(By.css('textarea'))).toBeFalsy();
expect(input).toBeTruthy();

input.value = '@a';
fixture.detectChanges();
dispatchFakeEvent(input, 'click');
fixture.detectChanges();
flush();

expect(mention.isOpen).toBe(true);

const option = overlayContainerElement.querySelector('.ant-mention-dropdown-item') as HTMLElement;
option.click();
fixture.detectChanges();

tick(500);
expect(mention.isOpen).toBe(false);
expect(overlayContainerElement.textContent).toEqual('');
}));
});

describe('keyboard events', () => {
Expand Down Expand Up @@ -434,13 +460,21 @@ describe('mention', () => {
@Component({
template: `
<nz-mention [nzSuggestions]="suggestions">
<textarea nz-input [nzAutosize]="{ minRows: 4, maxRows: 4 }" [(ngModel)]="inputValue" nzMentionTrigger>
<textarea
*ngIf="!inputTrigger"
nz-input
[nzAutosize]="{ minRows: 4, maxRows: 4 }"
[(ngModel)]="inputValue"
nzMentionTrigger
>
</textarea>
<input *ngIf="inputTrigger" nz-input [(ngModel)]="inputValue" nzMentionTrigger />
</nz-mention>
`
})
class NzTestSimpleMentionComponent {
inputValue: string = '@angular';
inputTrigger = false;
suggestions = ['angular', 'ant-design', 'mention', '中文', 'にほんご'];
@ViewChild(NzMentionComponent, { static: false }) mention: NzMentionComponent;
@ViewChild(NzMentionTriggerDirective, { static: false }) trigger: NzMentionTriggerDirective;
Expand Down
1 change: 1 addition & 0 deletions components/mention/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './nz-mention.module';
export * from './nz-mention.component';
export * from './nz-mention-trigger';
export * from './nz-mention-suggestions';
export * from './nz-mention.service';

0 comments on commit c8b5b09

Please sign in to comment.