Reputation: 14166
I'm new to TypeScript, and frankly, I may be doing this wrong. But...I'm trying to create a "KeyUp Listener" for text-boxes that will "notify" when the user has stopped typing. However, when I try to register the class, I get the following error:
Exception: Call to Node module failed with error: Prerendering failed because of error: ReferenceError: HTMLElement is not defined
REGISTRATION:
// MODULES
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { UniversalModule } from 'angular2-universal';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
// COMPONENTS
import { AppComponent } from './components/app/app.component'
import { HeaderComponent } from './components/shared/components/shared-header.component';
import { SampleIndexComponent } from './components/samples/sample.index.component';
import { SampleFormComponent } from './components/samples/sample.form.component';
import { StatusFilterComponent } from './components/samples/filters/status-filter.component';
import { AuthorFilterComponent } from './components/samples/filters/author-filter.component';
// LISTENERS
import { TextboxKeyUpListener } from "./components/shared/services/textbox.keyup.listener";
@NgModule({
bootstrap: [ AppComponent ],
declarations: [
AppComponent,
HeaderComponent,
SampleIndexComponent,
StatusFilterComponent,
AuthorFilterComponent,
SampleFormComponent
],
imports: [
UniversalModule, // <-- Must be first import. This automatically imports BrowserModule, HttpModule, and JsonpModule too.
FormsModule,
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'samples', pathMatch: 'full' },
{ path: 'samples', component: SampleIndexComponent },
{ path: 'form', component: SampleFormComponent },
{ path: '**', redirectTo: 'samples' }
])
],
providers: [AuthorFilterNotifier, StatusFilterNotifier, TextboxKeyUpListener]
})
export class AppModule
{
constructor() { }
}
NOTIFIER LOOKS LIKE:
// MODULES
import { Injectable, Inject } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class TextboxKeyUpListener {
// CONSTRUCTORS
constructor(private textbox: HTMLInputElement)
{
this.init();
}
// PROPERTIES - private
private typingTimer: NodeJS.Timer;
private typingTimerInterval: number = 1000;
private notifyDoneTyping = new Subject<string>();
// PROPERTIES - public
public notifyDoneTyping$ = this.notifyDoneTyping.asObservable();
// METHODS - public
private keyUp(ev: KeyboardEvent)
{
global.clearTimeout(this.typingTimer);
if(this.textbox.value)
this.typingTimer = global.setTimeout(this.notify, this.typingTimerInterval);
}
// METHODS - private
private init()
{
this.textbox.onkeyup = this.keyUp;
}
private notify()
{
this.notifyDoneTyping.next(this.textbox.value);
console.log("Done Typing")
}
}
Upvotes: 8
Views: 20836
Reputation: 4219
Maybe this is actually an eslint
and not a typescript
error.
For me it solved completely by adding browser
to the list of environments on .eslintrc.js
.
{
...
env: {
...
browser: true,
...
},
...
}
Upvotes: 8
Reputation: 17752
Some time ago I had a problem in having Typescript recognize some basic DOM classes, which has been solved adding
"lib": [
"es2016",
"dom"
]
to tsconfig.json file
I am not sure this can help your case, but it may be worth trying
==========================================================================
ADDITIONAL THOUGHTS TRIGGERED BY THE COMMENTS CHAIN - NOT RELATED TO THE ORIGINAL QUESTION
Use of debounce Rx operator to signal end-of-typing
If you need to signal end of typing in a simple and elegant way, you may want to consider to use Rx and the debounce
operator. The idea is to create an Observable out of the event stream coming from the Front End element (in your case the Input element I guess) and use debounce
to have an event emitted if no new value has been received from the input stream within a specified amount of time. You can look at these links for more details (What does RxJS.Observable debounce do?, https://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html) - many more examples are available online
Communication among components
I understand you have 2 components that need to communicate. Specifically the "listener" needs to tell the "other component" that typing is finished.
If the "other component" always contains the "listener" you may use @Output
to define output events that the "listener" can emit and the "other component" can listen to.
If the "listener" is not contained by the "other component", then the use of a service to communicate can be considered even if you have to also consider that services are Singletons (at least within their scope). Being a Singleton means that if you have more than one Input field you want to listen to for end-of-typing, than you need to figure out how to map the Singleton service with the many Inputs.
In case the UI is complex, you can consider to use a central store as per redux pattern (redux store pattern is available in Angular through https://github.com/ngrx/store or https://github.com/angular-redux/store - this is an interesting link that explains pros and cons of a redux-store based architecture)
Upvotes: 8