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?
Any type is known as nullable if you can assign a value or null to this variable it means that the type will have no value. In C# all reference types like string are of a nullable type, but the other types like int32 are not nullable type.
A string refers to a character's sequence. Sometimes strings can be empty or NULL. The difference is that NULL is used to refer to nothing. However, an empty string is used to point to a unique string with zero length.
If you were to use s , it would actually have a value of null , because it holds absolute nothing. An empty string, however, is a value - it is a string of no characters. Null is essentially 'nothing' - it's the default 'value' (to use the term loosely) that Java assigns to any Object variable that was not initialized.
A field with a NULL value is a field with no value. If a field in a table is optional, it is possible to insert a new record or update a record without adding a value to this field. Then, the field will be saved with a NULL value. Note: A NULL value is different from a zero value or a field that contains spaces.
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/>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With