@@ -204,6 +204,17 @@ export class TextfieldBase extends ManageHelpText(
204204 return this . inputElement ;
205205 }
206206
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+
207218 /**
208219 * Sets the start and end positions of the current selection.
209220 *
@@ -316,10 +327,6 @@ export class TextfieldBase extends ManageHelpText(
316327 pattern=${ ifDefined ( this . pattern ) }
317328 placeholder=${ this . placeholder }
318329 .value=${ this . displayValue }
319- @change=${ this . handleChange }
320- @input=${ this . handleInput }
321- @focus=${ this . onFocus }
322- @blur=${ this . onBlur }
323330 ?disabled=${ this . disabled }
324331 ?required=${ this . required }
325332 ?readonly=${ this . readonly }
@@ -351,10 +358,6 @@ export class TextfieldBase extends ManageHelpText(
351358 pattern=${ ifDefined ( this . pattern ) }
352359 placeholder=${ this . placeholder }
353360 .value=${ live ( this . displayValue ) }
354- @change=${ this . handleChange }
355- @input=${ this . handleInput }
356- @focus=${ this . onFocus }
357- @blur=${ this . onBlur }
358361 ?disabled=${ this . disabled }
359362 ?required=${ this . required }
360363 ?readonly=${ this . readonly }
@@ -389,6 +392,54 @@ export class TextfieldBase extends ManageHelpText(
389392 super . update ( changedProperties ) ;
390393 }
391394
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+
392443 public checkValidity ( ) : boolean {
393444 let validity = this . inputElement . checkValidity ( ) ;
394445 if ( this . required || ( this . value && this . pattern ) ) {
@@ -413,6 +464,9 @@ export class TextfieldBase extends ManageHelpText(
413464 * @slot negative-help-text - negative help text to associate to your form element when `invalid`
414465 */
415466export class Textfield extends TextfieldBase {
467+ @query ( '#form' )
468+ public form ! : HTMLFormElement ;
469+
416470 @property ( { type : String } )
417471 public override set value ( value : string ) {
418472 if ( value === this . value ) {
@@ -428,4 +482,46 @@ export class Textfield extends TextfieldBase {
428482 }
429483
430484 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+ }
431527}
0 commit comments