I'm trying to pass a ngModel to a function and get the change,
I don't know the way to use.
this is what I got now:
<ion-input text-right
formControlName="monday"
type="number" pattern="[0-9]*"
placeholder="00.00"
[(ngModel)]="monday"
(keypress)="onChange(monday)">
</ion-input>
<ion-input text-right
formControlName="tuesday"
type="number" pattern="[0-9]*"
placeholder="00.00"
[(ngModel)]="tueasday"
(keypress)="onChange(tuesday)">
</ion-input>
.... and so on...
Then in my page.ts I got
monday: string = '';
tuesday: string = '';
etc...
onChange(input: string){
//I want the input to correspond to my ngModel so it gets updated
input = this.clientAction.transformInput(input);
}
I don't want to do:
this.monday = this.clientAction.transformInput(input);
Because as you may think I got all the day of the week so I don't want to have a function for every day like:
onChangeMonday(){};
onChangeTuesday(){};
I need something dynamic.
How can I resolve this issue?
Thanks in advance
[SOLUTION] #AJT_82
instead of using my ngModel and trying to update it, the solution was to access the controls from the form.
in your page.html
<ion-input text-right
formControlName="monday"
type="number" pattern="[0-9]*"
placeholder="00.00"
[(ngModel)]="monday"
(keypress)="onChange(monday, 'monday')">
</ion-input>
then in your page.ts
onChange(input: string, day: string){
this.rateForm.controls[day].setValue(this.clientAction.transformInput(input));
}
works like a charm now !!
Thanks #AJT_82
Since you have a form, I would suggest that you skip the ngModels altogether and make use of the form you have. Still a bit unsure about what this.clientAction.transformInput(input) is supposed to do, transform the values somehow, as you explained. You should be able to incorporate this, perhaps when you submit the form? Anyway, as said, you have your form values safely stored in the object created by the form, which would for you look something like this:
{
"monday":null,
"tuesday":null,
"wednesday":null,
// ... and so on
}
When you type in your fields you can capture every keypress with valueChanges, where you can access the complete form:
this.myForm.valueChanges.subscribe(res => {
console.log("all form values: ", res) // here is an object with all your form values
})
When you need, you can also access each form control by, here accessing monday:
console.log(this.myForm.controls['monday'].value)
So this get's rid of the hassle to use ngModel for each form value.
So these are a couple of ways you can intercept the values and then "transform" them at some point, when you want/need to. Probably best place to do so, is when submitting form, loop the values and transform them. And this is totally dynamic, as you wished for, and do not need 7 functions to transform each form control! ;)
Hope this helps you, and here's a plunker (check the console as well).
Plunker
When you are using ngModel why do you want to pass the same in to function
<ion-input text-right
formControlName="monday"
type="number" pattern="[0-9]*"
placeholder="00.00"
[(ngModel)]="monday"
(keypress)="onChange()">
</ion-input>
and handle using the ngModel itself as
onChange(){
input = this.clientAction.transformInput(this.monday);
}
Update 1:
I got your are looking transform the textbox value as the user types it.
Check Custom Directive
Related
I've got a field for a product that its quantity is dependant on another product's quantity (cant be less than 70%, or more than 100%). Thing is, it evaluates it so quiclky that if the main field is '100', I cant enter 75 on the other field, because I first need to enter the '7', and my code considers it less than 70% and instantly changes it to the 70% value.
I've already tried using a self-made 'sleep' function, that makes a promise take some time to resolve.
setInterval and setTimeout also do not work as I intend for some reason (only evaluates the dependent field when I press enter, and it is not after the stablished time). This is not consistent with the rest of the table, so it is not a suitable solution.
This is the angular bit that controls this input
<div class="input-field">
<input class="input" type="number" [integerInput] ="true"
[disabled] ="item.deshabilitado( ) || !editable"
[(ngModel)] ="item.cantidad"
[ngModelOptions]="{standalone: true}"
(keyup) ="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
Sadly I cant get a minimal and working example. I need the dependent field to be able to evaluate its value automatically (without pressing enter or clicking on another field) without automatically correcting my input when I press only one character.
Use blur() method instead of keyup(). I guess you are validating the input with keyup() and each time you enter value it validates. For instance you are trying to enter 70 but when you enter first character, 7 it is invalid. The blur() fires your method and validates your input when you are done with inputting value.
<div class="input-field">
<input class="input" type="number" [integerInput]="true"
[disabled]="item.deshabilitado( ) || !editable"
[(ngModel)]="item.cantidad"
[ngModelOptions]="{standalone: true}"
(focusout)="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
In addition, you can use keyup.enter if a user is done with inputting value and presses enter. The value updates when the enter key is pressed or clicked somewhere else.
UPDATE:
I was able to solve this and get it to work like I intended at the beginning. The resulting code for the field I tried to validate would be
debounce (afterValueChanged)="setCantidad( item )"
It behaves in a way that does not need me to click outside the field for it to start validating, instead of the (blur) or (focusout)
Try to use the debounce function
Import debounceTime from rxjs and use it to add some delay :)
Check out this example
In the other field where you are trying to enter 75, you can add an ngModelOptions configuration to update only on blur.
[ngModelOptions]="{ updateOn: 'blur' }"
By default it updates on 'change', which explains the current behavior.
Update
You could also debounce the input using RXJS. This is probably closer to what you were trying to do with setInterval / setTimeout. This is also a use case where Reactive Forms really shines over Template Driven Forms imo, since you'll need to use RXJS operators.
For reactive driven forms, you just pipe an operator before subscribing to the valueChanges observable of the formControl
this.myInput.valueChanges
.pipe(
debounceTime(1000), // add 1 second of delay
distinctUntilChanged() // optional but recommended - only trigger for new values
)
.subscribe(val=> {
console.log('value', val);
});
It is possible to accomplish the same behavior in template driven forms but there is some setup involved. See this SO question/answer
As per the information given, you might want to debounce your function call.
Debounced functions do not execute when invoked, they wait for a pause of invocations over a configurable duration before executing; each new invocation restarts the timer.
<div class="input-field">
<input class="input" type="number" [integerInput] ="true"
[disabled] ="item.deshabilitado( ) || !editable"
[ngModel] ="item.cantidad"
[ngModelOptions]="{standalone: true}"
(keyup) ="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
In your component class:
timer;
setCantidad(item,value){
if(this.timer){
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
this.item.cantidad = value;
//perform any operations here
console.log(item, value);
},1000);
}
This will wait for the user to stop typing and execute the operation after the specified time in the timeout.
Note: One additional change, if you want to render the value in the same input field where you are typing, consider changing the [(ngModel)] -> [ngModel].
This will just perform a property binding and not event binding.
Demo stackblitz link : https://stackblitz.com/edit/angular-cu9gss
I've two text boxes with different ng-models. They fill up using a $http.get request on click of a button.
Lets say:
<input type="text" ng-model="name.title" />
<input type="text" ng-model="name.surname" />
These get filled up just fine from my JSON data.
The value of my name.title can sometimes be like "abc (123)". If a user edits this, I want the name.surname to become the part inside the (). If the user removes "abc (123)" and just types in 123, then 123 should reflect in name.surname.
I've tried various combinations using ng-blur and ng-change but nothing so far has worked for me.
Its just one two textboxes so no point writing a new directive.
How do I do this?
Any help will be appreciated. :)
I asume that your using angular 1.x.
You could have a watch over name.
something like in you
$scope.$watch('[name.title, name.surname]', function(newValue, prevValue) {
if (newValue === prevValue) {
return;
}
//Here you put your logic and update the models.
});
I'm doing a input with ng-model. But I want to keep the original value when someone put invalid number inside the input box. How can I achieve this?
Here's the plunker:
http://plnkr.co/edit/wX7n0jBn1Ek1py4DJHqT?p=preview
In the input box I'm using ng-model to bind the value. Also I specified the type of the input to be number.
<input type="number" name="input" ng-model="example.value" min="0" max="99" required>
But when I change the input the ng-model also changes. Can I delay this ng-model change until the number is valid? Or can I use ng-change to achieve this? But it seems that the ng-model will change when you change your input so the ng-change cannot capture the original value.
To make things clear, I'll have an example here:
if the current ng-model is 10, And I type 50. It'll change to 50. Then I type 5000 and it'll change to 5000.
If the current ng-model is 10, and I type 'aaa', It'll go back to 10.
The part I want to ask is how to make a copy of ng-model as I can set the ng-model back when I'm using onchange in this input box.
Putting you input type number you already validating your model correctly, what you need is to check if your form is valid. Take a look at validation with Angular here.
To make your value change only after input loose focus, use ng-model-options, your input should be like this:
<input type="number" name="input" ng-model="example.value" min="0" max="99" required ng-model-options="{ updateOn: 'blur' }">
You can always make directive to store last valid value, just add parser:
ngModelCtrl.$parsers.push(function(val) {
if (val) {
stored = val;
console.log(stored);
}
return val;
});
Then when you want you can revert value to last valid one. Example plunk:
http://plnkr.co/edit/XCacrP3Ij4ZCgyYYaoIa?p=preview
I don't know what you want to achieve with it, it's better to disable the save button until the form is valid.
return back to old value will create more problem, say current value is 10, I changed to 50, means valid and changed the value, further I typed to make it 5000, which value you want to return, 10, 5 or 50?
$scope.$watch('example.value', function(newValue, oldValue) {
if(newValue != oldValue){
//validate
if(!valid)
$scope.example.value = oldValue;
}
});
I have a huge form with many text boxes. Not all are mandatory but I dont want it to send undefined to my backend since many are of type integer and float.I need to define default values for all of them but I don't want the users to have to delete the default values before entering theirs everytime. The default values show up if I do value="defaultVal" in the <input>...</input> tag. I tried providing placeholder="..." but still value overrides placeholder. Any suggestions to achive this?
you can set the default value as you have been, and then just clear the input field onFocus, so that the user can enter into a fresh slate
You can try this:
<input type="text" onfocus="if(this.value == 'value') { this.value = ''; }" value="value" />
Source code
I have an input file element within an angular view/form. I'm using ng-upload like this:
<input id="img" type="file" name="image" onchange="angular.element(this).scope().setFile(this)">
<input id="imgname" type="hidden" value=""></div>
Since I can't tell angular to listen for changes on input[type="file"] element, I've created the method that updates the hidden input that just holds the current filename. That way I can run my validator on the second field.
Another field I have has some sort of validator, like this:
<input ng-model="other" ng-change="chg()"/>
Now, the trouble is, if I trigger the validator, $scope.chg(), from setFile() method, I think I don't get the same scope - chg() runs, but it's as if the validator is in another scope and doesn't set my actual submit button to enabled. I tried logging from the chg() - it shows different scope then what I actually see on the view.
And if I later trigger the ng-change by changing the regular input field ("other"), it picks up the changes, or actually, it sets the submit button state correctly.
Now, I suspect this has to do with me calling the angular.element(this).scope().setFile(this) from my form instead of direct, $scope-bound method. But I cannot call $scope-bound method because it does not trigger - if I understood correctly, that's due to Angular not (yet) working with input type=file fields.
What can I do here?
I simply want to detect if there is a file or not so I can enable/disable the submit button appropriately.
I used followed flow that works for me:
<input type="file"
ng-model="upFile"
onchange="angular.element(this).scope().setFileEventListener(this)"
/>
From controller:
$scope.setFileEventListener = function(element) {
$scope.uploadedFile = element.files[0];
if ($scope.uploadedFile) {
$scope.$apply(function() {
$scope.upload_button_state = true;
});
}
}
Hope it will help.