angular-redux / ng-redux

Angular bindings for Redux
MIT License
1.16k stars 178 forks source link

Was there a particular reason for choosing the provider as the place to set up the store? #138

Open niamleeson opened 7 years ago

niamleeson commented 7 years ago

Hello,

Thank you so much for creating an amazing library to tie Redux and AngularJs together.

I would like to use Redux-Observable, and I'm trying to allow injection of AngularJs services inside Action Creators and Epics by turning the Action Creators and Epics into services. This seems to be the setup ng2-redux is using.

In ng2-redux (the redux bindings for Angular 2), you are allowed to declare redux-observable epics inside a injectable service and inject the epics into the module. This allows you to inject other services into the redux-observable epics.

However, in ng-redux (the one for Angular 1), we are creating the store in the config phase of the application, and you are not allowed to inject services into a provider. If you create an epicProvider this will allow you to inject the epics into the main config, but now you lose the ability to inject other services to use inside the epics.

Here is an example where I can't inject Angularjs service into Epics:

angular.provider('myEpic', function(myService) { // This will not work. You can't inject service into a provider
  this.createEpics = function() {
    return [
      createEpicMiddleware(this.myFirstEpic)
    ];
  };

  this.myFirstEpic = function(action$, store) {
    return action$.ofType(/* type */).map(/* do something with myService */);
  };
});

angular.module('app', [])
.config(function ($ngReduxProvider, myEpicProvider) {
  var myEpics = myEpicProvider.createEpics();
  var myEpicMiddleware = createEpicMiddleware(myEpics);
  $ngReduxProvider.createStoreWith(reducer, [myEpicMiddleware], [ /* enhancers */ ], { /* initial state */ });
})
.service('myService', myServiceClass);

Here is another example where I can't inject myEpic into the config:

angular.module('app', [])
.config(function ($ngReduxProvider, myEpicService) { // Now this will not work. You can't inject a service into a provider
  var myEpics = myEpicService.createEpics();
  var myEpicMiddleware = createEpicMiddleware(myEpics);
  $ngReduxProvider.createStoreWith(reducer, [myEpicMiddleware], [ /* enhancers */ ], { /* initial state */ });
})
.service('myService', myServiceClass)
.service('myEpic', function(myService) { // I can now inject myService into myEpic
  this.createEpics = function() {
    return [
      createEpicMiddleware(this.myFirstEpic)
    ];
  };

  this.myFirstEpic = function(action$, store) {
    return action$.ofType(/* type */).map(/* do something with myService */);
  };
});;

I feel like if the store can be created in a service, injecting AngularJs services into Epics or Action Creator services would be a lot easier...

Was there a particular reason the provider was chosen as the place to set up the store?

I am not sure how I can achieve this. Would you please kindly point me toward the right direction?

jamesbrobb commented 7 years ago

@niamleeson $ngRedux middleware can be strings:

https://github.com/angular-redux/ng-redux#createstorewithreducer-middlewares-storeenhancers-initialstate

So you can create an angular factory, into which you can inject your epics (or service that creates you epics) and then return createEpicMiddleware(myEpicService.createEpics());