Angular 2 set null as empty string value for input

2019-02-06 08:19发布

I have an input field mapped to an entity in my controller with a ngModel 2-way binding.

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

When I initialize my controller, I have this entity :

{ one_attribute: null }

If a user starts to fill in the field but does not submit the form immediately and empties the field, my entity is updated to become:

{ one_attribute: "" }

Is it possible to define that empty string should be changed to null automatically?

3条回答
\"骚年 ilove
2楼-- · 2019-02-06 09:05

After viewing a bunch of answers about ValueAccessor and HostListener solutions, I made a working solution (tested with 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);
  }
}

Then use it that way on your input fields:

<input [(ngModel)]="bindedValue" nullValue/>
查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-02-06 09:12

I have done it globally. But its not 100%. I could not find the method where angular 4 call JSON.stringify on the body. I'm hoping someone could help out here. Until the new HttpClient in 4.3 is out I continue to use a wrapper class for the Http service. I do this because no interceptors has been present in Angular2 and forward. My wrapper looks something like this.

@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);
}

So far so good. But I have not found any good transformRequest as in AngularJS, so until i find it I have implemented transformEmptyStringAsNull as this:

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

I know it's ugly in the way that I will do an extra stringify back to parse again. But I don't need to do anything in the rest of the application.

查看更多
贼婆χ
4楼-- · 2019-02-06 09:21

I just formed this solution after much research. It's kind of hacky since the Angular team doesn't recommend extending DefaultValueAccessor, but it automagically works for every input without having to mark each one individually.

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);
        });
    }
}

This is working great for me on Angular 4.4.5.

查看更多
登录 后发表回答