<ion-card *ngFor='#product of products | mapToIterable:"key":true'>
<ion-list>
<ion-item>
<ion-label stacked>Account No. / Phone No.</ion-label>
<ion-input type="text" [(ngModel)]="product.msisdn"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Amount</ion-label>
<ion-input type="text" (keypress)="isNumberKey($event)" [(ngModel)]="product.amount"></ion-input>
</ion-item>
</ion-list>
</ion-card>
Referring to the html above, how do I get the reference of ion-input so that I can setFocus()
on it after validation fails. I've already came out with the code below to validate each inputs.
for (var product of <any>this.products) {
if (product.service_type_id == 2 && !product.msisdn) {
alert('something');
//Get the element and set focus here.
}
}
Is this a good approach? Is there a better way of handling this in Angular 2?
An approach to get references of elements created with *ngFor
is @ViewChildren()
If the elements are actually components or directives then the component/directive type can be passed as parameter otherwise a template variable can be added and the name of the template variable (as string) can be used to query the elements.
In this case both a template variable and the component type return the component instance but to call focus we need the ElementRef.nativeElement
therefore I created a helper directive that is applied to ion-input
and is used to query the elements and also to call focus()
:
import {Component, Directive, Renderer, HostListener, ViewChildren, ElementRef} from 'angular2/core'
/// Helper directive
@Directive({
selector: 'ion-input'
})
class Focusable {
constructor(public renderer: Renderer, public elementRef: ElementRef) {}
focus() {
console.debug(this.elementRef.nativeElement);
this.renderer.invokeElementMethod(
this.elementRef.nativeElement, 'focus', []);
}
}
/// Test component instead of the original ion-input
@Component({
selector: 'ion-input',
host: {'tabindex': '1'},
template: `
<div>input (focused: {{focused}})</div>
`,
})
export class IonInput {
focused:boolean = false;
@HostListener('focus')
focus() {
this.focused = true;
}
@HostListener('blur')
blur() {
this.focused = false;
}
}
/// Queries the elements and calls focus
@Component({
selector: 'my-app',
directives: [IonInput, Focusable],
template: `
<h1>Hello</h1>
<div *ngFor="let product of products">
<ion-input #input type="text"></ion-input>
</div>
<button *ngFor="let product of products; let index=index" (click)="setFocus(index)">set focus</button>
`,
})
export class AppComponent {
constructor(private renderer:Renderer) {
console.debug(this.renderer)
}
products = ['a', 'b', 'c']
@ViewChildren(Focusable) inputs;
ngAfterViewInit() {
// `inputs` is now initialized
// iterate the elements to find the desired one
}
setFocus(index) {
// `inputs` is now initialized
// iterate the elements to find the desired one
//var input = ...
//console.debug(this.inputs.toArray()[1]);
this.inputs.toArray()[index].focus();
}
}
See also Angular 2: Focus on newly added input element
Plunker example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With