Coder Social home page Coder Social logo

rx_command's Introduction

RxCommand

RxCommand is an Reactive Extensions (Rx) based abstraction for event handlers. It is based on ReactiveCommand for the ReactiveUI framework. It makes heavy use of the RxDart package.

PRs are always welcome ;-)

If you don't know Rx think of it as Dart Streams on steroids. RxCommand capsules a given handler function that can then be executed by its execute method. The result of this method is then published through its results Observable (Observable wrap Dart Streams). Additionally it offers Observables for it's current execution state, if the command can be executed and for all possibly thrown exceptions during command execution.

A very simple example

final command = RxCommand.createSync3<int, String>((myInt) => "$myInt");

command.results.listen((s) => print(s)); // Setup the listener that now waits for events, not doing anything

// Somwhere else
command.execute(10); // the listener will print "10"

Getting Started

Add to your pubspec.yaml dependencies to rxdartand rx_command. (As long as the package is not published to Dart Packages please see the dependency entry of the sample App)

An RxCommand is a generic class of type RxCommand<TParam, TRESULT> where TPARAM is the type of data that is passed when calling execute and TResult denotes the return type of the handler function. To signal that a handler doesn't take a parameter or returns a Null value.

An example of the declaration from the included sample App

RxCommand<String,List<WeatherEntry>>  updateWeatherCommand;
RxCommand<bool,bool>  switchChangedCommand;

updateWeatherCommand expects a handler that takes a String as parameter and returns a List<WeatherEntry>. switchChangedCommand expects and returns a bool value

Creating RxCommands

For the different variations of possible handler methods RxCommand offers several factory methods for synchronous and asynchronous handlers. Due to the limitation that Dart doesn't allow method overloading they are numbered and look like this.

  /// Creates  a RxCommand for a synchronous handler function with no parameter and no return type 
  /// `action`: handler function
  /// `canExecute` : observable that can bve used to enable/diable the command based on some other state change
  /// if omitted the command can be executed always except it's already executing
  static RxCommand<Null, Null> createSync(Action action,[Observable<bool> canExecute])

The sample App contains a Switch widget that enables/disables the update command. The switch itself is bound to the switchChangedCommand that's result is then used as canExcecute of the updateWeatherCommand:

switchChangedCommand = RxCommand.createSync3<bool,bool>((b)=>b);

// We pass the result of switchChangedCommand as canExecute Observable to the upDateWeatherCommand
updateWeatherCommand = RxCommand.createAsync3<String,List<WeatherEntry>>(update,switchChangedCommand.results);

As the Update Button's building is based on a StreamBuilderthat listens on the canExecute Observable of the updateWeatherCommand the buttons enabled/disabled state gets automatically updated when the Switch's state changes

Using RxCommands

RxCommand is typically used in a ViewModel of a Page, which is made accessible to the Widgets via an InheritedWidget. Its executemethod can then directly be assigned as event handler of the Widgets.

The result of the command is best used with a StreamBuilder or inside a StatefulWidget.

By subscribing (listening) to the isExecuting property of a RxCommand you can react on any execution state change of the command. E.g. show a spinner while the command is running.

By subscribing to the canExecute property of a RxCommand you can react on any state change of the executability of the command.

Disposing subscriptions (listeners)

When subscribing to an Observable with .listen you should store the returned StreamSubscription and call .cancel on it if you want to cancel this subscription to a later point or if the object where the subscription is made is getting destroyed to avoid memory leaks. RxCommand has a dispose function that will cancel all active subscriptions on its observables. Calling disposebefore a command gets out of scope is a good practise.

Exploring the sample App

The best way to understand how RxCommand is used is to look at the supplied sample app which is a simple app that queries a REST API for weather data.

The ViewModel

It follow the MVVM design pattern so all business logic is bundled in the WeatherViewModel class in weather_viewmodel.dart.

It is made accessible to the Widgets by using an InheritedWidget which is defined in main.dart and returns and instance of WeatherViewModelwhen used like TheViewModel.of(context)

The view model publishes two commands

  • updateWeatherCommand which makes a call to the weather API and filters the result based on a string that is passed to execute. Its result will be bound to a StreamBuilderin your View.
  • switchChangedCommand which will be bound to a Switch widget to enable/disable the `updateWeatherCommand.

The View

main.dart creates the ViewModel and places it at the very base of the app`s widget tree.

homepage.dart creates a Column with a

  • TextField where you can enter a filter text which binds to the view models onFilterEntryChanged handler.

  • a middle block which can either be a ListView (WeatherListView) or a busy spinner. It is created by a StreamBuilder which listens to
    TheViewModel.of(context).updateWeatherCommand.isExecuting

  • A row with the Update Button and a Switch that toggles if an update should be possible or not by calling TheViewModel.of(context).switchChangedCommand.execute). To change the enabled state of the button the button is build by a StreamBuilder that listens to the TheViewModel.of(context).updateWeatherCommand.canExecute

listview.dart implements WeatherListView which consists again of a StreamBuilder which updates automatically by listening on TheViewModel.of(context).updateWeatherCommand.results

rx_command's People

Contributors

escamoteur avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.