我有一个input
字段映射到我的控制器中的实体,并带有ngModel
双向绑定:
<input type="text" [(ngModel)]="entity.one_attribute" />
当我初始化我的控制器时,我有这个实体:
{ one_attribute: null }
如果用户开始填写该字段但未立即提交表单并清空该字段,我的实体将更新为:
{ one_attribute: "" }
是否可以定义空字符串应自动更改为null
?
答案 0 :(得分:17)
在查看了大量有关ValueAccessor
和HostListener
解决方案的答案后,我制作了一个有效的解决方案(使用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);
}
我知道这样做很难看,我会再做一次额外的字符串再解析。但是我不需要在应用程序的其余部分做任何事情。