change a variable value using *ngIf in angular 7 - html

I am trying to add some validation using [pattern] in an angular 7 application. I want to disable a button using a variable this.isSubmitDisabled if the pattern has errors ( phoneNumber.errors?.pattern ).
I know that this can be achieved using Reactive form but unfortunately, I cannot use forms. Is there a way to set the variable value to 'true' if phoneNumber.errors?.pattern is true?.
Here is my code:
<input
type="text"
class="form-control"
(ngModelChange)="dialInDetailsChange($event)"
name="dialInDetails"
[disabled]="false"
id="dialInDetails"
pattern="^\d+(?:[,.]\d+)?$"
required
[(ngModel)]="agendaMeeting.dialInDetails"
ngModel #dialInDetails="ngModel" />

You can also check it using .match() in your .ts file. On model change just check whether the entered value matches your regex. If matches then set inputDisabled to false otherwise set inputDisabled to true.
let inputDisabled:boolean = false;
dialInDetailsChange(event:any){
if(agendaMeeting.dialInDetails.match("^\d+(?:[,.]\d+)?$") === null){
inputDisabled = true;
}
else{
inputDisabled = false;
}
}
Edit after recent comment
WORKING DEMO : LINK
myInput='';
result='';
changeHandler(){
if(this.myInput.match('^[\\s]+[a-zA-Z]*') === null){
this.result = "correct input";
}
else{
this.result = "there are spaces at the begining."
}
}

i think you can't assign values using expression in your template, check the documentations
You can't use JavaScript expressions that have or promote side effects, including:
Assignments (=, +=, -=, ...)
Operators such as new, typeof, instanceof, etc.
Chaining expressions with ; or ,
The increment and decrement operators ++ and --
Some of the ES2015+ operators

try this :
<input
type="text"
class="form-control"
(ngModelChange)="updateState(phone)"
name="dialInDetails"
[disabled]="false"
id="dialInDetails"
pattern="^\d+(?:[,.]\d+)?$"
required
[(ngModel)]="agendaMeeting.dialInDetails"
#phone="ngModel" />
<button type="button" [disabled]="isDisabled">Submit</button>
updateState(input){
this.isDisabled = input.errors && input.errors.pattern ? true : false ;
}

Related

How to restrict invalid values from entering in an input field having a regex pattern

I have an input field in which I want first 4 characters to be numbers only, after that only dot(.) is allowed, and then only 2 numbers allowed. Example: 9999.99
I also want that if I am entering something else it should not enter in input field.
For this I created a regex as : ^[0-9]{4}+\.+[0-9]{2}+$
HTML: <input type="text" (keypress)="onKeydown($event)">
TS:
regex = '/^[0-9]{4}+\.+[0-9]{2}+$/';
onKeydown(event) {
if(event.target.value.match(this.regex)) {
return true;
} else return false;
}
But I guess I am doing something quite wrong here. Kindly let me know about it.
Thanks.
You don't need + (select 1 or more matches) in your regex.
Instead, you need | (or) to catch two cases: when input does not contain dot and when dot is added.
Try something like this: /^(?:\d{0,4}|\d{4}\.\d{0,2})$/.
I've added ?: (non-capturing group mark) to exclude group in match, but it's not necessary.
UPDATE: here's a quick sketch using oninput event handler:
var regex = /^(?:\d{0,4}|\d{4}\.\d{0,2})$/;
var lastValue = "";
function onInput(e) {
var currentValue = e.target.value;
if (!currentValue.match(regex))
e.target.value = lastValue;
else
lastValue = currentValue;
}
<input type="text" oninput="onInput(event)">

Angular6 - Custom Input field

I have to create input field in Angular, that input field allow only number with 2 decimal places like '123455.12'
Below is what i have tried so far
<input myCustomDirective type="text">
I created Directive. In my CustomDirective I used HostListener for keypress event in that listener i used regular expression to validate but it allow only number it not allowing to enter '.(dot)'
new RegExp('^[0-9]*$');// my regular expression
Here's a Directive that takes Only Decimal Values with custom
precisions.
https://stackblitz.com/edit/angular-decimal-directive
It will allow you to put digits before the .(dot)
It will not allow you to paste (ctrl+v) non-decimal.
It will take single .(dot) . by default it will take 2 digit after the . (dot).
Example:
`<input type="text" [(ngModel)]="myVar" decimal>`
But you can define the precision size like that :-
`<input type="text" [(ngModel)]="myVar" [decimal]="3">`
If you want to use Only Integer not floating point you can use the Directive Like this:
<input type="text" [(ngModel)]="myVar" [decimal]="0">
If you don't complete enough precision in the input , then it will
automatically complete rest of the number precision (also if a .(dot)
needed) by onblur event.
You Can't inject string value by two way binding.
N.B: [(ngModel)] is mandatory for using the Directive.
ng-pattern that you reguire is ng-pattern=" /^[.\d]+$/"
Please check out the fiddle jsfiddle.net/gsferreira/Lsv9f0b0 , posted in link ,
ng-pattern="/^[0-9]+(\.[0-9]{1,2})?$/" is the key
From Plain Old Java script fiddle link https://jsfiddle.net/j3cbytws/
Only numbers please and a single dot allowed , nothing else:
<input type="number" name="someid" onkeypress="return isNumberKey(event)" />
<script>
var isDecimalAlredyEcountered = false;
function isNumberKey(evt){
var charCode = (evt.which) ? evt.which : event.keyCode
if(isDecimalAlredyEcountered && charCode === 46)
return false;
if(charCode == 46)
{isDecimalAlredyEcountered =true;
}
if (charCode > 31 && (charCode < 48 || charCode > 57)&& charCode != 46)
return false;
return true;
}
</script>
There can be an issue of backspace char and delete with the above implementation, so you have to reset the state on clear

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.

Allow Single Type Input in Html

Ok so i have a Chatroom, People are required to type in a name and once done they may chat. But alot of times people take other peoples name. So what i need is kind of like a limited input
here is the input:
<input type="text" class="input-block-level" ng-model="name" ng-change="setName()" placeholder="Your Name" maxlength="10" required></div>
I need this so if i type in the name Bob, no one can use that name again
Incase you want the website: https://project-js-imthatguy.c9users.io/
One possible way to check amongst a given set...
used a simple for loop for this example
Inside your send function that you have defined, perform a check:
$scope.send = function send() {
var isDuplicated = 0
for (i = 0; i < $scope.roster.length; i++){
if ($scope.roster[i] == $scope.name){ isDuplicated++ }
}
if (isDuplicated > 1){
//make an error message appear here
//quick and dirty solution
alert('Please choose a name that has not been taken by someone else')
//suggestion set a variable here to true and then use that variable to show/hide a div below the user input area
}
else {
console.log('Sending message:', $scope.text);
socket.emit('message', $scope.text);
$scope.text = '';
}
};

How to filter or custom filter array of objects based on matching values from another object

I implemented an advance search with 15 input fields in AngularJS.
In the page load itself the result set is return from database in JSON format and i need to do the filter in client side only.
The input criteria's equivalent column is available in the result set and i need to check in its respective column only.
I am converting each column by JSON.stringify() and check with the search params like the below :
$scope.filteredData = $scope.actualData.filter(function(item) {
return JSON.stringify(item.FirstName).toLowerCase().indexOf(lowerFirstName) != -1 &&
JSON.stringify(item.LastName).toLowerCase().indexOf(lowerLastName) != -1 &&
JSON.stringify(item.EmailAddress).toLowerCase().indexOf(lowerEmailAddress) != -1 &&
JSON.stringify(item.Address1).toLowerCase().indexOf(lowerAddress1) != -1 &&
JSON.stringify(item.Address2).toLowerCase().indexOf(lowerAddress2) != -1;
...... etc // upto 15 fields
});
Since i have the 15 input fields and the actual result set contains a minimum of 50,000 records.
So converting each record's each column by JSON.stringify() and check with search params will surely cause the performance issue.
Is there any other way to achieve the filtering in client side with other approach.
I posted a sample code in Plunker with 5 input fields only : http://plnkr.co/edit/nUWZEbGvz7HG6gb91YZP
sylwester's answer is the normal way you'd filter things. Your code looks like you want to filter down to only the object that matches every input field. You code attempts to find an object where every property matches the searchParams object. At that point, I don't see what benefit there is to finding that object, because the user already created the object again! Nonetheless, here's a proper version of your code:
Live demo here.
<div ng-repeat="data in actualData | filter:searchData()">
$scope.searchData = function() {
return function(item) {
return Object.keys(item).every(function(key) {
// skip the $$hashKey property Angular adds to objects
if (key === '$$hashKey') { return true; }
var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
return item[key].toLowerCase() === $scope.searchParams[searchKey].toLowerCase();
});
};
};
You really need to limit the data coming from the server for the browser's sake and for the server's sake. It's easy to implement a LIMIT, OFFSET system. It sounds like, overall, you just need to be able to query the server for a certain record.
From your comments, it seems you definitely want Angular's built in filter filter:searchParams, and just capitalize your searchParams models to match your data. For fun, I'll include more options for finer tuning.
This one almost mimics filter:searchParams. You can change > 1 to adjust when the partial matching kicks in, or have it return true only when both items are strictly equal === to disable partial matching. The difference here is that all items are hidden until matched, whereas filter:searchParams will show all items and then remove what doesn't match.
Live demo here.
$scope.searchData = function() {
return function(item) {
return Object.keys(item).some(function(key) {
if (key === '$$hashKey') { return false; }
var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
var currentVal = $scope.searchParams[searchKey].toLowerCase();
var match = item[key].toLowerCase().match(currentVal);
return currentVal.length > 1 && match;
});
};
};
Lastly, to perfectly mimic filter:searchParams, you'd just put in a check to NOT filter the items until there is user input and the input is long enough to start the partial match.
Live demo here.
$scope.searchData = function() {
var partialMatchLength = 2;
return function(item) {
var shouldFilter = Object.keys($scope.searchParams).some(function(key) {
return $scope.searchParams[key] && $scope.searchParams[key].length >= partialMatchLength;
});
if (!shouldFilter) { return true; }
return Object.keys(item).some(function(key) {
if (key === '$$hashKey') { return false; }
var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
var currentVal = $scope.searchParams[searchKey].toLowerCase();
var match = item[key].toLowerCase().match(currentVal);
return currentVal.length >= partialMatchLength && match;
});
};
};
First of all you ng-repeter with 50.000 records more likely is going to kill your browser, so you should thing about pagination.
Secondly you can easy filter your data using angular filter please see that demo
http://plnkr.co/edit/R8b8G4xCMSQmX1144UJG?p=preview
<div ng-controller="ListCtrl">
<br />
First Name:
<input type="text" id="txtFirstname" ng-model="searchParams.FirstName">
<br/>Last Name:
<input type="text" id="txtLastname" ng-model="searchParams.LastName">
<br/>Email Address:
<input type="text" id="txtEmailAddress" ng-model="searchParams.EmailAddress">
<br/>Address 1:
<input type="text" id="txtAddress1" ng-model="searchParams.Address1">
<br/>Address 2:
<input type="text" id="txtAddress2" ng-model="searchParams.Address2">
<br/>
<button class="btn btn-primary" ng-click="searchData()">Search</button>
<br />
<hr />
<b>Filtered Data(s):</b>
<div ng-repeat="data in actualData | filter:searchParams ">
<span ng-bind="data.FirstName"></span>
<span ng-bind="data.LastName"></span> |
Address : {{data.Address1}}
</div>
<hr />
</div>