How to get the previous value in (input) event in angular 4 - html

I am trying to add the value and also need to remove the previous value by comparing with a new value.
var total = [];
onSearchChange(event) {
total.push(event);
var sumNumber = total.reduce(
(acc, cur) => acc + Number(cur),
0
);
console.log("get all the changed value, I need to remove the previous values in the total list");
}
<input type='number' (input)="onSearchChange($event.target.value)" />

I don't know if the event itself retains the previous value. You can create a component property to hold the previous value and set it in every input event.
<input id="inputId" type="number" value=23 (input)="foo($event.target.value)">
// have some default value only if you want
previousValue: number
foo(value) {
console.log("previous value ", this.previousValue);
console.log("new value ", value);
this.previousValue = value
}
ngAfterViewInit() {
this.previousValue = parseInt((<HTMLInputElement>document.getElementById('inputId')).value)
}
https://stackblitz.com/edit/angular-ufd15s?file=src%2Fapp%2Fapp.component.ts
You can also add a helper event listener keydown (which seems unnecessary but just saying) on the input element. keydown will occur before input so with keydown you can grab the previous value. https://stackblitz.com/edit/angular-sjxvgp?file=src%2Fapp%2Fapp.component.ts

Related

Deleting a negative value from number input and validation

I feel that this is a dumb question, sorry.
I have an input with the number type and I want to add some validation to it. It is not required, so an empty string should be valid, negative numbers too, but not the - sign.
Consider now I've entered -102 into that field and removing symbols one by one, watching for changes.
Here's the basic codepen for it. As you can see, when there's just a - sign left the value (event.target.value) is an smpty string, which should be valid.
So, how can I check if there is only a minus sign left and mark this field as invalid?
const el = document.getElementById('input');
el.addEventListener('keyup', (e) => {
const value = e.target.value;
console.log(value)
})
<input type="number" id="input">
you can use pattern to only accept positive or negative number
in JS you can call method checkValidity() or use {yourinput}.validity.valid to check if value entered in input is valid or not
in css you can use the pseudo class :invalid to design your input when value entered don't match the pattern/field expectation
const el = document.getElementById('input');
el.addEventListener('keyup', (e) => {
console.log(el.checkValidity());
if (!el.checkValidity()) {
//treat case input invalid
}
})
input:invalid {
color: red;
}
<input type="number" id="input" pattern="\d+">

React JS: Ensure Progratimacally created input fields are unique from each other

I'm creating a form to seed a varying number of teams to a tournament, by first mapping them to a form group with labels and number input. How can I make it so each field has to be unique before the form is considered valid?
By unique, I mean each field with take a certain number in a range, say if a tournament has 14 teams, then each field should be a number between 1 and 14, but two fields shouldn't be able to take the same number.
renderButton() {
return (
<Form onSubmit={this.handleSeedingSubmit}>
{this.state.teams.map((team)=>
<FormGroup key={team.name}>
<Form.Label >{team.name}</Form.Label>
<Form.Control type = "number" name={team.name} min={1} max={this.state.tournament.noTeams} onChange={this.onChangeHandler} required />
</FormGroup>
)}
<Button type="submit" >
Submit
</Button>
</Form>
);
}
On submit each team is being mapped with {name, seeding}. I want every team to have a unique seeding as they will be sorted into pools based on seeding later.
Well what you can do is make the number inputs controlled by storing their values in the store:
state = {
// other state,
inputs: {}
}
then in onChangeHandler set the value of each input in the state:
function onChangeHandler(e) {
const { name, value } = e.target;
this.setState({
inputs: {
...this.state.inputs,
[name]: value
}
})
}
then when your form is submitted you can add a check to see if the values are unique or not, there are many ways to do that, what I'm doing here is remove the duplicates from the array and then check the length of the array against the values in the state like this:
function handleSeedingSubmit(e) {
e.preventDefault();
const { inputs } = this.state;
const valuesInState = Object.values(input);
const uniqueValuesArr = [...new Set(valuesInState)];
const areInputsValid = valuesInState.length === uniqueValuesArr.length;
if (!areInputsValid) {
// set Error here
return;
}
// Hurray!! Inputs are valid
// Handle Success case here
}
Hope it helps :)

How can I automatically insert commas when a user inputs currency value in an Angular 7 reactive form, no [(ngModel)]

I have an input field where the user can input a numeric value. I need to automatically insert commas after every 3rd digit. When the user deletes numbers, the commas need to be in the correct places (after every 3rd digit, starting from the first number) as well as stay in place instead of relocating to the end of the input value. I cannot use ngModel, this is a reactive form.
I have tried this method in my TS file, to mask the user input
maskInputAmount(e) {
const t = e.target.value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})
(\d{0,3})/);
e.target.value = t[2] ? t[1] + ',' + t[2] + (t[3] ? ',' + t[3] : '') :
t[1];
}
And in my HTML input field
<input (input)="maskInputAmount($event)" maxlength=11
formControlName="businessNetWorth" id="businessNetWorth"
type="text" class="form-control col-3 col-lg-12" data-hint="yes">
I am having commas come after every 3rd number. However, when deleting numbers from the end of the input, the commas at the front of the number should update correctly. For example, I enter '123,456,789'. When I delete the last two numbers I get '123,456,7' when it should be '1,234,567'.
One other issue, when a user deletes one of the first numbers, the comma in the input box automatically repositions itself to the end of the input value, I need it to stay in place. For example: '123,456,789'. I delete '3' and have '124,567,89' and the cursor is now behind the '9' when it should stay in front of the '2'.
How can I change my maskInputAmount(e) method to make this behave correctly?
Following code worked for me. (Assume present currency is in Indian rupees. If you want to have your own currency then you need to mention your country's code in code).
app.component.html
<input type="text" [formControl]="currency" (input)="changeToCurrency(currencyTextRef)" #currencyTextRef>
//sending reference of input element #currencyTextRef to function
{{ currency.value }}
app.component.ts
currency = new FormControl();
temp;
currncyLength=0;
changeToCurrency(currencyTextRef) {
this.currncyLength = this.currency.value.length;
console.log("currency len is "+this.currncyLength);
let index:number;
// if(currencyTextRef.selectionStart || currencyTextRef.selectionStart == '0') {
// console.log("index isss "+currencyTextRef.selectionStart);
index = currencyTextRef.selectionStart; //getting caret(cursor) position
// }
console.log("index is "+index);
// console.log("value is "+this.currency.value);
let a = this.currency.value;
a = a.replace(/,/g,'');
let num:number = + a;
let temp = new Intl.NumberFormat('en-IN').format(num); //inplace of en-IN you can mention your country's code
// console.log("temp is "+temp);
this.currency.setValue(temp.toString());
console.log("pressent len iss "+this.currency.value.length)
if(this.currncyLength<this.currency.value.length) {
console.log("incoming to < ")
index+=1;
currencyTextRef.setSelectionRange(index,index);
}
else if(this.currncyLength >=this.currency.value.length) {
console.log("incoming to > ");
// index-=1;
currencyTextRef.setSelectionRange(index,index);
}
// else {
// currencyTextRef.setSelectionRange(index,index);
// }
}
Following link might help.
Intl number MDN

Range Input won't reflect default value in Template Driven Form (Angular 2)

I want my range inputs to load with a default value of 0. When the page loads each input is set to the middle by default. When I inspect the element I see this
<input
class="form-control ng-untouched ng-pristine ng-valid"
step="1"
type="range"
ng-reflect-model=""
name="my_own_job"
id="bus_info_04_a_01_01"
min="0"
max="10"
value="0"
>
All the way at the end you see the value is indeed passed in. Here's what the input looks like which is inside of an *ngFor by the way.
<input class="form-control" type="range" step="1"
[attr.name]="ans.ctrlName"
[attr.id]="ans.id"
[attr.min]="Data.loExtreme"
[attr.max]="Data.hiExtreme"
[attr.value]="ans.value"
[(ngModel)]="UserResponse[ans.respName]"
#{{ans.respName}}="ngModel"
>
I'm also creating my variables dynamically like this
//From parent component
#Input() Data : Question;
//For dynamic variables for ngModel
UserResponse : { [ propName : string ] : string } = {};
//Function called in OnInit
loadResponses(){
let data : any = this.Data;
let control : string = data.ctrlName;
let response : string = data.respName;
let multiResp : Array<any> = data.answers;
let defVal : string = '';
let load : Array<string> = [];
load.push( control );
if( response == '' || response == undefined ){
if( this.Template == 'multi_fader' ){
multiResp.forEach( resp => {
this.UserResponse[ resp.ctrlName ] = resp.answer;
this.UserResponse[ resp.respName ] = 0;
});
}
else {
multiResp.forEach( resp => {
this.UserResponse[ resp.ctrlName ] = resp.answer;
this.UserResponse[ resp.respName ] = defVal;
});
}
}
else {
load.push(response);
load.forEach( ctrl => { this.UserResponse[ ctrl ] = defVal; });
this.UserResponse[ this.Data.ctrlName ] = this.Data.question;
}
}
I tried setting the value to UserResponse[respName] but the value property on the input just shows up as the word value with no equal next to it. I back and forth taking out the value property all together leaving just the ngModel stuff as well as commenting out the part of the function that sets the default value to see if just the value property alone would work without any other interference from from the function and it was the same result with the value being passed but the inputs being set in the middle. I tried setting it to 1 just to see if maybe 0 was making it null but that made no difference.
I even changed the value property on each question for that input in my json file to 1 and it shows up in the inspection yet doesn't change the default placement of the input. Can someone please shed some light on why this is happening and how to fix it? Here's a Plunkr of the entire mechanism if you need to see what else is going on.
If you change in the template,
[attr.value]="ans.value"
to,
[(ngModel)]="ans.value"
it should initialize the value to zero in the range input view (confirmed in plunker). Not sure what you are doing with the other ngModel in your template though.

HTML5 Time Element in Form with Milliseconds

There are several examples of HTML5 form options on this page, including the "time" element. Is it possible to force the time element to include a millisecond component?
I'm not concerned for the fallback option where a plain text box is used.
This works:
<input type="time" step="0.001"></input>
Live preview: http://jsbin.com/giqikelumu/edit?html,output
Simply use the step attribute. In case of a input type="time". The step attribute defaults to 60 (1 means 1 second). But you can also set fractions.
<input type="time" step="any" />
As its an input tag, the value can be entered into it by the user then using the step attribute as stated above will surely help.
What if this input is in the form and value can come from some API cal and is given to the form to show it. It can be changed too. If the requirement then is to show or not show the second or millisecond part we can do the following.
When second and millisecond is required
getFormatDate = function (val) { // assuming val is date like "/Date(946673340000)/"
if (val != undefined) {
date = new Date(val.match(/\d+/)[0] * 1); // creating a date object from val
return new Date(date.getFullYear(), date.getMonth(), date.getDate(),
date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
}
}
When second and millisecond is NOT required
getFormatDate = function (val) { // assuming val is date like "/Date(946673340000)/"
if (val != undefined) {
date = new Date(val.match(/\d+/)[0] * 1); // creating a date object from val
return new Date(date.getFullYear(), date.getMonth(), date.getDate(),
date.getHours(), date.getMinutes());
}
}