alexeieleusis / greencat

A port of Redux(https://github.com/reactjs/redux) to Dart, including Redux Thunk(https://github.com/gaearon/redux-thunk) and a simple Logger.
Apache License 2.0
48 stars 4 forks source link

How to inject a service into an AsyncAction #6

Closed sturmf closed 7 years ago

sturmf commented 7 years ago

Hi, thanks for the greencat library!

So far it looks really nice and I now want to add async actions to my application. With that I mean I want to create an action that makes an ajax call which returns with some new event which would trigger another action.

For this I tried to use the ThunkMiddleware. But for now I am stuck with where to get my service from. Usually I let inject the service into the Angular2 components but now the actions need to have access to it.

How would you pass it in? I don't really like to have the component that creates the action to pass the service as a parameter to the action. My component should not need to know which service to use.

Tanks a lot for any ideas!

alexeieleusis commented 7 years ago

In the place you bootstrap the app I would register the async action, similar to how is done in https://github.com/alexeieleusis/greencat/blob/master/examples/todo_list_angular/lib/app_component.dart

But I am not sure it will fit you needs, probably a minimal example to reproduce your use case would better help me understand.

Besides that cc @yjbanov who has more experience with this architecture type.

sturmf commented 7 years ago

Hmm I am not sure what you mean by registering the async action?

In case of your todolist example. I would write one service which handles all the async rest api calls for adding, removing and resolving todo entries. I can inject this service easily into any component. But I can't inject it into the action itself where I would need a reference to the service in the "call" method. Or am I missing something obvious here?

sturmf commented 7 years ago

Ok I now could come up with a working solution. In my AppCommponent I now have a static field for the global Injector. I fill it like this:

  bootstrap(AppComponent, <Provider>[provide(Client, useFactory: () => new BrowserClient(), deps: <Object>[])]).then((ComponentRef ref) =>
    AppComponent.myinjector = ref.injector
  );

And my AsyncAction now looks like this:

/// Action to request the add of a new Event.
class AddNewEventAction extends RegattaAction<String> implements AsyncAction {
  ///
  AddNewEventAction(String payload) : super(payload);

  @override
  ActionType get type => ActionType.addNewEvent;

  @override
  Future call(MiddlewareApi api) {
    EventService _event_service = AppComponent.myinjector.get(EventService);
    return _event_service.addEvent(payload).then(
        (event) { api.dispatch(addEvent(event)); }
    );
  }
}

Maybe there is something more elegant? But for me this seems to work fine.

yjbanov commented 7 years ago

I think ideally AddNewEventAction would be created by the injector too, and EventService would be injected via a constructor parameter. Unfortunately, Angular injectors can only vend singletons, and the workaround is not pretty.

Therefore, I think your solution is fine. One small suggestion: if EventService is itself a singleton (or more generally, if it's lifecycle encompasses that of AddNewEventAction), you can make it a private final field:

class AddNewEventAction extends RegattaAction<String> implements AsyncAction {
  AddNewEventAction(String payload) :
    _event_service = AppComponent.myinjector.get(EventService),
    super(payload);

  final EventService _event_service;

  @override
  ActionType get type => ActionType.addNewEvent;

  @override
  Future call(MiddlewareApi api) {
    return _event_service.addEvent(payload).then(
        (event) { api.dispatch(addEvent(event)); }
    );
  }
}
sturmf commented 7 years ago

Thank you very much for your answers. After some more twiddeling I could now also get my tests working again! So I am closing this here. I would have more questions about greencat but I don't know where to aks them, since they are not really issues with the library itself but more with the usage of it.

alexeieleusis commented 7 years ago

Feel free to ask them here or in stack overflow and ping the link here. I do not have that much experience with the flux/redux architecture, actually I implemented greencat because I was learning it, still I am happy to help with whatever I can.