@@ -204,6 +204,17 @@ export class TextfieldBase extends ManageHelpText(
204
204
return this . inputElement ;
205
205
}
206
206
207
+ private _eventHandlers = {
208
+ input : this . handleInput . bind ( this ) ,
209
+ change : this . handleChange . bind ( this ) ,
210
+ focus : this . onFocus . bind ( this ) ,
211
+ blur : this . onBlur . bind ( this ) ,
212
+ } ;
213
+
214
+ protected _firstUpdateAfterConnected = false ;
215
+
216
+ protected abortController ?: AbortController ;
217
+
207
218
/**
208
219
* Sets the start and end positions of the current selection.
209
220
*
@@ -316,10 +327,6 @@ export class TextfieldBase extends ManageHelpText(
316
327
pattern=${ ifDefined ( this . pattern ) }
317
328
placeholder=${ this . placeholder }
318
329
.value=${ this . displayValue }
319
- @change=${ this . handleChange }
320
- @input=${ this . handleInput }
321
- @focus=${ this . onFocus }
322
- @blur=${ this . onBlur }
323
330
?disabled=${ this . disabled }
324
331
?required=${ this . required }
325
332
?readonly=${ this . readonly }
@@ -351,10 +358,6 @@ export class TextfieldBase extends ManageHelpText(
351
358
pattern=${ ifDefined ( this . pattern ) }
352
359
placeholder=${ this . placeholder }
353
360
.value=${ live ( this . displayValue ) }
354
- @change=${ this . handleChange }
355
- @input=${ this . handleInput }
356
- @focus=${ this . onFocus }
357
- @blur=${ this . onBlur }
358
361
?disabled=${ this . disabled }
359
362
?required=${ this . required }
360
363
?readonly=${ this . readonly }
@@ -389,6 +392,54 @@ export class TextfieldBase extends ManageHelpText(
389
392
super . update ( changedProperties ) ;
390
393
}
391
394
395
+ public override connectedCallback ( ) : void {
396
+ super . connectedCallback ( ) ;
397
+ this . _firstUpdateAfterConnected = true ;
398
+ this . requestUpdate ( ) ;
399
+ }
400
+
401
+ public override disconnectedCallback ( ) : void {
402
+ // Cleanup all event listeners and and remove input element from DOM
403
+ this . abortController ?. abort ( ) ;
404
+ super . disconnectedCallback ( ) ;
405
+ }
406
+
407
+ protected firstUpdateAfterConnected ( ) : void {
408
+ this . abortController = new AbortController ( ) ;
409
+ const { signal } = this . abortController ;
410
+
411
+ this . inputElement . addEventListener (
412
+ 'change' ,
413
+ this . _eventHandlers [ 'change' ] ,
414
+ { signal }
415
+ ) ;
416
+ this . inputElement . addEventListener (
417
+ 'input' ,
418
+ this . _eventHandlers [ 'input' ] ,
419
+ { signal }
420
+ ) ;
421
+ this . inputElement . addEventListener (
422
+ 'focus' ,
423
+ this . _eventHandlers [ 'focus' ] ,
424
+ { signal }
425
+ ) ;
426
+ this . inputElement . addEventListener (
427
+ 'blur' ,
428
+ this . _eventHandlers [ 'blur' ] as EventListener ,
429
+ { signal }
430
+ ) ;
431
+ }
432
+
433
+ protected override updated ( changedProperties : PropertyValues ) : void {
434
+ super . updated ( changedProperties ) ;
435
+ // Adding this here instead of firstUpdated because we want to make sure
436
+ // this is called again on the first update after a previous disconnect
437
+ if ( this . _firstUpdateAfterConnected ) {
438
+ this . _firstUpdateAfterConnected = false ;
439
+ this . firstUpdateAfterConnected ( ) ;
440
+ }
441
+ }
442
+
392
443
public checkValidity ( ) : boolean {
393
444
let validity = this . inputElement . checkValidity ( ) ;
394
445
if ( this . required || ( this . value && this . pattern ) ) {
@@ -413,6 +464,9 @@ export class TextfieldBase extends ManageHelpText(
413
464
* @slot negative-help-text - negative help text to associate to your form element when `invalid`
414
465
*/
415
466
export class Textfield extends TextfieldBase {
467
+ @query ( '#form' )
468
+ public form ! : HTMLFormElement ;
469
+
416
470
@property ( { type : String } )
417
471
public override set value ( value : string ) {
418
472
if ( value === this . value ) {
@@ -428,4 +482,46 @@ export class Textfield extends TextfieldBase {
428
482
}
429
483
430
484
protected override _value = '' ;
485
+
486
+ private handleSubmit ( event : Event ) : void {
487
+ event . preventDefault ( ) ;
488
+ this . dispatchEvent (
489
+ new Event ( 'submit' , {
490
+ cancelable : true ,
491
+ bubbles : true ,
492
+ } )
493
+ ) ;
494
+ }
495
+
496
+ protected override renderField ( ) : TemplateResult {
497
+ return html `
498
+ < form id ="form "> ${ super . renderField ( ) } </ form >
499
+ ` ;
500
+ }
501
+
502
+ public override connectedCallback ( ) : void {
503
+ super . connectedCallback ( ) ;
504
+ this . _firstUpdateAfterConnected = true ;
505
+ this . requestUpdate ( ) ;
506
+ }
507
+
508
+ public override disconnectedCallback ( ) : void {
509
+ // Cleanup form event listener and remove form element from DOM
510
+ this . form . removeEventListener ( 'submit' , this . handleSubmit . bind ( this ) ) ;
511
+ this . form . remove ( ) ;
512
+ super . disconnectedCallback ( ) ;
513
+ }
514
+
515
+ protected override firstUpdateAfterConnected ( ) : void {
516
+ super . firstUpdateAfterConnected ( ) ;
517
+ this . form . addEventListener ( 'submit' , this . handleSubmit . bind ( this ) ) ;
518
+ }
519
+
520
+ protected override updated ( changes : PropertyValues < this> ) : void {
521
+ super . updated ( changes ) ;
522
+ if ( this . _firstUpdateAfterConnected ) {
523
+ this . _firstUpdateAfterConnected = false ;
524
+ this . firstUpdateAfterConnected ( ) ;
525
+ }
526
+ }
431
527
}
0 commit comments