interstate

Last updated:

0 purchases

interstate Image
interstate Images
Add to Cart

Description:

interstate

A library for managing state and communicating across dynamic forms and widget trees.
Features #
Widgets can pass events to other interstate widgets in the tree.
Widgets can query state from widgets below them in the tree.
Dynamically added widgets are automatically connected to the interstate.
Build dynamic forms without mirroring the structure in your data model.
Widgets in your form can manage their own states and children, without a higher level state object
to define structures.

Basic explainer #
This is not intended as a replacement for a more powerful state management solution, this is generally
useful when constructing forms that have interesting dynamic properties and or convoluted validation
scenarios.
When a new InterstateWidget attaches to the tree, it registers itself with the nearest ancestor
InterstateWidget. This is how we pass events through the tree.
EventHandlers define which event types any particular InterstateWidget cares about.
At the time of firing an event, we can decide how we want to broadcast the event.
The event is always sent to the local handler.

if the down flag is set to true: The event will be sent to every interstate widget below us in the tree.
if the up flag is set to true: The event will be sent to up the tree until the root InterstateWidget is reached.
if the span flag is set to true (with the up flag also set to true): The event will travel up the tree, and then back down any branch it encounters.

Getting started #
1. Depend on it #
Add this to your package's pubspec.yaml file:
dependencies:
interstate: '^1.0.0'
copied to clipboard
2. Install it
You can install packages from the command line:
$ pub get
..
copied to clipboard
Alternatively, your editor might support pub. Check the docs for your editor to learn more.
3. Import it
Now in your Dart code, you can use:
import 'package:interstate/interstate.dart';
copied to clipboard
Usage #
1. Define a state object #
class NestedTextFieldState extends Equatable {
final String text;
final String error;

const NestedTextFieldState({required this.text, this.error = ""});

NestedTextFieldState copyWith({String? text, String? error}) =>
NestedTextFieldState(text: text ?? this.text, error: error ?? this.error);

@override
List<Object?> get props => [text, error];
}
copied to clipboard
2. Define an interstate widget #
InterstateWidget<NestedTextFieldState>(
id: uniqueId,
widgetBuilder: (BuildContext context, NestedTextFieldState state, Widget? child, InterstateController<NestedTextFieldState> controller) {
return TextFormField(
initialValue: state.text,
decoration: InputDecoration(
errorText: state.error,
border: const OutlineInputBorder()
),
onChanged: (text) {
// We send a String as an event to the local controller
controller.send(text);
// Then we send a validation event up and down the widget tree
controller.send(EventValidate(), up: true, down: true);
},
onEditingComplete: () {
// We can query the validation state including the validation of our children at save time!
if ((controller.send(EventValidate(), down: true).result as ValidationResponse).canSave == true) {
// We have valid data!
debugPrintSynchronously("VALID DATA:${state.text}");
}
},
),
);
},
controllerInitializer: (String id, bubbleUpListener) {
return InterstateController<NestedTextFieldState>(
id: id,
initialState: const NestedTextFieldState(text: ""),
bubbleUpListener: bubbleUpListener,
handlers: [],
);
},
child: child,
);
copied to clipboard
3. Define handlers to respond to events #
...
handlers: [
/// This is a useful example of using the supplied EventValidate and ValidationResponse classes
/// We can validate our state, and differentiate local errors and child errors
EventHandler<EventValidate, NestedTextFieldState>(
eventDataType: EventValidate,
resultBuilder: (Event<EventValidate> event, NestedTextFieldState currentState,
List<Response<EventValidate, dynamic>> subResponses) =>
ValidationResponse.fromSubResponses(
// The validation error relates to the
validationError: currentState.text.isEmpty ? "Required!" : null,
// Here we could pass along an existing error message if we wanted, but we just want to replace
// any existing error messages, not propagate them
stateError: null,
// We pass along a set of all the child validation responses, and if we wanted we could do
// something with them
subResponses: subResponses),
stateBuilder: (event, state, result, subresponses) {
// The result comes from the resultBuilder, so we know it is a ValidationResponse
final validationResp = result as ValidationResponse;

if (validationResp.dataValidationError != null) {
// If we have a local validation error, we update our state accordingly
return state.copyWith(error: validationResp.dataValidationError ?? "");
} else if (validationResp.childrenHaveErrors) {
// If our children have errors, we also report an error
return state.copyWith(error: "Children have errors!");
} else {
// Otherwise clear the error
return state.copyWith(error: "");
}
}),
/// This takes a String event and uses it to update the state text. Generally we would like to wrap something
/// like this in its own StringUpdateEvent class, but for example code we can call this a demonstration of
/// typing flexibility
EventHandler<String, NestedTextFieldState>(
eventDataType: String,
resultBuilder: (_, __, ___) => null,
stateBuilder: (event, currentState, ___, ____) => currentState.copyWith(text: event.data, error: ""),
),
],
...
copied to clipboard
Additional information #
https://github.com/jdrotos/interstate

License:

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Files In This Product:

Customer Reviews

There are no reviews.