Plain-Old Events

Consider, for instance, a click handler that colors the border of the clicked element a brilliant orange.

events/simple.dart
 
var​ el = document.query(​'#clicky-box'​);
 
el.onClick.listen((event) {
 
el.style.border = ​"5px solid orange"​;
 
});

Here, we define an anonymous function to be invoked when a click event occurs. This is slightly more compact than the equivalent JavaScript code: el.addEventListener(’click’, callback_fn). But there is a subtle difference in Dart’s syntax: the lack of the word “add.”

In Dart, the onClick property (like all “on” properties) is a stream. That is, the onClick property represents a stream of click events. Every time a DOM element is clicked, the corresponding event is added to the onClick stream and any listeners that are subscribed to receive those events will be invoked.

The difference between a list of callbacks and a stream may seem minor (and really there is not that much of a difference). The power of streams comes from their ubiquity in Dart. Anytime there is an event or asynchronous action in Dart, you can find a stream of events or data. There is no need to remember how asynchronous actions behave in the DOM versus how they behave when reading a file—they are the same thing.

In fact, we saw an example of event streams back in Chapter 1, Project: Your First Dart Application. The onLoad Ajax stream looks like this:

events/http_request.dart
 
req.onLoad.listen((event) {
 
var​ list = JSON.decode(req.responseText);
 
container.innerHtml = graphicNovelsTemplate(list);
 
});

It is this kind of organization and consistency that puts the “structured” in Dart’s structured code for the modern Web.

In Design Pattern parlance, streams implement a Publish/Subscribe, or pubsub, pattern. The various “on” properties on DOM elements (or anything that describes a stream in Dart) publishes a stream of events. Anything can subscribe to the published stream, via listen, to get notifications of asynchronous events.

Streams in Dart are almost always read-only. That is, they implement the pubsub pattern and nothing else. Events and data are added to streams by stream controllers such as DOM elements. When it makes sense to allow programmatic generation of stream events, Dart supports helper methods. In the case of DOM elements, for instance, the usual dispatchEvent DOM method is supported:

 
el.dispatchEvent(​new​ Event(​'click'​));

Or, even better, use the built-in click in Element:

 
el.click();

Since streams are pubsub patterns by another name, the listen method generates a subscription. To unsubscribe from a stream, call the cancel method on the subscription:

 
var​ subscription = el.onClick.listen((event) {
 
el.style.border = ​"50px dotted purple"​;
 
});
 
// Do some stuff, then...
 
subscription.cancel();

Subscriptions are also a place to add error handling with onError:

 
var​ subscription = el.onClick.listen((event) {
 
// Normal click handling here...
 
});
 
subscription.onError((error) {
 
// Add the error to the list of errors...
 
errors.add(error);
 
});

One of the cooler features of Dart streams is that they are iterable. This means that they implement Iterable methods like distinct, takeWhile, and even where:

 
// Only count clicks where the Control key is also held down:
 
el.onClick.
 
where((e)=> e.ctrlKey).
 
listen((event) {
 
clicked++;
 
});

There is a lot of power in Dart streams, so let’s spend some time in the next section to build our own.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.78.102