将null设置为输入字段的空字符串值

时间:2016-07-22 13:19:40

标签: angular angular2-template

我有一个input字段映射到我的控制器中的实体,并带有ngModel双向绑定:

<input type="text" [(ngModel)]="entity.one_attribute" />

当我初始化我的控制器时,我有这个实体:

{ one_attribute: null }

如果用户开始填写该字段但未立即提交表单并清空该字段,我的实体将更新为:

{ one_attribute: "" }

是否可以定义空字符串应自动更改为null

4 个答案:

答案 0 :(得分:17)

在查看了大量有关ValueAccessorHostListener解决方案的答案后,我制作了一个有效的解决方案(使用RC1测试):

import {NgControl} from "@angular/common";
import {Directive, ElementRef, HostListener} from "@angular/core";

@Directive({
  selector: 'input[nullValue]'
})
export class NullDefaultValueDirective {
  constructor(private el: ElementRef, private control: NgControl) {}

  @HostListener('input', ['$event.target'])
  onEvent(target: HTMLInputElement){
    this.control.viewToModelUpdate((target.value === '') ? null : target.value);
  }
}

然后在输入字段中使用它:

<input [(ngModel)]="bindedValue" nullValue/>

答案 1 :(得分:5)

经过大量研究后,我才形成了这个解决方案。它是一种hacky since the Angular team doesn't recommend extending DefaultValueAccessor,但它可以自动适用于每个输入而无需单独标记每个输入。

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

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

@Directive({
    selector: 'input:not([type]),input[type=text],input[type=password],input[type=email],input[type=tel],textarea',
    host: {
        '(input)': '_handleInput($event.target.value)',
        '(blur)': 'onTouched()',
        '(compositionstart)': '_compositionStart()',
        '(compositionend)': '_compositionEnd($event.target.value)'
    },
    providers: [VALUE_ACCESSOR]
})
export class InputExtensionValueAccessor extends DefaultValueAccessor  {
    // HACK: Allows use of DefaultValueAccessor as base
    // (https://github.com/angular/angular/issues/9146)
    static decorators = null;

    constructor(renderer: Renderer2, elementRef: ElementRef) {
        super(renderer, elementRef, (null as any));
    }

    registerOnChange(fn: (_: any) => void): void {
        super.registerOnChange(value => {
            // Convert empty string from the view to null for the model
            fn(value === '' ? null : value);
        });
    }
}

这对我来说非常适合Angular 4.4.5。

答案 2 :(得分:1)

尽管在接受的答案中@jobou 解决方案是有道理的,但我认为仍然需要记住将 'nullValue' 添加到每个字段中,这是一个相当大的开销。

我换了一个方向,检查了拦截器服务中的数据。

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  ...
   request = this.nullValueService.setNullValues();
  ...
}

我创建了一个服务,它检查请求正文中的每个值,如果找到一个空字符串,它将设置为 Null。

@Injectable()
export class NullValueService {
    ...
    setNullValues(request) {
        for (let key in request.body) {
            if (request.body[key] === '') {
                request.body[key] = null;
            }
        }
    }

}

这个解决方案适用于我的后端,我认为在大多数情况下应该没问题。

答案 3 :(得分:-3)

我在全球范围内完成了这项工作。但它不是100%。我找不到angular 4在身体上调用JSON.stringify的方法。我希望有人能在这里帮忙。 在4.3中的新HttpClient出来之前,我继续使用包装类来进行Http服务。我这样做是因为Angular2和前进中都没有拦截器。我的包装看起来像这样。

@Injectable()
export class MyDao {
constructor(private http: Http) {
}
public get(options?:MyRequestOptions){...}
public post(url:string,body,options?:MyRequestOptions){
   let reqOptions = new BaseRequestOptions();
   reqOptions.url = url;
   reqOptions.params= this.processParams(options);
   reqOptions.header= this.processHeaders(options); //ex. add global headers
   reqOptions.body=this.removeEmptyStringsInBody(body);
   this.http.post(options);
}

到目前为止一切顺利。但是我没有像AngularJS那样找到任何好的transformRequest,所以在我找到之前我已经实现了transformEmptyStringAsNull:

 private removeEmptyStringsInBody(body:any) {
    let bodyTemp= JSON.stringify(body, function (key, value) {
        return value === "" ? null : value
    });
    return JSON.parse(bodyTemp);
}

我知道这样做很难看,我会再做一次额外的字符串再解析。但是我不需要在应用程序的其余部分做任何事情。