Angular change displayed value - html

I have an input that retrieve a numeric value. I would like to change the display on the html side, basically if the variable equals to let s say 7 the value displayed becomes 'abcdefg' instead of 7. On the contrary if I type abcdefg I would like for the form to understand that the value that should be stored is 7 and not the string. Is there a way to do that only on the HTML side ?
<div class="col-6">
<mat-form-field>
<input matInput placeholder="Cardinality Max" required #asbiepCardinalityMax
(change)="changeMax(asbiepCardinalityMax.value)"
(focus)="focusInMax(asbiepCardinalityMax.value)"
[(ngModel)]="asAsbiepDetail().cardinalityMax"
(ngModelChange)="onChange()"
[disabled]="!isEditable() || !asAsbiepDetail().used"
(keypress)="numberOnly($event)">
</mat-form-field>
</div>

You want to separate out the logic for controller to view binding and view to controller. You want to add separate functions for updating and reading. You can either add an event handler to set the value onChange and remove the () from the ngModel (removing the view -> controller updating), or use typescript getters and setters to bind to one value, with different logic.
Option 1:
HTML:
<div class="col-6">
<mat-form-field>
<input matInput placeholder="Cardinality Max" required #asbiepCardinalityMax
(change)="changeMax(asbiepCardinalityMax.value)"
(focus)="focusInMax(asbiepCardinalityMax.value)"
[ngModel]="fieldValue()"
(ngModelChange)="onChange()"
(change)="setFieldValue($event)"
[disabled]="!isEditable() || !asAsbiepDetail().used"
(keypress)="numberOnly($event)">
</mat-form-field>
</div>
Controller:
#Component({})
export class Controller {
realValue: number = 7;
setFieldValue($event) {
let newValue = $event.target.value;
//Code here to turn newValue into something correct for real value
if (newValue == 'abcdefg') {
realValue = 7;
}
}
fieldValue(): string {
if (realValue === 7) {
return 'abcdefg';
}
};
}
Option 2:
HTML:
<div class="col-6">
<mat-form-field>
<input matInput placeholder="Cardinality Max" required #asbiepCardinalityMax
(change)="changeMax(asbiepCardinalityMax.value)"
(focus)="focusInMax(asbiepCardinalityMax.value)"
[(ngModel)]="fieldValue"
(ngModelChange)="onChange()"
[disabled]="!isEditable() || !asAsbiepDetail().used"
(keypress)="numberOnly($event)">
</mat-form-field>
</div>
Controller:
#Component({})
export class Controller {
realValue: number = 7;
set FieldValue(newValue): void {
//Code here to turn newValue into something correct for real value
if (newValue == 'abcdefg') {
realValue = 7;
}
}
get fieldValue(): string {
if (realValue === 7) {
return 'abcdefg';
}
};
}
And then you use realValue where you want.
The advantage of the first is you can pick what event you want to fire the function that sets the value on the controller - you might want change, keyup, keydown, blur - you can have any of the classic javascript events. The second approach requires onChange.

Related

Get the radio button value in a form [duplicate]

I’m having some strange problem with my JS program. I had this working properly but for some reason it’s no longer working. I just want to find the value of the radio button (which one is selected) and return it to a variable. For some reason it keeps returning undefined.
Here is my code:
function findSelection(field) {
var test = 'document.theForm.' + field;
var sizes = test;
alert(sizes);
for (i=0; i < sizes.length; i++) {
if (sizes[i].checked==true) {
alert(sizes[i].value + ' you got a value');
return sizes[i].value;
}
}
}
submitForm:
function submitForm() {
var genderS = findSelection("genderS");
alert(genderS);
}
HTML:
<form action="#n" name="theForm">
<label for="gender">Gender: </label>
<input type="radio" name="genderS" value="1" checked> Male
<input type="radio" name="genderS" value="0" > Female<br><br>
Search
</form>
This works with any explorer.
document.querySelector('input[name="genderS"]:checked').value;
This is a simple way to get the value of any input type.
You also do not need to include jQuery path.
You can do something like this:
var radios = document.getElementsByName('genderS');
for (var i = 0, length = radios.length; i < length; i++) {
if (radios[i].checked) {
// do whatever you want with the checked radio
alert(radios[i].value);
// only one radio can be logically checked, don't check the rest
break;
}
}
<label for="gender">Gender: </label>
<input type="radio" name="genderS" value="1" checked="checked">Male</input>
<input type="radio" name="genderS" value="0">Female</input>
jsfiddle
Edit: Thanks HATCHA and jpsetung for your edit suggestions.
document.forms.your-form-name.elements.radio-button-name.value
Since jQuery 1.8, the correct syntax for the query is
$('input[name="genderS"]:checked').val();
Not $('input[#name="genderS"]:checked').val(); anymore, which was working in jQuery 1.7 (with the #).
ECMAScript 6 version
let genderS = Array.from(document.getElementsByName("genderS")).find(r => r.checked).value;
Here's a nice way to get the checked radio button's value with plain JavaScript:
const form = document.forms.demo;
const checked = form.querySelector('input[name=characters]:checked');
// log out the value from the :checked radio
console.log(checked.value);
Source: https://ultimatecourses.com/blog/get-value-checked-radio-buttons
Using this HTML:
<form name="demo">
<label>
Mario
<input type="radio" value="mario" name="characters" checked>
</label>
<label>
Luigi
<input type="radio" value="luigi" name="characters">
</label>
<label>
Toad
<input type="radio" value="toad" name="characters">
</label>
</form>
You could also use Array Find the checked property to find the checked item:
Array.from(form.elements.characters).find(radio => radio.checked);
In case someone was looking for an answer and landed here like me, from Chrome 34 and Firefox 33 you can do the following:
var form = document.theForm;
var radios = form.elements['genderS'];
alert(radios.value);
or simpler:
alert(document.theForm.genderS.value);
refrence: https://developer.mozilla.org/en-US/docs/Web/API/RadioNodeList/value
Edit:
As said by Chips_100 you should use :
var sizes = document.theForm[field];
directly without using the test variable.
Old answer:
Shouldn't you eval like this ?
var sizes = eval(test);
I don't know how that works, but to me you're only copying a string.
Try this
function findSelection(field) {
var test = document.getElementsByName(field);
var sizes = test.length;
alert(sizes);
for (i=0; i < sizes; i++) {
if (test[i].checked==true) {
alert(test[i].value + ' you got a value');
return test[i].value;
}
}
}
function submitForm() {
var genderS = findSelection("genderS");
alert(genderS);
return false;
}
A fiddle here.
This is pure JavaScript, based on the answer by #Fontas but with safety code to return an empty string (and avoid a TypeError) if there isn't a selected radio button:
var genderSRadio = document.querySelector("input[name=genderS]:checked");
var genderSValue = genderSRadio ? genderSRadio.value : "";
The code breaks down like this:
Line 1: get a reference to the control that (a) is an <input> type, (b) has a name attribute of genderS, and (c) is checked.
Line 2: If there is such a control, return its value. If there isn't, return an empty string. The genderSRadio variable is truthy if Line 1 finds the control and null/falsey if it doesn't.
For JQuery, use #jbabey's answer, and note that if there isn't a selected radio button it will return undefined.
First, shoutout to ashraf aaref, who's answer I would like to expand a little.
As MDN Web Docs suggest, using RadioNodeList is the preferred way to go:
// Get the form
const form = document.forms[0];
// Get the form's radio buttons
const radios = form.elements['color'];
// You can also easily get the selected value
console.log(radios.value);
// Set the "red" option as the value, i.e. select it
radios.value = 'red';
One might however also select the form via querySelector, which works fine too:
const form = document.querySelector('form[name="somename"]')
However, selecting the radios directly will not work, because it returns a simple NodeList.
document.querySelectorAll('input[name="color"]')
// Returns: NodeList [ input, input ]
While selecting the form first returns a RadioNodeList
document.forms[0].elements['color']
// document.forms[0].color # Shortcut variant
// document.forms[0].elements['complex[naming]'] # Note: shortcuts do not work well with complex field names, thus `elements` for a more programmatic aproach
// Returns: RadioNodeList { 0: input, 1: input, value: "red", length: 2 }
This is why you have to select the form first and then call the elements Method. Aside from all the input Nodes, the RadioNodeList also includes a property value, which enables this simple manipulation.
Reference: https://developer.mozilla.org/en-US/docs/Web/API/RadioNodeList/value
Here is an Example for Radios where no Checked="checked" attribute is used
function test() {
var radios = document.getElementsByName("radiotest");
var found = 1;
for (var i = 0; i < radios.length; i++) {
if (radios[i].checked) {
alert(radios[i].value);
found = 0;
break;
}
}
if(found == 1)
{
alert("Please Select Radio");
}
}
DEMO : http://jsfiddle.net/ipsjolly/hgdWp/2/ [Click Find without selecting any Radio]
Source (from my blog): http://bloggerplugnplay.blogspot.in/2013/01/validateget-checked-radio-value-in.html
Putting Ed Gibbs' answer into a general function:
function findSelection(rad_name) {
const rad_val = document.querySelector('input[name=' + rad_name + ']:checked');
return (rad_val ? rad_val.value : "");
}
Then you can do findSelection("genderS");
lets suppose you need to place different rows of radio buttons in a form, each with separate attribute names ('option1','option2' etc) but the same class name. Perhaps you need them in multiple rows where they will each submit a value based on a scale of 1 to 5 pertaining to a question. you can write your javascript like so:
<script type="text/javascript">
var ratings = document.getElementsByClassName('ratings'); // we access all our radio buttons elements by class name
var radios="";
var i;
for(i=0;i<ratings.length;i++){
ratings[i].onclick=function(){
var result = 0;
radios = document.querySelectorAll("input[class=ratings]:checked");
for(j=0;j<radios.length;j++){
result = result + + radios[j].value;
}
console.log(result);
document.getElementById('overall-average-rating').innerHTML = result; // this row displays your total rating
}
}
</script>
I would also insert the final output into a hidden form element to be submitted together with the form.
I realize this is extremely old, but it can now be done in a single line
function findSelection(name) {
return document.querySelector(`[name="${name}"]:checked`).value
}
I prefer to use a formdata object as it represents the value that should be send if the form was submitted.
Note that it shows a snapshot of the form values. If you change the value, you need to recreate the FormData object. If you want to see the state change of the radio, you need to subscribe to the change event change event demo
Demo:
let formData = new FormData(document.querySelector("form"));
console.log(`The value is: ${formData.get("choice")}`);
<form>
<p>Pizza crust:</p>
<p>
<input type="radio" name="choice" value="regular" >
<label for="choice1id">Regular crust</label>
</p>
<p>
<input type="radio" name="choice" value="deep" checked >
<label for="choice2id">Deep dish</label>
</p>
</form>
If it is possible for you to assign a Id for your form element(), this way can be considered as a safe alternative way (specially when radio group element name is not unique in document):
function findSelection(field) {
var formInputElements = document.getElementById("yourFormId").getElementsByTagName("input");
alert(formInputElements);
for (i=0; i < formInputElements.length; i++) {
if ((formInputElements[i].type == "radio") && (formInputElements[i].name == field) && (formInputElements[i].checked)) {
alert(formInputElements[i].value + ' you got a value');
return formInputElements[i].value;
}
}
}
HTML:
<form action="#n" name="theForm" id="yourFormId">
I like to use brackets to get value from input, its way more clear than using dots.
document.forms['form_name']['input_name'].value;
var value = $('input:radio[name="radiogroupname"]:checked').val();

How to check on page load if input and select boxes are empty with Javascript

I am using Vue.js to create a form. Currently my HTML looks like this:
<div class="form-group m-0" role="group">
<label class="d-block form-label" for="code_part3">Last Three</label>
<div>
<input class="form-input form-control is-invalid hasError" type="text"><!----><!----><!---->
</div>
</div>
When a user focuses on an input, or changes a select box, a class (.focused) is added to the main parent (.form-group). This animates the label to sit on top of the input/select box. And on blur a method is ran to check if the input value is to empty.
resetAnimateInputLabel() {
var target = event.currentTarget;
var inputValue = event.currentTarget.value;
var parentOfParent = target.parentElement.parentElement;
if (inputValue == "") {
//remove focused class to Parent of Parent to animate
parentOfParent.classList.remove("focused");
}
}
However I am using localStorage which will prepopulate the input fields when a user returns to the page. This causes an issue where the label is restored back to its original position (within the input itself) and both text clash.
What is the best way to solve this, so that on page load, if an input or select box is empty, for the label to remain animated?
I have tried the following:
Created a new method:
checkInputEmpty() {
var inputs = document.getElementsByClassName("form-input");
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].value == "") {
inputs[i].parentElement.parentElement.classList.remove("focused");
} else {
inputs[i].parentElement.parentElement.classList.add("focused");
}
}
}
and called it here:
mounted() {
this.checkInputEmpty();
if (localStorage.email !== "undefined") {
this.form.email = localStorage.email;
}
}
You could do two things differently to handle this in a simple and elegant way:
First - Checking input values:
Step 1: Having data property for storing the input value
data () {
return {
inputValue: '',
}
}
Step 2: Binding your input to that property
<input v-model="inputValue" />
Step 3: Investigating the data property and handling both cases as needed (wherever needed)
if (this.inputValue) {
// here, the input value is non-empty ("", null, undefined would evaluate to false)
} else {
// here, the input value is empty
}
Second - Class toggling
Step 1: You don't have to set and remove classes in this complicated way:
inputs[i].parentElement.parentElement.classList.add("focused");
Instead you can, again, create a data property for storing toggled state of the focused class:
data () {
return {
inputValue: '',
formFocused: false
}
}
Step 2: Dynamically assign the class to your element like this:
<div
class="form-group m-0" role="group"
:class="{ 'focused' : formFocused }"
>
...
</div>
Step 3: And handle the property as needed, in your case probably like this:
if (this.inputValue) {
this.formFocused = false;
} else {
this.formFocused = true;
}
Which is the same as:
this.formFocused = !this.inputValue;
For more info:
https://v2.vuejs.org/v2/guide/forms.html#v-model-with-Components
https://v2.vuejs.org/v2/guide/class-and-style.html

How do I perform field validation within the Angular typescript and not in the form?

Due to specific requirements, I need to validate the presence of my delivery.address field within the typescript code, so I am calling a function, addressIsValid(), to do this as shown in the code below.
<div class="col col-md-6 col-lg-12">
<input class="form-control" type="text" name="address" id="address"
[(ngModel)]="delivery.address" #address="ngModel">
<ng-container *ngIf="delivery.method=='Delivery'">
<div *ngIf="!addressIsValid()" class="primary-color">
<!-- <div *ngIf="address.invalid && (address.dirty
|| address.touched)" class="primary-color"> -->
Address is required
<!-- </div> -->
</div>
</ng-container>
</div>
Typescript function:
public addressIsValid() {
return !this.delivery.address == undefined
&& !this.delivery.address == null;
}
The problem is after valid value is entered into the field, the error message: "Address is required." does not go away. How do I fix this?
I think the problem is in your addressIsValid function.
Take this 2 objects for example:
const o = { name: 'john' };
const o2 = { name: undefined };
!o.name --> false;
!o2.name --> true;
Neither of the above fulfills the condition == undefined or == null.
Thus, you will always get a falsy value.
You could modify your function like this:
public addressIsValid() {
return this.delivery.address !== undefined
&& this.delivery.address !== null;
}
You probably wanted to check this:
public addressIsValid() {
return !!this.delivery.address;
}
example
If that is not the case you need to debug what this.delivery actually contains after your method call.
console.log(this.delivery)
And tell us what that contains.
I would suggest reading about Angular Reactive Forms. You can easily define validation rules in TypeScript and drive the display of error messages in your view.
this.heroForm = new FormGroup({
'name': new FormControl(this.hero.name, [
Validators.required,
Validators.minLength(4),
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
]),
'alterEgo': new FormControl(this.hero.alterEgo),
'power': new FormControl(this.hero.power, Validators.required)
});
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="name.errors.forbiddenName">
Name cannot be Bob.
</div>
Also take a look at the FormBuilder service, which will help condense the form creating syntax.

Reactive form angular using FormArrayName

In my form I need to add phones, I have seen that in the database you are saving a string array with the phone numbers that I added, but the moment the value returned from the database is set to the form, only the first array value is shown .
I would like to display all array values that contain number of phones in string format.
component.html:
<div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start">
<div formArrayName="phones" fxFlex="30">
<div *ngFor="let phone of phones.controls; index as i">
<mat-form-field>
<input matInput [formControlName]="i" placeholder="Phone Number">
</mat-form-field>
</div>
</div>
<div fxFlex="30">
<button mat-raised-button class="blue" (click)="addPhone()">Add</button>
</div>
</div>
component.ts:
this.myForm = this._formBuilder.group({
phones: new FormArray([new FormControl('')]),
});
this.values$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((values) => {
// values = {phones: ['999999', '88888', '77777']}
if (values) {
this.myForm.patchValue(values, { emitEvent: false });
}
});
get phones(): FormArray { return this.myForm.get('phones') as FormArray; }
addPhone(): void { this.phones.push(new FormControl('')); }
Even returning more than one value inside the array only displays the first array value on my form, what am I doing wrong?
patchValue won't create any form controls for you, so when you call patchValue it only sets the value for the first form control in your form array, because you only created one.
You have to call addPhone for each phone number or create form inside the describe when you already know how many form controls there should be, but you still need to create as many form controls as number of elements in your array.
this.myForm = this._formBuilder.group({
phones: new FormArray(),
});
this.values$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((values) => {
if (values && values.phones) {
phones.forEach(phone => this.addPhone(phone));
}
});
get phones(): FormArray { return this.myForm.get('phones') as FormArray; }
addPhone(phone = ''): void { this.phones.push(new FormControl(phone)); }

Check html input before it's updated

I'm trying to implement a time picker in Angular, and I'm having some trouble figuring out how to check if the text input is valid.
In the html I have an input element that binds to keyPress function.
<input matInput style="text-align: right;" [(ngModel)]="hour" type="number" min="0" max="23" (keypress)="keyPress($event)">
keyPress(event: any) {
const pattern = /^(([[0|1]\d)|(2[0-3]))$/;
let inputChar = String.fromCharCode(event.charCode);
let tempHour = this.hour;
if (!tempHour) {
tempHour = '0';
}
let newHour = (+tempHour * 10 + +inputChar).toString();
if (newHour.length === 1) {
newHour = '0' + newHour;
}
if (!pattern.test(newHour)) {
event.preventDefault();
}
}
The problem here is that the event passed to the keyPress function only contains the current pressed key. This works fine unless the user moves the input cursor. For example: If user presses key "1", and then moves the cursor backwards and enter a "9". My code will treat it as 19 and let it pass, but the actual input is 91. So I guess I need to some how get the cursor position? Or is there a better way to solve this?
Thanks very much!
The problem is that the keypress-event happens before ngModel updates your "hour" variable. In your case I'd suggest to react on the change-event which gets fired after ngModel has already done its update.
(change)="onChange($event)"
And then your method can look like this
<input matInput style="text-align: right;" [(ngModel)]="hour" type="number" min="0" max="23" (change)="onChange($event)">
private lastValue: number = 0;
onChange(event: any) {
const pattern = /^(([[0|1]\d)|(2[0-3]))$/;
if (!pattern.test(this.hour)) {
this.hour = this.lastValue;
} else {
this.lastValue = this.hour;
}
}