Angular 2 Установите null как пустое строковое значение для поля ввода

у меня есть поле ввода, сопоставленное с сущностью в моем контроллере с ngModel 2-способ привязки.

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

когда я инициализирую свой контроллер, у меня есть этот объект:

{ one_attribute: null }

если пользователь начинает заполнять поле, но не отправляет форму сразу и опустошает поле, моя сущность обновляется, чтобы стать:

{ one_attribute: "" }

можно ли определить, что пустая строка должна быть автоматически изменена на null?

3 ответов


после просмотра кучу ответов о 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/>

Я только что сформировал это решение после многих исследований. Это своего рода hacky так как команда Angular не рекомендует расширять 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.


Я сделал это глобально. Но это не 100%. Я не смог найти метод, где angular 4 вызывает JSON.stringify на теле. Надеюсь, кто-нибудь сможет помочь. Пока новый HttpClient в 4.3 не выйдет, я продолжаю использовать класс-оболочку для службы Http. Я делаю это, потому что в Angular2 и forward не было перехватчиков. Моя обертка выглядит примерно так.

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

пока все хорошо. Но я не нашел хорошего transformRequest как в AngularJS, так что пока я найти его я реализовал transformEmptyStringAsNull следующим образом:

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

Я знаю, что это уродливо, так как я сделаю дополнительную stringify обратно для разбора снова. Но мне не нужно ничего делать в остальной части приложения.