Angular Bloc Package

Pub build codecov Star on Github style: effective dart Flutter Website Awesome Flutter Flutter Samples License: MIT Discord Bloc Library


An Angular package that helps implement the BLoC pattern. Built to work with package:bloc.

Learn more at bloclibrary.dev!

Angular Components

BlocPipe is an Angular pipe which helps bind Bloc state changes to the presentation layer. BlocPipe handles rendering the html element in response to new states. BlocPipe is very similar to AsyncPipe but has a more simple API to reduce the amount of boilerplate code needed.

Cubit Usage

Lets take a look at how to use BlocPipe to hook up a CounterPage html template to a CounterCubit.

counter_cubit.dart

import 'package:bloc/bloc.dart';

class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
  void decrement() => emit(state — 1);
}

counter_page_component.dart

import 'package:angular/angular.dart';
import 'package:angular_bloc/angular_bloc.dart';

import './counter_cubit.dart';

@Component(
  selector: 'counter-page',
  templateUrl: 'counter_page_component.html',
  styleUrls: ['counter_page_component.css'],
  pipes: [BlocPipe],
)
class CounterPageComponent implements OnInit, OnDestroy {
  CounterCubit counterCubit;

  @override
  void ngOnInit() {
    counterCubit = CounterCubit();
  }

  @override
  void ngOnDestroy() {
    counterCubit.close();
  }
}

counter_page_component.html

<div class="counter-page-container">
  <h1>Counter App</h1>
  <h2>Current Count: {{ counterCubit | bloc }}</h2>
  <button class="counter-button" (click)="counterCubit.increment()">➕</button>
  <button class="counter-button" (click)="counterCubit.decrement()">➖</button>
</div>

Bloc Usage

Lets take a look at how to use BlocPipe to hook up a CounterPage html template to a CounterBloc.

counter_bloc.dart

import 'dart:async';
import 'package:bloc/bloc.dart';

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0);

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield state - 1;
        break;
      case CounterEvent.increment:
        yield state + 1;
        break;
    }
  }
}

counter_page_component.dart

import 'package:angular/angular.dart';
import 'package:angular_bloc/angular_bloc.dart';

import './counter_bloc.dart';

@Component(
  selector: 'counter-page',
  templateUrl: 'counter_page_component.html',
  styleUrls: ['counter_page_component.css'],
  pipes: [BlocPipe],
)
class CounterPageComponent implements OnInit, OnDestroy {
  CounterBloc counterBloc;

  @override
  void ngOnInit() {
    counterBloc = CounterBloc();
  }

  @override
  void ngOnDestroy() {
    counterBloc.close();
  }

  void increment() {
    counterBloc.add(CounterEvent.increment);
  }

  void decrement() {
    counterBloc.add(CounterEvent.decrement);
  }
}

counter_page_component.html

<div class="counter-page-container">
  <h1>Counter App</h1>
  <h2>Current Count: {{ counterBloc | bloc }}</h2>
  <button class="counter-button" (click)="increment()">+</button>
  <button class="counter-button" (click)="decrement()">-</button>
</div>

At this point we have successfully separated our presentational layer from our business logic layer!

Dart Versions

  • Dart 2: >= 2.6.0

Examples

  • Counter - a complete example of how to create a CounterBloc and hook it up to an AngularDart app.
  • Github Search - an example of how to create a Github Search Application using the bloc and angular_bloc packages.

Maintainers

Supporters

Libraries

angular_dart