When the JavaScript runtime in a browser executes application code written in JavaScript, it uses the techniques of events and event handling. When the browser accesses web pages from back-end servers and when the users interact with the browser, the JavaScript runtime publishes the DOM events. The application code handles the DOM events in the event handlers. The DOM event handlers are the entry points to developing web applications.1 Events and event handling are part of the programming model of JavaScript web application development.
AppRun application development uses the event publication and subscription (event pub-sub) pattern as the primary programming model. The AppRun programming model matches perfectly with the event-driven programming model of JavaScript. To develop AppRun applications, we need to connect the DOM events to the AppRun events. The AppRun events have two categories: global and local events. The global events are the events that are broadcast to all modules and components. The local events are the events that are broadcast and scoped only within the components.
This chapter demonstrates some of the commonly used DOM events, including a button click event, an input event, keyboard events, mouse events, a browser history event, and web workers. You will learn all the event-handling techniques necessary for your application development projects.
We will start with reviewing the concept of events.
Event Concept
There are two types of events: DOM events and AppRun events.
DOM Events
The JavaScript runtime in browsers uses DOM events . Browsers are multithreaded themselves. The browser code is running on multiple threads to interact with the operating system and the hardware to capture events. An event is a signal that something has happened.2 Examples include the user clicking a button, pressing a key, and moving the mouse; a system time ticker; network I/O; and so forth. The browser adds a message into the message queue of the JavaScript runtime. The message queue is like a to-do list. Therefore, it allows the JavaScript runtime to run on a single thread. The JavaScript runtime continually monitors the message queue. It picks up the messages one by one from the message queue and invokes the functions that are associated with the messages. It repeats the loop until the message queue is empty. The functions that the JavaScript runtime invokes upon events are the event listeners or event handlers. JavaScript programming mostly is creating DOM event handlers and registering them with DOM events.
AppRun Events
Figure 5-1 shows the AppRun architecture and breaks down the application logic. It also shows the interaction between the application code and AppRun. The application code is developed as event handlers and the view function piece by piece. There is no direct relationship between the event handlers and the view function. We rely on AppRun events to trigger the AppRun event lifecycle, which means we can publish an AppRun event and expect the DOM to be updated .
Connect the Events
Publishing the AppRun events in the DOM event handlers is a commonly used pattern in AppRun application development.
Global and Local Events
The AppRun Global Architecture and Global Event
The foo event in Listing 5-1 is a global event. We publish the foo event from the button’s onclick event handler by calling the app.run function (line 2 of Listing 5-1). The event is broadcast globally to all code modules.
The AppRun Component Architecture and Local Event
The bar event is a local event that is only scoped in the component in Listing 5-2. We publish the bar event from the button’s onclick event handler by calling the this.run function (line 4 of Listing 5-2).
Global Events in a Component
Clock Application
In the clock application (Listing 5-4), we use the system timer to publish an AppRun global event named #tick (line 9). The #tick event triggers the AppRun event lifecycle of ClockComponent to display the current time every second.
So far, you learned about AppRun events and the event lifecycle. Next, you will learn more about the various DOM events and learn how to use them in AppRun applications. All the example applications in the next sections are developed using the component architecture.
User Input
User input starts with the keyboard and mouse. Modern web browsers also support advanced technologies such as drag and drop and touch. They all follow the same event-driven programming model: when user input happens, the browsers publish DOM events. Our general approach to handle user input is to publish the AppRun events in the DOM event handlers to trigger the AppRun event lifecycle.
Click Events
The Click Event
The Hello World application shown in Listing 5-5 publishes the AppRun event input in the button’s onclick event handler (line 7). The AppRun event handler of the input event creates a new state using the value of the input box (line 10). The view function creates the virtual DOM using the new state (lines 4–8).
Input Event
The Input Event
The AppRun event handler in Listing 5-6 receives the DOM event as the function parameter. We can get the value of the input box from event.target (line 9). The value of the input box is synchronized with the state.
The Delayed Input Event
Next, we will develop a type-ahead application to demonstrate the delayed event handling along with the keyboard events.
Keyboard Events
TypeAhead Component
The TypeAhead component shown in Listing 5-8 has the majority of code to handle the DOM keyboard events of the text input control.
The search event is for taking the user’s input when the user is typing (lines 22–30). It has a delay of 200 milliseconds. The keydown event is for handling the Esc key, the up and down arrow keys, and the Enter key (lines 32–49).
Type-Ahead Application
The type-ahead application in Listing 5-9 has the U.S. states in an array (lines 3–12) and the search function for searching the states (lines 13–14). It also has an AppRun event input for updating the state (line 24). The main program uses the TypeAhead component (Listing 5-9) by setting the two callback functions for searching the options and for handling the selected item (lines 19–21).
So far, we have developed the TypeAhead component as a generic component and used it in an application for selecting U.S. states. You can use the application as an example to reuse the TypeAhead component in other applications.
Mouse Events
Float Action Button Application
The main program sets the initial location of the float action button (line 7). It also sets the callback function to publish the AppRun event, called action (line 8), which will record the number of times the button is clicked.
Float Action Button Component
The float action button component shown in Listing 5-11 tracks the button position in its state (lines 4–7). The position is applied to the button in the view function (line 8). It creates a <div> element and subscribes to its three DOM pointer events: pointerdown, pointermove, and pointerup. It is the same as using the DOM events: mousedown, mousemove, and mouseup. The DOM Pointer API is the unified API that incorporates more forms of input, including mouse, touchscreens, and pen input.
Brower History Event
Web browsers record and keep a history of the URLs that users visit. When the user enters a URL in the browser’s address bar, clicks a hyperlink in a web page, or clicks the back/forward button, the browser saves the corresponding URL in the browser history and publishes a DOM event: the popstate event.
A URL is the web address of web resources, such as web pages. Also, the URL can identify a specific location within the web pages. The location within the web pages is identified by a fragment identifier, which is anything in the URL after the # sign. We can navigate to different locations of web pages by changing this fragment identifier. Changing the fragment identifier does not make the browser navigate to other web pages, but it does create browser history entries and publish the popstate events. We can subscribe to the popstate event and use window.location.hash to retrieve the fragment identifier.
AppRun has built-in code that subscribes to the popstate event. AppRun parses the URL into the event parameters and publishes the # event. For example, if the browser address URL is http://.../#/a/b/c, AppRun publishes the # event as app.run('#', ['a', 'b', 'c']).
Handling Browser History
There are a few interesting points to explain in Listing 5-12. The view function displays the state to the <h1> element (line 5). The <input> element’s DOM event, the change event , is converted to the AppRun change event (line 6). The event handler for the # event sets the location hash as the current state (line 9). In the event handler of the change event, we take the user’s input and push it into the browser history as a new fragment identifier (lines 11–12). Notice the change event handler does not return anything. Therefore, the event lifecycle ends. However, because we pushed data into the browser history, the browser publishes the DOM popstate event. AppRun then converts it to the # event. We have another event lifecycle. The event handler for the # event returns the new state, which is displayed in the <h1> element.
The AppRun # event often is used as the main entry point of AppRun applications. It is also commonly used in single-page applications, which you will learn more about in Chapter 7.
Web Workers
Because the main JavaScript runtime inside web browsers executes application code in a single thread, it could slow down the user interface or even make it become unresponsive when the application code is computationally heavy and time-consuming. A web worker is a new JavaScript runtime with which we can spawn web workers to execute application code in the background. Web workers provide a way to create a multithreaded architecture in which the browser can execute multiple tasks at once. Web workers are often able to utilize multicore CPUs more effectively.
To allow multithreaded execution, the web workers do not have direct access to the DOM. The web page and the web workers communicate with each other by passing messages. The process of sending and processing messages again falls into the AppRun sweet spot. AppRun is an event engine that abstracts away the complexity of dispatching events and messages.
Web Page Using Web Worker
Web Worker
Although the counter calculation is not heavy-computational code, it demonstrates the architecture of using a web worker with AppRun.
Source Code and Examples
npm Scripts of This Chapter
Example | Script |
---|---|
The button click event (Listing 5-5) | npm run hello |
The input event (Listing 5-6) | npm run echo |
The delayed input event (Listing 5-7) | npm run echo-delayed |
npm run typeahead | |
npm run fab | |
The browser history events (Listing 5-12) | npm run echo-hash |
npm run worker |
Summary
JavaScript programming on the web platform is event-driven. From the system timer and user input to the browser history and web workers, we respond to various events, attach callbacks, and send messages. When developing AppRun applications, we mainly connect the DOM events to the AppRun events.
AppRun has an event engine that supports event publication and subscription. Associated with the event engine, it has state management and a DOM rendering engine. When AppRun events are published, AppRun not only invokes the event handlers but also manages the states and renders the DOM. We can publish an AppRun event and expect the web page to be updated.
By using AppRun events, code is well organized, modularized, and decoupled. It solves the problem that code is like spaghetti in the event-driven world.
The events discussed in this chapter are all synchronous events. We will introduce the asynchronous events in the next chapter.