Skip to content
This repository has been archived by the owner on Apr 2, 2018. It is now read-only.

Prevent keyboard from hiding #81

Closed
buunguyen opened this issue Apr 14, 2015 · 14 comments
Closed

Prevent keyboard from hiding #81

buunguyen opened this issue Apr 14, 2015 · 14 comments

Comments

@buunguyen
Copy link

I'm building an app where I want the keyboard to stay open even after the input loses focus.

After reading posts on Ionic forum and StackOverflow, I tried to refocus on the text input after it loses focus. However, the input only gets focused in desktop browsers, not Safari iOS. It looks like iOS ignores calls to focus(), with or without wrapping in a timeout. This is what I tried:

.directive('constantFocus', function($timeout){
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element[0].addEventListener('focusout', function(e) {
        $timeout(function() {element[0].focus();})
      });
    }
  };
})
<textarea constant-focus></constant-focus>

So, there are really two questions:

  • Is there a way to make keyboard stay open without having to refocus programmatically?
  • If having to refocus, is there a way to make focus() work on Safari iOS?

Thanks!

@mlynch
Copy link
Contributor

mlynch commented Apr 14, 2015

Random idea: could try toggling autofocus on an input?

@buunguyen
Copy link
Author

Thanks. I just tried it, but the input still doesn't receive focus. Is it necessary (or possible) to hack the keyboard plugin to make this work? I haven't read the source but thought I should check first before sinking time on it.

@alvaromontoro
Copy link

I had a similar issue but in Android: the keyboard flashed because it got hidden when the input lost focus, and then reshown when the input regained focus.

After testing with different configurations, finally I found something that worked for me: triggering the click event, and then the focus event for the input element. I don't know if that will work on iOS, but it's worth a try. The code looks like this: $textbox.click().focus();

@tlancina
Copy link
Contributor

Make sure you have <preference name="KeyboardDisplayRequiresUserAction" value="false"/> in your config.xml if you want to call focus() on iOS.

https://cordova.apache.org/docs/en/4.0.0/guide_platforms_ios_config.md.html#iOS%20Configuration

@buunguyen
Copy link
Author

@tlancina awesome, setting that pref to false work. Thank you!

@edgebal
Copy link

edgebal commented Feb 7, 2017

As a post-mortem note (this issue's page keep appearing first on Google):

If you want to keep the keyboard open when user clicks a button (i.e on a "Send" or "Search" button), you should use (mousedown)="something(); $event.preventDefault()" on that button. This will prevent the input from losing focus and the keyboard closing.

This way was successfully tested on Ionic2.

@manishoswal
Copy link

@edgebal - The solution works on android. Do we need to do something else for ios?

@msio
Copy link

msio commented Apr 14, 2017

@edgebal is it working with WKWebView too ?
thanks

@RohinMohanadas
Copy link

@edgebal Thank you so much :) @manishoswal @msio777 tested in iOS and seems to be working fine 👍

@larssn
Copy link

larssn commented Jul 19, 2017

@edgebal It works, but it seems to break some underlying native functionality. On Android I'm seeing the textarea not being cleared correctly, and on iOS spelling suggestions become glitchy.

Edit: touchend is an alternative event, but it has the same problems I mentioned.

@chrisjpalmer
Copy link

chrisjpalmer commented Jul 31, 2017

Button within a slides control
These are the lengths I had to go to in order to stop the keyboard from hiding.

export class CommentsComponent {

  @ViewChild('sendButton') sendButton:Button;

  constructor() {
    
  }

  ngAfterViewInit() {
    let el = this.sendButton._elementRef.nativeElement;
    el.addEventListener('click', (event) => {
      this.stopBubble(event);
    });
    el.addEventListener('mousedown', (event) => {
      this.stopBubble(event);
    });
    el.addEventListener('touchdown', (event) => {
      this.stopBubble(event);
    });
    el.addEventListener('touchmove', (event) => {
      this.stopBubble(event);
    });
    el.addEventListener('touchstart', (event) => {
      this.stopBubble(event);
    });
    el.addEventListener('touchend', (event) => { //Triggered by a phone
      this.stopBubble(event);
      this.sendPressed();
    });
    el.addEventListener('mouseup', (event) => { //Triggered by the browser
      this.sendPressed();
    });
  }

  stopBubble(event) {
    event.preventDefault(); 
    event.stopPropagation(); //Stops event bubbling
  }

  sendPressed() {
    //... send message routine
  }

}

Why??
If your button is embedded in a slides control, the swiper receives all click, mouse and touch, events. This is so that when you swipe the slides, it can automatically blur any focussed control to tidy up the view for the next transition. This works to your detriment however when you want to implement a send button and have the keyboard remain where it is.

The solution is to bind to the native events of the button and call event.stopPropagation(). This method prevents a phenomenon called 'bubbling'. Bubbling is where the click event of a child DOM element gets sent to its parent. By disabling bubbling with the event.stopPropagation() method, you can prevent the slides control from ever receiving the mouse down message.

I tried doing this with angular event bindings like normal but I was unsuccessful. I resorted to a more direct method of binding direct to the control.

Would be great to see if we can add a directive to buttons embedded in slides which can prevent the slide from responding to the events.

@numerized
Copy link

numerized commented Oct 22, 2017

WOW @chrisjpalmer !!!! Thanks A LOT ! I'm using it in a chat and it works like a charm !
This should be a parameter of ionic-plugin-keyboard.

@webkoils
Copy link

webkoils commented Oct 24, 2017

Here is a directive I made for suppressing events on a button based on @chrisjpalmer

import {  Directive, ElementRef, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';

@Directive({
	selector: '[suppressEvents]',
	inputs: ["suppressEvents"],
	outputs: ["onClick"]
})
export class SuppressEvents implements OnChanges {

	suppressEvents: string | string[];

	constructor(public element: ElementRef) {

	}

	ngOnChanges(changes: SimpleChanges) {
		if (changes.suppressEvents) {
			if (changes.suppressEvents.firstChange) {
				console.log(this.suppressEvents);
				let el = this.element.nativeElement;

				if (this.suppressEvents == "all" || this.suppressEvents == null) {
					this.suppressEvents = ["click", "mousedown", "touchdown", "touchmove", "touchstart"];

				} else if (typeof this.suppressEvents == "string") {
					this.suppressEvents = [this.suppressEvents];
				} else if (typeof this.suppressEvents == "object" && !Array.isArray(this.suppressEvents)) {
					let r: string[] = [];
					for (let e of this.suppressEvents) {
						r.push(e);
					}
					this.suppressEvents = r;
				}
				for (let evName of this.suppressEvents) {
					el.addEventListener(evName, (event) => {
						this.stopBubble(event);
					});
				}



				el.addEventListener('touchend', (event) => { //Triggered by a phone
					this.stopBubble(event);
					this.onClick.emit(event);
				});
				el.addEventListener('mouseup', (event) => { //Triggered by the browser
					this.onClick.emit(event);
				});
			}
		}
	}

	stopBubble(event) {
		event.preventDefault();
		event.stopPropagation(); //Stops event bubbling
	}

	onClick: any = new EventEmitter();
}

@chrisjpalmer
Copy link

Hi @johnthackstonanderson thanks so much. Thats a great innovation. I will give this a try a bit later.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests