frappe 0.4.0+6

  • Readme
  • Changelog
  • Installing
  • 10

Frappé #

Build Status Coverage Status

A functional reactive programming library for Dart. Frappé extends the functionality of Dart's streams, and introduces new concepts like properties/signals.

Why FRP? #

UI applications today are highly interactive and data driven. User input can trigger updates to the DOM, playing animations, invoking network requests, and modifying application state. Using the traditional form of event callbacks and modifying state variables can quickly become difficult to write and maintain.

Functional reactive programming (FRP) makes it clearer to define user and system events that cause state changes. For instance, it's easy to define "when a user performs A, do X and Y, then output Z."

When writing reactive code, you'll find yourself focusing more on the dependencies between events for business logic, and less time on their implementation details.

Example #

Lets write an auto-complete movie widget with Frappé. The widget has an input field for the movie name, and a list element that displays movies that most closely match the user's input. A working version can be found here.

var searchInput = document.querySelector("#searchInput");
var suggestionsElement = document.querySelector("#suggestions");

var onInput = new EventStream(searchInput.onInput)
    .debounce(new Duration(milliseconds: 250)) // Limit the number of network requests
    .map((event) => // Get the text from the input field
    .distinct(); // Ignore duplicate events with the same text

// Make a network request to get the list of movie suggestions. Because requests
// are asynchronous, they can complete out of order. Use `flatMapLatest` to only
// respond to request for the last text change.
var suggestions = onInput.flatMapLatest((input) => querySuggestions(input));

suggestions.listen((movies) =>
        ..addAll( => new LIElement()..text = movie));

// Show "Searching ..." feedback while the request is pending
var isPending = searchInput.onInput.isWaitingOn(suggestions);
isPending.where((value) => value).listen((_) {
      ..add(new DivElement()..text = "Searching ...");

Future<List<String>> querySuggestions(String input) {
  // Query some API that returns suggestions for 'input'


You can explore the full API here.

Reactable #

The Reactable class extends from Stream and is inherited by EventStream and Property. Because these classes extend from Dart's Stream, you can pass them directly to other APIs that expect a Stream.

EventStream #

An EventStream represents a series of discrete events. They're like a Stream in Dart, but extends its functionality with the methods found on Reactable.

Event streams can be created from a property via Property.asEventStream(), or through one of its constructor methods. If an event stream is created from a property, its first event will be the property's current value.

An EventStream will inherit the behavior of the stream from which it originated. So if an event stream was created from a broadcast stream, it can support multiple subscriptions. Likewise, if an event stream was created from a single-subscription stream, only one subscription can be added to it. Take a look at the article on single-subscription streams vs broadcast streams to learn more about their different behaviors.

Property #

A Property represents a value that changes over time. They're similar to event streams, but they remember their current value. Whenever a subscription is added to a property, it will receive the property's current value as its first event.

Properties can be created through one of its constructors, or from an event stream via EventStream.asProperty(). Depending on how the property was created, it may or may not have a starting value. Separate methods are available for creating properties with an initial value, i.e. Property.fromStreamWithInitialValue() and EventStream.asPropertyWithInitialValue(). Properties can support having a null initial value, and is partly the motivation for having separate construction methods.

Internally, properties are implemented as broadcast streams and can receive multiple subscriptions.

If you were to model text input using properties and streams, the individual key strokes would be events, and the resulting text is a property.

Learning More #

Definitely take a look at the API documentation, and play around with some of the examples. It's also worth checking out BaconJS and RxJS. They're both mature FRP libraries, and offer some great resourses on the subject.

Running Tests #

Tests are run through the Grinder build task. This will run the Dart Analyzer, linter and unit tests.

  • Install grinder: pub global activate grinder
  • Run grinder: grind build

Features and bugs #

Please file feature requests and bugs at the issue tracker.

Contributing #

Take a look here on ways to contribute to Frappé.

Changelog #

Note: Patch versions that only include documentation changes are omitted.

0.4.0+5 (08/06/2015) #

  • Add better type annotations to suppress warnings in DDC. [#47]

0.4.0+3 (03/09/2015) #

  • Fix an issue where the stream returned by Property.asEventStream() would still behave like a property [#38]

0.4.0 (03/02/2015) #

  • Fix an issue where EventStreams wouldn't be the same type of stream as its source [#17]
  • Transformation methods on Property or EventStream now return the same type of Reactable
  • Add Reactable.concat()
  • Add Reactable.concatAll()
  • Add Reactable.doAction()
  • Add Reactable.mergeAll()
  • Add Reactable.sampleOn()
  • Add Reactable.sampleEachPeriod()
  • Add Reactable.selectFirst()
  • Add Reactable.startWith()
  • Add Reactable.startWithValues()
  • Add
  • Add EventStream.empty() constructor
  • Add EventStream.fromValue() constructor
  • Add EventStream.periodic() constructor
  • Bug fixes in Reactable.isWaitingOn()
  • Deprecate Reactable.asStream(), it's now Reactable.asEventStream()
  • Deprecate Property operator overrides, equals(), >, >=, <, <=, +, -, *, /
  • Property.and() and Property.or() can now accept any stream
  • Property.not() has been moved to Reactable
  • Remove type declerations for Reactable.scan()

0.3.2+1 (01/10/2015) #

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  frappe: ^0.4.0+6

2. Install it

You can install packages from the command line:

with pub:

$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:frappe/frappe.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

The package version is not analyzed, because it does not support Dart 2. Until this is resolved, the package will receive a health and maintenance score of 0.

Analysis issues and suggestions

Support Dart 2 in pubspec.yaml.

The SDK constraint in pubspec.yaml doesn't allow the Dart 2.0.0 release. For information about upgrading it to be Dart 2 compatible, please see


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.8.0