I've many input
boxes in a div
and I need to focus one of them programmatically.
How to do it?
It's something like:
<div>
<input type="text" name="txt1" />
<input type="text" name="txt2" />
<input type="text" name="txt3" />
<input type="text" name="txt4" />
<input type="text" name="txt5" />
<input type="text" name="txt6" />
</div>
<button (click)="selectSample()" />
selectSample() {
?????????('txt3').focus();
console.log('Button pressed, txt3 has been selected');
}
@Component({
selector: 'my-app',
template: `
<div>
<input #input type="text" name="txt1" />
<input #input type="text" name="txt2" />
<input #input type="text" name="txt3" />
<input #input type="text" name="txt4" />
<input #input type="text" name="txt5" />
<input #input type="text" name="txt6" />
</div>
<button (click)="selectSample()">click</button>
`
})
export class App {
@ViewChildren('input') inputs;
selectSample() {
// console.debug(this.inputs.toArray().find((e) => {
// return e.nativeElement.getAttribute('name') == 'txt3';
//}).nativeElement.value);
this.inputs.toArray().find((e) => {
return e.nativeElement.getAttribute('name') == 'txt3';
}).nativeElement.focus();
}
}
Plunker example
Take a look at the ViewChild
(and ViewChildren
like Gunter suggests) annotations.
You can do something like this:
@Component({
selector: 'samples',
template: `
<div>
<input type="text" name="txt1">
<input type="text" name="txt2">
<input type="text" name="txt3" #input3>
<input type="text" name="txt4">
<input type="text" name="txt5">
<input type="text" name="txt6">
</div>
<button (click)="selectSample()">select</button>`
})
export class SamplesComponent {
@ViewChild('input3') input3:ElementRef;
constructor(private _renderer : Renderer) {}
public selectSample() {
//as per Eric's suggestion
this._renderer.invokeElementMethod(this.input3.nativeElement, 'focus', []);
}
}
Here's a Directive implementation, per Eric's suggestion:
@Directive({selector: 'input'})
export class MyInput {
constructor(private _elRef:ElementRef, private _renderer:Renderer) {}
focusIf(attrValue:string) {
console.log(this._elRef.nativeElement.getAttribute('name'))
if(this._elRef.nativeElement.getAttribute('name') === attrValue) {
this._renderer.invokeElementMethod(this._elRef.nativeElement, 'focus', []);
return true;
}
return false;
}
}
@Component({
selector: 'my-app',
directives: [MyInput],
template: `<div>
<input type="text" name="txt1">
<input type="text" name="txt2">
<input type="text" name="txt3">
<input type="text" name="txt4">
<input type="text" name="txt5">
<input type="text" name="txt6">
</div>
<button (click)="selectSample()">click</button>`
})
export class AppComponent {
@ViewChildren(MyInput) inputs;
constructor() { console.clear(); }
selectSample() {
this.inputs.toArray().some(myInput =>
myInput.focusIf('txt3'));
}
}
Plunker
I like the directive approach, because we don't need to add #input
to the HTML, and the directive knows how to focus itself.
I used Array.some()
just to be slightly more efficient.
My approach would be to rely on a Directive and its selector, to remove the necessity of iterating over an array, and to avoid the local variables (I don't like the idea of having too many of them on my view), as Mark mentioned.
I'm assuming that the user always want only one and it's hardcoded, which is enough for the case the user asked about. Having a dynamic element to focus would defeat this approach.
The directive
@Directive({
selector : 'input[type=text][name=txt3]'
})
class Input {
constructor(public renderer: Renderer, public elementRef: ElementRef) {}
focusMe() {
this.renderer.invokeElementMethod(this.elementRef.nativeElement, 'focus', []);
}
}
The component would be basically the same in each answer
export class App {
@ViewChild(Input) input: Input;
selectSample() {
this.input.focusMe();
}
}
Here's the plnkr.