2017-09-19 88 views
1

我已經創建了一個簡單的管道,我應用於文本輸入。正則表達式的工作 - 但有些奇怪。控制檯日誌正確顯示新值(非字母數字已刪除),但在瀏覽器中,輸入字段不會更新,直到我輸入好字符爲止。因此,輸入'123 !!!! A'將顯示感嘆號,直到A被輸入然後消失。爲什麼?角度2輸入與管道不更新視圖(更改檢測不工作)

我使用管道這樣的:

<input type="text" class="form-control" [ngModel]="name | inputFormat" (ngModelChange)="name=$event"> 

和管

import { Pipe, PipeTransform } from '@angular/core'; 

@Pipe({ 
    name: 'inputFormat' 
}) 
export class InputFormatPipe implements PipeTransform { 

    transform(value: any): any { 
    value = value.replace(/[^a-z0-9]/gi, ''); 
    console.log('new value: '+value); 
    return value; 
    } 

} 

我懷疑變化檢測不工作 - 但不知道如何解決這個問題。

+0

你試圖用這個代碼解決什麼任務?我會說它不應該工作。如果你希望你的值在輸入中以某種特定的方式格式化,那麼你可能需要實現ControlValueAccessor ...但這只是我的猜測。請提供您想要實現的細節。 –

+0

我正在編寫一個通用管道,用於刪除受限制的字符,更改大小寫,替換其他字符等。爲了簡化操作,我將問題簡化爲可能的最簡單情況來演示該錯誤 – TSG

+0

這不是要走的路無論如何。如果您需要執行此類操作,則ControlValueAccessor是您最好的朋友。它將允許您直接訂閱輸入上的不同事件並在**值到達模型之前處理它們。例如,您可以通過在keydown事件中拒絕不需要的字符甚至在輸入之前拒絕它來糾正您的值。只要看看角度來源中的DefaultValueAccessor並添加一些創意思維。這不是火箭科學,儘管它需要你的一些代碼,但它肯定會是更好的方法。 –

回答

0

好的,這裏是一個如何處理用戶輸入的例子,它應該被設計處理。

測試input.directive.ts

import { Directive, ElementRef, Renderer2, forwardRef, HostListener } from '@angular/core'; 
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; 

export const TEST_VALUE_ACCESSOR: any = { 
    provide: NG_VALUE_ACCESSOR, 
    useExisting: forwardRef(() => TestInputDirective), 
    multi: true 
}; 

@Directive({ 
    selector: 'input[appTestInput]', 
    providers: [TEST_VALUE_ACCESSOR] 
}) 
export class TestInputDirective implements ControlValueAccessor { 

    onChange = (_: any) => { }; 
    onTouched =() => { }; 

    constructor(private _renderer: Renderer2, private _elementRef: ElementRef) { } 

    // this gets called when the value gets changed from the code outside 
    writeValue(value: any): void { 
    const normalizedValue = value == null ? '' : value; 
    this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue); 
    } 

    registerOnChange(fn: (_: any) => void): void { this.onChange = fn; } 
    registerOnTouched(fn:() => void): void { this.onTouched = fn; } 

    setDisabledState(isDisabled: boolean): void { 
    this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); 
    } 

    // just as an example - let's make this field accept only numbers 
    @HostListener('keydown', ['$event']) 
    _handleKeyDown($event: KeyboardEvent): void { 
    if (($event.keyCode < 48 || $event.keyCode > 57) && $event.keyCode !== 8) { 
     // not number or backspace, killing event 
     $event.preventDefault(); 
     $event.stopPropagation(); 
    } 
    } 

    @HostListener('input', ['$event']) 
    _handleInput($event: KeyboardEvent): void { 
    // this is what we should call to inform others that our value has changed 
    this.onChange((<any>$event.target).value); 
    } 
} 

這個指令申報只需添加到您的模塊:

app.module.ts

import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { FormsModule } from '@angular/forms'; 

import { AppComponent } from './app.component'; 
import { TestInputDirective } from './test-input.directive'; 

@NgModule({ 
    declarations: [ 
    AppComponent, 
    TestInputDirective // <-- you'll need this 
    ], 
    imports: [ 
    BrowserModule, 
    FormsModule  // <-- and this 
    ], 
    providers: [], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

然後你可以像這樣在模板中使用它:

app.component.html

<input type="text" appTestInput [(ngModel)]="name"> 
<div>{{name}}</div> 

這比用管道,真正的更多的代碼,但是這是處理用戶輸入正確的方式,特別是當它應該以某種方式預處理。

+0

這適用於簡單地殺死按鍵,但是如果我想將鍵'a'更改爲'一個' ? – TSG

+0

然後預處理您傳遞給onChange()的值。你可以在輸入中處理你想要的任何事件。例如,我省略了「模糊」事件,我有時使用它來重新格式化用戶輸入的值,特別是爲時間添加零(類似於'9'中的'09:00')或將字符串大寫。有一大堆你可以在這裏做的事情。我甚至改變了這個輸入綁定的數據類型。我的其中一個項目中的日期輸入直接綁定到日期值,我不必在輸入中對字符串值進行單獨轉換。很方便。 –

+0

但是我需要改變用戶鍵入的字符(例如替換/和\),這就是爲什麼我用管道去的原因。我不想改變模糊值,因爲這可能會讓用戶感到挫敗。必須有一種方法來改變和/或刪除鍵,因爲用戶鍵入... – TSG