I make a simple demo user login screen .I am facing one issue that get property function call multiple times (4 times).
Step to reproduce
Enter 10 digit number or email example test#gmail.com
Click continue button it show password screen.
click on change email or mobile no and see the console log it call four (4) times
here is my code
is there my implementation is wrong ?
here is my code
https://stackblitz.com/edit/angular-p5knn6?file=src%2Fapp%2Flogin-component%2Flogin-component.component.html
get userenterValue() {
console.log('log==')
return this.userInfo.username;
}
set userenterValue(val) {
this.userInfo.username = val;
}
That is expected, since you are using ngModel with set , whenever there is a change input value there will be a console.log entry.
The value bound on the html has to be evaluated every time something "has changed" in the app so that if the value of the bound item has changed it will be reflected to the html
Instead you could use ngBlur to get the value when the focus is left.
Instead of binding it using getters and setters. How about you try binding with the property itself like:
<input type="text" name="email"
autocomplete="off"
placeholder="Enter the Email or Number"
[(ngModel)]="userInfo.username"
required
[disabled]="showPasswordField"
pattern="^(\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+)$|^(\d{10})$">
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 am using protractor 4.0.10 to test an angular 1.5.10 with chromedriverVersion: 2.26.436382
My test is basically checking if an inputbox behaves properly when typing an invalid email, and then when the email is correct.
For the first part, I wait until ng-invalid-email is present in the class attribute (and then test for it). This step always work fine.
After that, I clear() the inputbox and add a valid email to it. After doing so I wait to see if ng-invalid-email disappear using a helper function:
function waitClassValueToDisappear(fieldElement, class_value) {
var local_class = class_value;
browser.wait(function() {
return element(by.model(fieldElement)).getAttribute('class').then(function(value) {
//console.log(value ,' <> ', local_class);
return value.indexOf(local_class) < 0;
});
}, 5000);
}
Most of the time, this seems to work properly but sometimes it times out. After doing some debugging, I found ng-invalid-email is kept as class attribute until the test above times out.
The test case screenshot shows the valid email in the inputbox and the inputbox has a blue frame (we are using red frame when ng-invalid-email is present).
I wonder if there is any problem in the way protractor queries the attributes of an ui element that could cause the behaviour above (or maybe this is provided by webdriver/selenium)?
If I uncomment the console.log above I see this when the error happens:
form-control (..lots of other values..) ng-not-modified-remove-active
ng-modified-add-active ng-valid-error-add-active
ng-invalid-pattern-remove-active ng-valid-pattern-add-active
ng-invalid-remove-active ng-valid-add-active <> ng-invalid-email (*
once or twice at the beginning)
and then mutiples:
form-control
ng-untouched ng-dirty ng-not-empty ng-invalid-email ng-valid-required
ng-invalid-pattern ng-valid ng-valid-error ng-modified <>
ng-invalid-email (.... repeating until it times out)
So it looks like the object class attribute has changed, but ng-invalid-email is still present, even though the screenshot tells me it is valid.
For reference, the full test case is as follows:
it(this.description, function() {
...
utils.waitModelExist(cs.alerts.ADD_EMAIL_INPUT);
browser.wait(EC.visibilityOf(app.getAppElementByModel(cs.alerts.ADD_EMAIL_INPUT)), TIME_TO_WAIT_MILLISECONDS);
app.getAppElementByModel(cs.alerts.ADD_EMAIL_INPUT).sendKeys('username');
actions.waitClassValueToBePresent(cs.alerts.ADD_EMAIL_INPUT, 'ng-invalid-email');
expect(app.getAppElementByModel(cs.alerts.ADD_EMAIL_INPUT).getAttribute('class')).toContain('ng-invalid-email');
app.getAppElementByModel(cs.alerts.ADD_EMAIL_INPUT).clear();
//actions.waitForAttributeValue(cs.alerts.ADD_EMAIL_INPUT, '');
app.getAppElementByModel(cs.alerts.ADD_EMAIL_INPUT).sendKeys('username#nowitis.valid');
//actions.waitForAttributeValue(cs.alerts.ADD_EMAIL_INPUT, 'username#nowitis.valid');
actions.waitClassValueToDisappear(cs.alerts.ADD_EMAIL_INPUT, 'ng-invalid-email');
expect(app.getAppElementByModel(cs.alerts.ADD_EMAIL_INPUT).getAttribute('class')).not.toContain('ng-invalid-email');
});
Any ideas? Is this a protractor problem?
Thanks
I am developing an application in Angularjs. I am using ng-keypress event in input type=text. While typing value in text I'm getting wrong values in the keypress function. For example, the first time if I type "1" I am getting undefined. Second time, typing any other value gives the first value
<input ng-model="NodeId_1" type="text" ng-keypress="getValue()"/>
var angularapp = angular.module('nameapp', []);
angularapp.controller('NameCtrl', function ($scope) {
$scope.getValue = function () {
alert($scope.NodeId_1);//Here first time undefined is coming and second what ever we enter first value will come
}
}
)
You'll want to use ng-keyup instead.
ng-keypress happens as the key is pressed, and BEFORE the value populates the input. This is why you're not getting any value on the first keypress, but on subsequent presses you will.
Use ng-keyup and your problem is solved, as it happens once the value has already populated the input.
<input ng-model="NodeId_1" type="text" ng-keyup="getValue()" />
ng-keypress is working as intended, but it is not the directive applicable to your requirements.
Working plunkr: http://plnkr.co/edit/OHWDZo68siDlcrXnLyzJ?p=preview
The keypress event is fired when a key is pressed down and that key
normally produces a character value (use input instead).
https://developer.mozilla.org/en-US/docs/Web/Events/keypress
So neither the input field value nor the scope value(apply/digest loop etc.) will reflect the expected input value.
Solution is depending on your requirements. Here are some:
1) Use another event on the inputfield: change, keyup, ...
2) Use the $event object in your listener method:
<input ng-model="NodeId_1" type="text" ng-keypress="getValue($event)"/>
$scope.getValue = function (event) {
console.log(event)
}
3) Create a watcher for your NodeId_1 value within your scope:
$scope.$watch('NodeId_1', function(newVal) {
...
});
The watcher function work for me, I attached my example
$scope.$watch('itemm.montoAmodificar', function (newValue) {
$scope.fnActualizarNuevoSaldoDependencia(parseFloat(newValue));
});
The html code is the following
<input ng-model="itemm.montoAmodificar" my-focus class="form-control" type="text" placeholder="Ingrese el monto" ng-keypress="fnActualizarNuevoSaldoDependencia($event);" />
My ultimate goal is to add some validation to a set of date fields. However, my javascript sucks, so I'm starting small.
I am starting out by trying to get an alert message when a user leaves a field.
(For simplicity I'm just doing it all in my view...) Heres what I go to work...
# html.erb-template
<div class="from_date">
From Date
<input type="text" id="from_date" name="from_date"></input>
</div>
<script>
$("#from_date").blur( function() {
alert("boom!");
});
</script>
Your code seems to be fine - problem is that class and id are named the same, but you want to watch the input field not the surrounding div.
I just made a fiddle from your script and changed
the listener to be attached to the input field's id - and it's working.
the alert into a console.log
see
$("#from_date").blur(function() {.....
// instead of
$(".from_date").blur(function() {.....
You can see in the paper form attached what I need to convert into a web form. I want it to show the check boxes and disable the input fields unless the user checks the box next to it. I've seen ways of doing this with one or two elements, but I want to do it with about 20-30 check/input pairs, and don't want to repeat the same code that many times. I'm just not experienced enough to figure this out on my own. Anyone know anywhere that explains how to do this? Thanks!
P.S. Eventually this data is all going to be sent through an email with PHP.
I don't think this is a good idea at all.
Think of the users. First they have to click to enter a value. So they always need to change their hand from mouse to keyboard. This is not very usable.
Why not just give the text-fields? When sending with email you could just leave out the empty values.
in your HTML :
//this will be the structure of each checkbox and input element.
<input type="checkbox" value="Public Relations" name="skills" /><input type="text" class="hidden"/> Public Relations <br/>
in your CSS:
.hidden{
display:none;
}
.shown{
display:block;
}
in your jQuery:
$('input[type=checkbox]').on('click', function () {
// our variable is defined as, "this.checked" - our value to test, first param "shown" returns if true, second param "hidden" returns if false
var inputDisplay = this.checked ? 'shown' : 'hidden';
//from here, we just need to find our next input in the DOM.
// it will always be the next element based on our HTML structure
//change the 'display' by using our inputDisplay variable as defined above
$(this).next('input').attr('class', inputDisplay );
});
Have fun.
Since your stated goal is to reduce typing repetitive code, the real answer to this thread is to get an IDE and the zen-coding plug in:
http://coding.smashingmagazine.com/2009/11/21/zen-coding-a-new-way-to-write-html-code/
http://vimeo.com/7405114