ngx-material-keyboard/core

How to bind to text input field

Closed this issue · 12 comments

Hi, I'm using the virtual keyboard and its a great one. I need to show the keyboard on a button click next to input field instead of showing when input is on focus. Used the service to open the keyboard but how can I capture the value entered through keyboard into the input field?
This is the html
`


<input type="text" name="inpOne" ngControl="inpOnee" [(ngModel)]="inpOneModel"/><button (click)="openKeyboard(inpOnee)" type="button">Open keyboard

`

This is the ts code
openKeyboard(inp):void{ if(this.matKeyboardService.isOpened){ this.matKeyboardService.dismiss(); } else{ this.matKeyboardService.open("US International"); } }
How to pass the ngControl as keyboardconfig to the open() function of service?

You can use ngModel to observe the current input.

@davidenke hi, I think you didn't understand me. I mean how to capture the value entered by virtual keyboard into the input field by using the service.
When passed a formcontrol as ngControl in keyboardConfig, it's showing error as
"Argument of type '{ ngControl: AbstractControl; }' is not assignable to parameter of type 'MatKeyboardConfig'.
Types of property 'ngControl' are incompatible.
Type 'AbstractControl' is not assignable to type 'NgControl'.
Property 'name' is missing in type 'AbstractControl'."

Okay, you want to bind a custom control to a manually opened keyboard.

I'll look at it...

Yes exactly. I was following the docs and found the open() function of MatKeyboardService. I'm stuck at sending MatKeyboardConfig as parameter to open() function. MatKeyboardConfig has an ngControl property. What should be passed to it? I have a FormGroup with a formControlName.

Basically it's like the directive binds the keyboard to an input:

You open the keyboard (without ngControl in the config) and receive a reference.

const keyboardRef: MatKeyboardRef<MatKeyboardComponent> = this._keyboardService.open(locale, { ... });

Then you set the input instance (ElementRef) and attach the control (NgControl, e.g. NgModel):

// reference the input element
keyboardRef.instance.setInputInstance(elementRefOfTheInput);

// set control
keyboardRef.instance.attachControl(controlOfTheInput);

Then you've bound the keyboard inputs on the model.

I'm adding a demo right now, you'll see it in the source of the AppComponent (openAttachedKeyboard),

Thank you very much @davidenke. It works perfectly. I actually searched and experimented a lot for this feature. And thank you for creating this awesome plugin.

@codersree - any chance you could share your src that accomplished this?

Looking to do the same thing but with an type provided by the Ionic Framework. Currently have the keyboard displaying my custom key layout but can't quite get it to bind to the input properly.

Heres a few bits of my src:

`
@ViewChild('emailInput') userEmailInput : any;

constructor(public navCtrl: NavController,
private view: ViewController,
public navParams: NavParams,
private renderer: Renderer,
private keyboardService: MatKeyboardService,
@optional() @self() private _control?: NgControl
) {
}

closeModal() {
this.view.dismiss();
//this.keyboard.show();
}

ionViewDidLoad() {
console.log('ionViewDidLoad ModalEmailAddressPage');

setTimeout(() => {
  //this.userEmailInput.nativeElement.focus();
  const keyboardRef: MatKeyboardRef<MatKeyboardComponent> = this.keyboardService.open("CPlayout");

  this.keyboardService.open("CPlayout"); 
  keyboardRef.instance.setInputInstance(this.userEmailInput);
  
  keyboardRef.instance.attachControl(this._control.control);
},150);

    <ion-input #emailInput placeholder="Enter your email..." autofocus="true"> 
            <!-- <input #emailInput autocomplete="off" type="text" id="email" [matKeyboard]="'CPlayout'" class="rectangle-input"/> -->
    </ion-input>
  </div>

`
Seeing this error:

TypeError: Cannot read property 'control' of null
at http://localhost:8100/build/1.js:177:63
at t.invokeTask (http://localhost:8100/build/polyfills.js:3:15660)
at Object.onInvokeTask (http://localhost:8100/build/vendor.js:5125:33)
at t.invokeTask (http://localhost:8100/build/polyfills.js:3:15581)
at r.runTask (http://localhost:8100/build/polyfills.js:3:10834)
at e.invokeTask (http://localhost:8100/build/polyfills.js:3:16794)
at i.isUsingGlobalCallback.invoke (http://localhost:8100/build/polyfills.js:3:16682)
at n (http://localhost:8100/build/polyfills.js:3:61)

@CPMikeAmato - These are the relevant piece of code

export class AddMessageComponent implements OnInit {
	private _keyboardRef: MatKeyboardRef<MatKeyboardComponent>;
	
	@ViewChild('mesOne', { read: ElementRef })
	private _attachToElementMesOne: ElementRef;
	 @ViewChild('mesOne', { read: NgModel })
	private _attachToControlMesOne: NgControl;

        keyboard: string = 'US International';
        constructor(
		private matKeyboardService: MatKeyboardService,
		private eRef: ElementRef
	) { }

        showKeyboard(option, locale):void{
		let el: ElementRef;
		let control: AbstractControl;
		el = this._attachToElementMesOne;
		control = this._attachToControlMesOne.control;
                this._keyboardRef = this.matKeyboardService.open(locale,{});
		this._keyboardRef.instance.setInputInstance(el);
    	        this._keyboardRef.instance.attachControl(control);
        }
}

This is the input

<input #mesOne [(ngModel)]="message.mesOne" name="inpFirstRow">
<button (click)="showKeyboard(1,keyboard)"></button>

Thanks @codersree - going to mess around with this a bit and see if I can get this working on my side. Appreciate your help! Cheers xx

Managed to get the keyboard up and visible but now seeing an issue on the Keyboard Javascript code. This is what I'm seeing:

TypeError: Cannot read property 'slice' of undefined
at MatKeyboardKeyComponent.replaceSelectedText
(http://localhost:8100/build/vendor.js:93888:30)
at MatKeyboardKeyComponent.onClick (http://localhost:8100/build/vendor.js:93864:18)
at Object.eval [as handleEvent]
(ng:///MatKeyboardModule/MatKeyboardKeyComponent.ngfactory.js:35:27)
at handleEvent (http://localhost:8100/build/vendor.js:13963:155)
at callWithDebugContext (http://localhost:8100/build/vendor.js:15472:42)
at Object.debugHandleEvent [as handleEvent] (http://localhost:8100/build/vendor.js:15059:12)
at dispatchEvent (http://localhost:8100/build/vendor.js:10378:25)
at http://localhost:8100/build/vendor.js:11003:38
at HTMLButtonElement. (http://localhost:8100/build/vendor.js:44060:53)
at t.invokeTask (http://localhost:8100/build/polyfills.js:3:15660)

Going to mess around with the replaceSelectedText function and see if I can fix it up. Would appreciate any input if you ran into this issue too @codersree 👍

In case someone else views this thread, I managed to fix this up with the following code in the replaceSelectedText function:

if (!value || !value.length) { this.inputValue = [headPart, char, endPart].join('');
return; }

TLDR: You can't splice an undefined String.

I'm stuck with this in Ionic 4 and it's ion-input fields. Typing with the virtual keyboard concatenates the new value with the previous value.