2017-09-19 63 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