Reputation: 233
I need to set focus and open keyboard after page loads or modal with input is shown.
Simple .focus() works in Android and also in iPad in landscape mode. However in portrait mode and on iPhone focus is set but keyboard not shown.
I tried also solution with adding and focusing on additional element, but it doesn't work with Angular. (IOS show keyboard on input focus)
@ViewChild('searchBarInput') searchBarInput: ElementRef;
ngAfterViewInit(): void {
setTimeout(()=> {
this.searchBarInput.nativeElement.focus();
this.searchBarInput.nativeElement.click();
},180);
}
test application: https://inputfocus.vercel.app/
expectation is that after page is loaded and focus set, user can start typing. It is simplified version - I need this on modal, but behaviour on iOS is similar
Upvotes: 3
Views: 9667
Reputation: 1
first time you need to create function like this, so can be reusable
focusTextInput: function(el) {
var __tempEl__ = document.createElement('input');
__tempEl__.style.position = 'relative';
__tempEl__.style.top = el.offsetTop + 'px';
__tempEl__.style.left = el.offsetLeft + 'px';
__tempEl__.style.height = 0 + '!important';
__tempEl__.style.opacity = 0;
el.after(__tempEl__);
__tempEl__.focus()
setTimeout(() => {
el.focus()
el.click()
__tempEl__.remove()
}, 50);
},
and then call the function from wherever you want
var el = document.getElementById("body-height")
// make sure you have id for the input that need to focused
focusTextInput(el);
Upvotes: 0
Reputation: 1295
Based on your answer, I abstracted the code into a directive so it's clearer and there's no need to handle events:
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[appAutoFocus]'
})
export class AutoFocusDirective {
constructor(private elementRef: ElementRef) {
// Create non-visible temporary input element and focus it
const tmpElement = document.createElement('input');
tmpElement.style.width = '0';
tmpElement.style.height = '0';
tmpElement.style.margin = '0';
tmpElement.style.padding = '0';
tmpElement.style.border = '0';
tmpElement.style.opacity = '0';
document.body.appendChild(tmpElement);
tmpElement.focus();
setTimeout(() => {
// Focus the main (input) element, thus opening iOS keyboard
this.elementRef.nativeElement.focus();
document.body.removeChild(tmpElement);
}, 0);
}
}
Just use it in your input element:
<input type="text" appAutoFocus>
Upvotes: 1
Reputation: 233
I think I found the solution. on iOS (iphone) and iPad portrait mode, focus() needs to be triggered by user action. So we need to set this immediately after use clicks button showing modal or new div with target input field.
We can create this new field automatically, set focus, and remove it after moving focus to target field.
On button click we need to create temporary input, append to existing container (close to our input) and focus on it.
btnClicked() {
this.showModal = true;
this.searchBar = this.renderer2.selectRootElement('#searchBar', true);
// 2nd argument preserves existing content
// setting helper field and focusing on it
this.inputHelper = this.renderer2.createElement('input');
this.renderer2.appendChild(this.searchBar, this.inputHelper);
this.inputHelper.focus();
let event = new KeyboardEvent('touchstart',{'bubbles':true});
this.searchBarButton.nativeElement.dispatchEvent(event);
}
after modal/target input is shown, we move focus and remove temporary one:
initiateKeyboard() {
setTimeout(()=> {
this.searchBarInput.nativeElement.focus();
this.renderer2.removeChild(this.searchBar, this.inputHelper);
},180);
}
and template:
<div id="searchBar">
<input type="button" class="button is-link is-light" value="Search" (click)="btnClicked()" (touchstart)="initiateKeyboard()" #searchBarButton>
</div>
You just need to remember that iPhone may zoom screen, so you need to adjust parameters of temporary input.
working solution: https://inputfocus.vercel.app/
Upvotes: 4