I'm trying to post an invoice form with autocalculated total value that depend on quantity and unit price, but onSubmit, the backend can't see the numeric amount of value and vatValue, except when I'm adding something on that autocalculated input. I can't resolve this even if I mark value and vatValue as dirty and touched. Any ideea can be helpful, thanks!
<input formControlName="name" placeholder="prod name" required>
<input formControlName="price" placeholder="prod quantity" required>
<input type="number" formControlName="value" value="{{calculateTotal()+ (calculateTotal() * 0.19)}}">
<input type="number" formControlName="vatValue" [value]="(calculateTotal() * 0.19)">
calculateTotal(): number {
this.positions = this.invoicePositions.value;
let tempValue = 0;
for (const productValue of this.positions) {
tempValue = tempValue + (productValue.quantity * productValue.product.price);
}
this.positions = [];
this.invoiceTotal = tempValue;
return tempValue;
}
onSubmit() {
this.invoiceForm.controls.value.markAsDirty();
this.invoiceForm.controls.value.markAsTouched();
this.invoiceForm.controls.vatValue.markAsDirty();
this.invoiceForm.controls.vatValue.markAsTouched();
this.invoice = this.invoiceForm.value;
console.log(this.invoice.value);
this.invoiceService.save(this.invoice).subscribe(result => this.gotoInvoiceList());
}
It looks like you're using Reactive Forms over Template-driven forms. In that case I'd recommend supplying the initial values to the form in your components ngOnInit rather than through the [value] attribute in the template.
In doing so, the values will be immediately available to you. You can then subscribe to change events to react to changes to any of values if necessary.
ngOnInit() {
this.myForm = new FormGroup({
name: new FormControl(null, Validators.required),
price: new FormControl(null, Validators.required),
value: new FormControl(
this.calculateTotal() + this.calculateTotal() * 0.19,
Validators.required
),
vatValue: new FormControl(
this.calculateTotal() * 0.19,
Validators.required
)
});
}
Demo here
try [(ngModel)] instead of value of {{calculateTotal()+ (calculateTotal() * 0.19)}}
I have an html input of type text and it's connected by [(ngModel)] to a formattedValue variable which updates whenever a value is entered.
I'm using this input field mainly for displaying numbers and it's of type text because after the user is putting in a number, I want to show it formatted (e.g: 1234 -> 1,234).
The problem occurs when I'm entering the number 0, it converts it to a string "0" and sets the input field value, but the input is always resetting - meaning, its value is being removed and the placeholder is showing.
This is my input:
<input
class="form-control form-text-input"
type="text"
name="field-{{ field.id }}"
id="field-{{ field.id }}"
[(ngModel)]="formattedValue"
(change)="updateFieldValue($event.target)"
placeholder="Enter any number">
And this is the logic:
formattedValue = '';
updateFieldValue($target: any) {
const decimalValue = parseFloat($target.value.replace(/,/g, ''));
if (decimalValue > 999) {
this.formattedValue = this._getFormattedValue();
} else {
this.formattedValue = decimalValue.toString();
}
}
private _getFormattedValue(): string {
return DecimalPipe.prototype.transform(this.field.value || this.field.defaultValue, undefined, 'en-US');
}
Here's a GIF showing the issue:
Thanks!
I have a html input that has a fixed length of 7.
If the users types 1234, how can I prefix this input with a number of zeros in order to have the required length of 7?
I want to do this only in the UI because I already have a method in ts code for prefixing with zeros this input in order to send this correctly to backend.
<input formControlName="userNumber" type="text" class="form-control" placeholder="User #" aria-label="userNumber" aria-describedby="userNumber">
You can make use of input event on input field. Once user enters some numbers and then when the input field loses focus, required number of zeroes will be added.
const $input = document.querySelector('input');
$input.addEventListener('change', (e) => {
const value = e.target.value;
const length = e.target.value.length;
if (length === 0) {
$input.value = value;
}
else if (length < 7) {
$input.value = '0'.repeat(7-length) + value;
}
});
<input formControlName="userNumber" type="text" class="form-control" placeholder="User #" aria-label="userNumber" aria-describedby="userNumber">
I'm trying to implement a time picker in Angular, and I'm having some trouble figuring out how to check if the text input is valid.
In the html I have an input element that binds to keyPress function.
<input matInput style="text-align: right;" [(ngModel)]="hour" type="number" min="0" max="23" (keypress)="keyPress($event)">
keyPress(event: any) {
const pattern = /^(([[0|1]\d)|(2[0-3]))$/;
let inputChar = String.fromCharCode(event.charCode);
let tempHour = this.hour;
if (!tempHour) {
tempHour = '0';
}
let newHour = (+tempHour * 10 + +inputChar).toString();
if (newHour.length === 1) {
newHour = '0' + newHour;
}
if (!pattern.test(newHour)) {
event.preventDefault();
}
}
The problem here is that the event passed to the keyPress function only contains the current pressed key. This works fine unless the user moves the input cursor. For example: If user presses key "1", and then moves the cursor backwards and enter a "9". My code will treat it as 19 and let it pass, but the actual input is 91. So I guess I need to some how get the cursor position? Or is there a better way to solve this?
Thanks very much!
The problem is that the keypress-event happens before ngModel updates your "hour" variable. In your case I'd suggest to react on the change-event which gets fired after ngModel has already done its update.
(change)="onChange($event)"
And then your method can look like this
<input matInput style="text-align: right;" [(ngModel)]="hour" type="number" min="0" max="23" (change)="onChange($event)">
private lastValue: number = 0;
onChange(event: any) {
const pattern = /^(([[0|1]\d)|(2[0-3]))$/;
if (!pattern.test(this.hour)) {
this.hour = this.lastValue;
} else {
this.lastValue = this.hour;
}
}
trying to get a form set up but for some reason, the Date input in my html is not binding to the object's date value, despite using [(ngModel)]
html:
<input type='date' #myDate [(ngModel)]='demoUser.date'/><br>
form component:
export class FormComponent {
demoUser = new User(0, '', '', '', '', new Date(), '', 0, [], []);
}
User class:
export class User {
constructor (
public id: number,
public email: string,
public password: string,
public firstName: string,
public lastName: string,
public date: Date,
public gender: string,
public weight: number,
public dietRestrictions: string[],
public fitnessGoals: string[]
){
}
}
A test output reveals the current "new" Date as the object's value, but the input doesn't update the User object's date value or reflect the value, suggesting neither of the two-way bindings are working. Help would be greatly appreciated.
Angular 2 , 4 and 5 :
the simplest way : plunker
<input type="date" [ngModel] ="dt | date:'yyyy-MM-dd'" (ngModelChange)="dt = $event">
Instead of [(ngModel)] you can use:
// view
<input type="date" #myDate [value]="demoUser.date | date:'yyyy-MM-dd'" (input)="demoUser.date=parseDate($event.target.value)" />
// controller
parseDate(dateString: string): Date {
if (dateString) {
return new Date(dateString);
}
return null;
}
You can also choose not to use parseDate function. In this case the date will be saved as string format like "2016-10-06" instead of Date type (I haven't tried whether this has negative consequences when manipulating the data or saving to database for example).
In your component
let today: string;
ngOnInit() {
this.today = new Date().toISOString().split('T')[0];
}
and in your html file
<input name="date" [(ngModel)]="today" type="date" required>
In .ts :
today: Date;
constructor() {
this.today =new Date();
}
.html:
<input type="date"
[ngModel]="today | date:'yyyy-MM-dd'"
(ngModelChange)="today = $event"
name="dt"
class="form-control form-control-rounded" #searchDate
>
use DatePipe
> // ts file
import { DatePipe } from '#angular/common';
#Component({
....
providers:[DatePipe]
})
export class FormComponent {
constructor(private datePipe : DatePipe){}
demoUser = new User(0, '', '', '', '', this.datePipe.transform(new Date(), 'yyyy-MM-dd'), '', 0, [], []);
}
Angular 2 completely ignores type=date. If you change type to text you'll see that your input has two-way binding.
<input type='text' #myDate [(ngModel)]='demoUser.date'/><br>
Here is pretty bad advise with better one to follow:
My project originally used jQuery. So, I'm using jQuery datepicker for now, hoping that angular team will fix the original issue. Also it's a better replacement because it has cross-browser support. FYI, input=date doesn't work in Firefox.
Good advise: There are few pretty good Angular2 datepickers:
https://github.com/emirdeliz/meus-projetos/tree/master/angular2-schedule/app/frontend/components/datepicker
https://github.com/MrPardeep/Angular2-DatePicker
https://www.npmjs.com/package/ng2-datepicker
As per HTML5, you can use
input type="datetime-local"
instead of
input type="date".
It will allow the [(ngModel)] directive to read and write value from input control.
Note: If the date string contains 'Z' then to implement above solution, you need to trim the 'Z' character from date.
For more details, please go through this link on mozilla docs.
If you are using a modern browser there's a simple solution.
First, attach a template variable to the input.
<input type="date" #date />
Then pass the variable into your receiving method.
<button (click)="submit(date)"></button>
In your controller just accept the parameter as type HTMLInputElement
and use the method valueAsDate on the HTMLInputElement.
submit(date: HTMLInputElement){
console.log(date.valueAsDate);
}
You can then manipulate the date anyway you would a normal date.
You can also set the value of your <input [value]= "..."> as you
would normally.
Personally, as someone trying to stay true to the unidirectional data flow, i try to stay away from two way data binding in my components.
you can use a workaround, like this:
<input type='date' (keyup)="0" #myDate [(ngModel)]='demoUser.date'/><br>
on your component :
#Input public date: Date,
In Typescript - app.component.ts file
export class AppComponent implements OnInit {
currentDate = new Date();
}
In HTML Input field
<input id="form21_1" type="text" tabindex="28" title="DATE" [ngModel]="currentDate | date:'MM/dd/yyyy'" />
It will display the current date inside the input field.