I am having trouble getting a filter to work on a number/text input.
<input type="number" class="text-center" ng-model="redeem.redemption.Amount | number: 2">
This throws an error: Expression 'redeem.redemption.Amount | number' is non-assignable
If I remove the filter, it works. I tried applying the same filter to the angular input demos and it works fine (https://docs.angularjs.org/api/ng/filter/number). Only difference I can see is I am binding to a an object on the scope and not a value directly. Is there something easy I am missing here?
I guess that what you are trying to do is to display the "formated value" of what they enter?
Then just remove the filter from the ng-model and in your controller watch the redeem.redemption.Amount and format it when the watch gets triggered. you will also need to set a timeout in order to allow the user to type, otherwise every time that the user hits a number the watch will try to format the number and the user won't be able to type anything.
The code that you have posted will never work because ng-model establishes a 2 way data binding with the property of the scope that you indicate, that's why you can not set filters there, it will only accept a property of the scope, that will be updated and from where it will read the value when it changes. The filter is a function with one input and retrieves a different output, think about it, if you set the filter, then Angularjs won't know where it has to set the changes of of the input.
Something like this:
app.controller('MyCtrl', function($scope,$filter,$timeout) {
$scope.testValue = "0.00";
var myTimeout;
$scope.$watch('testValue', function (newVal, oldVal) {
if (myTimeout) $timeout.cancel(myTimeout);
myTimeout = $timeout(function() {
if($filter('number')(oldVal, 2)!=newVal)
$scope.testValue = $filter('number')($scope.testValue, 2);
}, 500);
});
});
http://plnkr.co/edit/WHhWKdynw0nA4rYoy6ma?p=preview
Try tweaking the delay for the timeout, right now its been set to 500ms.
you cant put filter in ng-model directive.you can do it controller using this:
redeem.redemption.Amount=redeem.redemption.Amount.toFixed(2);
or you can use jquery to prevent keypress two digits after a decimal number like this:
$('.decimal').keypress(function (e) {
var character = String.fromCharCode(e.keyCode)
var newValue = this.value + character;
if (isNaN(newValue) || parseFloat(newValue) * 100 % 1 > 0) {
e.preventDefault();
return false;
}
});
<input type="number" id="decimal" class="text-center" ng-model="redeem.redemption.Amount | number:">
Related
Am using custom search filter
HtML
<input type="text" pInputText class="ui-widget ui-text" [(ngModel)]
="gloablFilterValue" (ngModelChange)="splitCustomFilter()" placeholder="Find" />
I am using ngModelChange() event on search box
globalSearch(realData, searchText, columns) {
searchText = searchText.toLowerCase();
return realData.filter(function (o) {
return columns.some(function (k) {
return o[k].toString().toLowerCase().indexOf(searchText) !== -1;
});
});
}
splitCustomFilter() {
let columns =
['PartNoCompleteWheel', 'DescriptionCompleteWheel', 'PartNoTyre', 'DescriptionTyre', 'PartNoRim', 'DescriptionRim','DeletedDateFromKDPStr', 'DateFromKDPStr', 'Status'];
this.tyreAndRimList = this.globalSearch(this.tyreAndRimList, this.gloablFilterValue, columns);
}
The this.tyreAndRimList list of values for the columns which is mentioned in a column variable.
Problem
The filter is working good! But the main problem is filter performance is very poor while the record count is huge(more than 100 rows per every column)
When
The filter is working good if am entering a single character (like a). But when I was typing the character continuously the browser is hanging. the reason is the filter has been firing every typing on the filter box(because of am using ngModelChange()// onchange() event)
What I want
I want to stop filtering if the user typing continuously on the search box. Once the user has stop the typing then only I need to start filtering.
What I did
I have tried to handle this by using setTimeout(). But it just wait the filter call for a second. It is working if the user entered just 2 or 3 character's continuously. But if the user typing more than 7 or 8 or above character's, it continues to hang the browser. because of many filter callbacks are processing on the same time.
setTimeout(() => //code of filtering ,1000);
Question
How to stop filtering while user continuously entering value and start the filtering once the user has been stop the typing?
I am working in angular-2 and typescript. But this question is not related with only for angularjs or angular or JavaScript or typescript because of I want an idea not a solution. So I'll add those all tags for this question. Don't remove it. Thanks
Debounce the function. See how underscore does it here: Function Debouncing with Underscore.js.
You would then generate a debounced version of your function like this:
var globalSearchDebounced = _.debounce(globalSearch, 100, false);
It will only call after the user has stopped typing for at least one second.
It's not possible to interrupt the Array.filter method. Based on what you need you could handle this like this:
let timerId = null
function handleChange() {
if(timerId) {
clearTimeout(timerId)
}
timerId = setTimeout(() => /* Array.filter(...) */, 1000)
}
Explanation
Have a variable which will contain the timerId returned from the setTimeout function. Every time the model get changed the handleChange function will be called (in this example). The function checks if the variable which contains the timerId is set and contains a timerId, when the variable contains the timerId the clearTimeout function will be called to clear the previous timeout after that the handleChange creates a new timeout and assigns the timerId (returned from the setTimeout function) to the variable.
Documentation for setTimeout
Documentation for clearTimeout
Without underscore, and without a Timeout (that will trigger the whole Angular lifecycle by the way), you can use an Observable with the async pipe and a debounce.
In your global search function :
return Observable.of(/* filter here and return the filtered array */).debounceTime(1000)
In your list (that has to be somewhere I guess)
<list-item *ngFor="let x of myFilteredResults | async">...</list-item>
I have complete it by using Subject to debounceTime.
private subject = new Subject<string>()
ngOnInit() {
this.subject.debounceTime(300).subscribe(inputText => {
this.gloablFilterValue = inputText;
this.splitCustomFilter(); // filter method
});
}
Now when I change the value in this.gloablFilterValue object by using change event. It just waiting for the end of event completion.
I am creating a web app in which I have a number in my $scope variable
$scope.total=20;
and I have one textbox
<input type="text" ng-model="amount1" ng-change="amountchange(amount1)" />
and when a user enters 500 in the textbox it should be 700 but instead the answer is coming 755 and when I delete 500 from my textbox it became null.
I just want to add or remove from my textbox what I am doing wrong here
Here is a fiddle created by me for better understanding
this problem is in this line:
$scope.total = parseInt($scope.amount1) + parseInt($scope.total);
you aggregate the value when you enter more input instead of just sowing the result.
what you can do is simple, add this method:
$scope.getTotal=function(){
return parseInt($scope.amount1) + parseInt($scope.total);
}
and replace {{total}} with this: {{getTotal()}}
It happens because of ng-change, each time the value is getting added
On entering 500,
Step1 5 + 200
Step2 50 + 205
Step3 500 + 255
and so it becomes 755. Use ng-blur instead of ng-change
<body data-ng-controller="myController">
<input type="text" ng-model="amount1" ng-blur="amountchange()" />
{{total}}
</body>
DEMO
What happens in your app is actually expected, because you add the current number on each input change.
Changing to ng-blur or setting a timeout before updating the value, using the built-in ng-model-options, which can now be done as of Angular 1.6 (released just yesterday) could be good options.
<input type="text" ng-model="amount1" ng-change="amountchange()" ng-model-options="{'debounce':{'default':300}}" />
or:
<input type="text" ng-model="amount1" ng-blur="amountchange()" />
However, I do not recommend either of them, and here's why:
By not letting the user decide when the data they entered is submitted (e.g.: pressing enter or a submit button) you make it user-unfriendly as well as introduce unwanted behaviour, such as when the user clicks off and on the in the second example, the number will have been added again and again...
Consider using a form and ng-submit instead as it's cleaner, more semantic and also conveys a friendlier way for your users to submit data.
Also here's the solution to your other issue:
$scope.amountchange = function () {
var amount = ($scope.amount1 != '') ? $scope.amount1 : 0;
console.log(amount)
if (amount != NaN) {
$scope.total = parseInt(amount) + parseInt($scope.total);
}
else {
alert("Please enter a number.");
$scope.amount1 = $scope.total;
}
}
To explain: first off you did not make use of any arguments, so you do not need to pass the amount1 model's value into the function in your directive. But that wasn't the problem. The reason why it set it to null is that the empty field doesn't parse to a 0, therefore you have to set it yourself. I saved the value into the variable amount on the function and assigned either the value of $scope.amount or 0 if it happens to be empty.
I am using angular js. How can i call a function if the length of the input text id greater than 5.
<input class="form-control" style="width:230px" ngmodel="Lookupemployer" ng-if={{ }} />
I want to call the below function
$scope.get = function()
{
}
if the length of the Lookupemployer is greater than 5.
I tried like this
ng-if={{ Lookupemployer.length >5 ? get() : ""}}
but did not work. Can anyone help me
Thanks,
The ng-if directive is used to determine whether or not to create the element in the DOM. It is not an actual conditional statement to be used to execute code.
Read the documentation for ng-if for further details: https://docs.angularjs.org/api/ng/directive/ngIf
You want to use ng-change. Call a method in that and have the function do the actual checking of the input length.
See the docs for more info: https://docs.angularjs.org/api/ng/directive/ngChange
First, you need to use ng-change - it will execute an expression on every change in the bound model.
You could do this all from the View, like so:
<input ng-model="foo" ng-change="foo.length > 5 && get()">
But it's better and cleaner to keep the logic out of the View (unless you consider it to be View-specific).
$scope.getIfNeeded = function(){
if ($scope.foo.length > 5) get();
}
And the View:
<input ng-model="foo" ng-change="getIfNeeded()">
I'm stumbling upon weird case while using angularJs and input type="number". Basically, if I have input with type number and initial value falls outside range defined by min and max, my initial value is simply destroyed.
I've made fiddle to illustrate the problem - http://jsfiddle.net/PK3QH/2/
HTML:
<div ng-controller="MyCtrl">
<input ng-model="bindData.SomeAmount" type="number" required="required" />
<br />
<input ng-model="bindData.SomeAmount" type="number" required="required"
min="2" max="10" />
</div>
Javascript:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.bindData = {
SomeAmount: 1
};
}
As you can see first textbox works without any problems, but the second one simply doesn't display the value. I definitely need value to be preserved while also being validated as number in certain range - so is there any way our this?
I agree this is a bug.
This happens because the formatters are applied first before validators.
The formatter in the case of 'number'
if (attr.min) {
var minValidator = function(value) {
var min = parseFloat(attr.min);
return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
};
ctrl.$parsers.push(minValidator);
**ctrl.$formatters.push(minValidator);**
}
all the $formatters are run first before the validators are run initially...checkout NgModelController.
I wonder if the "first" time when $dirty != true if they applied the formaters based on validity i.e. let the formatters yield if the validation results to false.
In the case of minNumber the formatter should be only a number. Why do we need a formatter for minNumber ?
Raised it https://github.com/angular/angular.js/issues/8264
Until the Angular team fixes this short term solution would be to use your own directive instead of min.
IMHO, this is a bug.
If you remove ng-model attribute, you see the initial value.
If this is NOT a bug, when we type invalid value such as 40, we must not see the entered text as it happend as when initialized. See, it's not consistent.
It only happens for the first time when input directive is initialized.
IMO, Even though, the model value is not value, it should preserve the original value by not setting to blank.
Sorry for not providing solution.
I'm using an input that takes a number that a user enters and converts it to a dollar amount when the blur event fires.
The issue I am having is that the browser seems to keep previously submitted values intact with their dollar signs. So if the user selects a previously entered value of '$25000' from the drop down list, when the blur event fires again it adds in the '$' so I get '$$25000'
In order to stop this, i've made an adjustment to the string value if it contains 2 '$'s on blur:
HTML:
<input type="text" value="$5,000" id="dollar-amount-goal" />
Javascript:
var valueOnBlur = $('#dollar-amount-goal').val();
if(valueOnBlur.charAt(1) === '$'){
valueOnBlur = $('#dollar-amount-goal').val(valueOnBlur.substr(1));
}
console.log(typeof( valueOnBlur ));
The result of the typeof statement above when the string checking is run is 'object'. any time after it comes out as 'string' (which is what I want).
My question: How do I make the "valueOnBlur = $('#dollar-amount-goal').val(valueOnBlur.substr(1));" statement return a string when it's run?
Thanks
Try changing this:
valueOnBlur = $('#dollar-amount-goal').val(valueOnBlur.substr(1));
To this:
valueOnBlur = $('#dollar-amount-goal').val(valueOnBlur.substr(1)).val();
You want the value of the $('#dollar-amount-goal') and not the jQuery object that $('#dollar-amount-goal') will return