Подтвердить что ты не робот

Установить пустое значение в качестве значения пустой строки для поля ввода

У меня есть поле input сопоставленное сущности в моем контроллере с двухсторонней привязкой ngModel:

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

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

{ one_attribute: null }

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

{ one_attribute: "" }

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

4b9b3361

Ответ 1

После просмотра кучи ответов о решениях 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/>

Ответ 2

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

Ответ 3

Я сделал это глобально. Но это не 100%. Я не мог найти метод, в котором angular 4 вызывает JSON.stringify на теле. Я надеюсь, что кто-то может помочь здесь. Пока новый HttpClient в версии 4.3 не появится, я продолжаю использовать класс-оболочку для службы 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);
}

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

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

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