Giter VIP home page Giter VIP logo

ng-redux's Introduction

ng-redux

Angular bindings for Redux.

For Angular 2+ see angular-redux/store -- made by the same people that started ng-redux.

build status npm version Conventional Commits

ngRedux lets you easily connect your angular components with Redux.

Table of Contents

Installation

npm

npm install --save ng-redux

bower (deprecated)

Warning! Starting with 4.0.0, we will no longer be publishing new releases on Bower. You can continue using Bower for old releases, or point your bower config to the UMD build hosted on unpkg that mirrors our npm releases.

{
  "dependencies": {
    "ng-redux": "https://unpkg.com/ng-redux/umd/ng-redux.min.js"
  }
}

Add the following script tag to your html:

<script src="bower_components/ng-redux/dist/ng-redux.js"></script>

Or directly from unpkg

<script src="https://unpkg.com/ng-redux/umd/ng-redux.min.js"></script>

Quick Start

Initialization

There are three ways to instantiate ngRedux:

  1. createStoreWith
  2. provideStore
  3. createStore
createStoreWith

You can either pass a function or an object to createStoreWith.

With a function:

import reducers from './reducers';
import { combineReducers } from 'redux';
import loggingMiddleware from './loggingMiddleware';
import ngRedux from 'ng-redux';

angular.module('app', [ngRedux])
.config(($ngReduxProvider) => {
    let reducer = combineReducers(reducers);
    $ngReduxProvider.createStoreWith(reducer, ['promiseMiddleware', loggingMiddleware]);
  });

With an object:

import reducers from './reducers';
import loggingMiddleware from './loggingMiddleware';
import ngRedux from 'ng-redux';
import reducer3 from './reducer3';

angular.module('app', [ngRedux])
.config(($ngReduxProvider) => {
	reducer3 = function(state, action){}
    $ngReduxProvider.createStoreWith({
		reducer1: "reducer1",
		reducer2: function(state, action){},
		reducer3: reducer3
	 }, ['promiseMiddleware', loggingMiddleware]);
  });

In this example reducer1 will be resolved using angular's DI after the config phase.

provideStore

You can pass an already existing store to ngRedux using provideStore:

import reducers from './reducers';
import { createStore, combineReducers } from 'redux';
import ngRedux from 'ng-redux';

const reducer = combineReducers(reducers);
const store = createStore(reducer);

angular.module('app', [ngRedux])
.config(($ngReduxProvider) => {
    $ngReduxProvider.provideStore(store);
  });
createStore

createStore allows you take full control over the store creation. This is handy if you want to control the order of enhancers by your self. It takes a function that gets middlewares and enhancers from ngRedux as a parameters. Note that middlewares provided by ngRedux needs to be last ones.

import reducers from './reducers';
import { createStore, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import ngRedux from 'ng-redux';

const reducer = combineReducers(reducers);

angular.module('app', [ngRedux])
.config(($ngReduxProvider) => {
    $ngReduxProvider.createStore((middlewares, enhancers) => {
        return createStore(
          reducer,
          {},
          compose(applyMiddleware(thunk, ...middlewares), ...enhancers)
        )
    });
  });

Usage

Using controllerAs syntax

import * as CounterActions from '../actions/counter';

class CounterController {
  constructor($ngRedux, $scope) {
    /* ngRedux will merge the requested state's slice and actions onto this,
    you don't need to redefine them in your controller */

    let unsubscribe = $ngRedux.connect(this.mapStateToThis, CounterActions)(this);
    $scope.$on('$destroy', unsubscribe);
  }

  // Which part of the Redux global state does our component want to receive?
  mapStateToThis(state) {
    return {
      value: state.counter
    };
  }
}
<div>
    <p>Clicked: {{counter.value}} times </p>
    <button ng-click='counter.increment()'>+</button>
    <button ng-click='counter.decrement()'>-</button>
    <button ng-click='counter.incrementIfOdd()'>Increment if odd</button>
    <button ng-click='counter.incrementAsync()'>Increment Async</button>
</div>

API

createStoreWith(reducer, [middlewares], [storeEnhancers], [initialState])

Creates the Redux store, and allow connect() to access it.

Arguments:

  • reducer (Function): A single reducer composed of all other reducers (create with redux.combineReducer)
  • [middlewares] (Function[]): Optional, An array containing all the middleware that should be applied. Functions and strings are both valid members. String will be resolved via Angular, allowing you to use dependency injection in your middlewares.
  • [storeEnhancers] (Function[]): Optional, this will be used to create the store, in most cases you don't need to pass anything, see Store Enhancer official documentation.
  • [initialState] (Object): Optional, the initial state of your Redux store.

connect(mapStateToTarget, [mapDispatchToTarget])(target)

Connects an Angular component to Redux.

Arguments

  • mapStateToTarget (Function): connect will subscribe to Redux store updates. Any time it updates, mapStateToTarget will be called. Its result must be a plain object or a function returning a plain object, and it will be merged into target. If you have a component which simply triggers actions without needing any state you can pass null to mapStateToTarget.
  • [mapDispatchToTarget] (Object or Function): Optional. If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but bound to a Redux store, will be merged onto target. If a function is passed, it will be given dispatch. It’s up to you to return an object that somehow uses dispatch to bind action creators in your own way. (Tip: you may use the bindActionCreators() helper from Redux.).

You then need to invoke the function a second time, with target as parameter:

  • target (Object or Function): If passed an object, the results of mapStateToTarget and mapDispatchToTarget will be merged onto it. If passed a function, the function will receive the results of mapStateToTarget and mapDispatchToTarget as parameters.

e.g:

connect(this.mapState, this.mapDispatch)(this);
//Or
connect(this.mapState, this.mapDispatch)((selectedState, actions) => {/* ... */});

Returns

Returns a Function allowing to unsubscribe from further store updates.

Remarks

  • The mapStateToTarget function takes a single argument of the entire Redux store’s state and returns an object to be passed as props. It is often called a selector. Use reselect to efficiently compose selectors and compute derived data. You can also choose to use per-instance memoization by having a mapStateToTarget function returning a function of state, see Sharing selectors across multiple components

Store API

All of redux's store methods (i.e. dispatch, subscribe and getState) are exposed by $ngRedux and can be accessed directly. For example:

$ngRedux.subscribe(() => {
    let state = $ngRedux.getState();
    //...
})

This means that you are free to use Redux basic API in advanced cases where connect's API would not fill your needs.

Dependency Injectable Middleware

You can use angularjs dependency injection mechanism to resolve dependencies inside a middleware. To do so, define a factory returning a middleware:

function myInjectableMiddleware($http, anotherDependency) {
    return store => next => action => {
        //middleware's code
    }
}

angular.factory('myInjectableMiddleware', myInjectableMiddleware);

And simply register your middleware during store creation:

$ngReduxProvider.createStoreWith(reducers, [thunk, 'myInjectableMiddleware']);

Middlewares passed as string will then be resolved throught angular's injector.

Config

Debouncing the digest

You can debounce the digest triggered by store modification (usefull in huge apps with a lot of store modifications) by passing a config parameter to the ngReduxProvider.

import angular from 'angular';

angular.module('ngapplication').config(($ngReduxProvider) => {
  'ngInject';

  // eslint-disable-next-line
  $ngReduxProvider.config.debounce = {
    wait: 100,
    maxWait: 500,
  };
});

This will debounce the digest for 100ms with a maximum delay time of 500ms. Every store modification within this time will be handled by this delayed digest.

lodash.debounce is used for the debouncing.

Routers

See redux-ui-router to make ng-redux and UI-Router work together.
See ng-redux-router to make ng-redux and angular-route work together.

Using DevTools

There are two options for using Redux DevTools with your angular app. The first option is to use the [redux-devtools package] (https://www.npmjs.com/package/redux-devtools), and the other option is to use the [Redux DevTools Extension] (https://github.com/zalmoxisus/redux-devtools-extension#usage). The Redux DevTools Extension does not require adding the react, react-redux, or redux-devtools packages to your project.

To use the redux-devtools package, you need to install react, react-redux and redux-devtools as development dependencies.

[...]
import { devTools, persistState } from 'redux-devtools';
import { DevTools, DebugPanel, LogMonitor } from 'redux-devtools/lib/react';
import React, { Component } from 'react';

angular.module('app', ['ngRedux'])
  .config(($ngReduxProvider) => {
      $ngReduxProvider.createStoreWith(rootReducer, [thunk], [devTools()]);
    })
  .run(($ngRedux, $rootScope, $timeout) => {
    React.render(
      <App store={ $ngRedux }/>,
      document.getElementById('devTools')
    );

    //To reflect state changes when disabling/enabling actions via the monitor
    //there is probably a smarter way to achieve that
    $ngRedux.subscribe(() => {
        $timeout(() => {$rootScope.$apply(() => {})}, 100);
    });
  });

  class App extends Component {
  render() {
    return (
      <div>
        <DebugPanel top right bottom>
          <DevTools store={ this.props.store } monitor = { LogMonitor } />
        </DebugPanel>
      </div>
    );
  }
}
<body>
    <div ng-app='app'>
      [...]
    </div>
    <div id="devTools"></div>
</body>

To use the Redux DevTools extension, you must first make sure that you have installed the Redux DevTools Extension.

angular.module('app', ['ngRedux'])
  .config(($ngReduxProvider) => {
      $ngReduxProvider.createStoreWith(rootReducer, [thunk], [window.__REDUX_DEVTOOLS_EXTENSION__()]);
    })
  .run(($ngRedux, $rootScope, $timeout) => {
    //To reflect state changes when disabling/enabling actions via the monitor
    //there is probably a smarter way to achieve that
    $ngRedux.subscribe(() => {
        $timeout(() => {$rootScope.$apply(() => {})}, 100);
    });
  });

Additional Resources

ng-redux's People

Contributors

abelmokadem avatar akolodeev avatar antjanus avatar c-dante avatar d34thwings avatar dballance avatar deini avatar derrickpelletier avatar elgerlambert avatar evanoxfeld avatar evgentraytyak avatar foxandxss avatar graingert avatar hgsigner avatar iamfirecracker avatar jchaney01 avatar jrakotoharisoa avatar jtassin avatar kareniel avatar koleok avatar lautis avatar mndewitt avatar no-stack-dub-sack avatar oliviernt avatar reneviering avatar roryokane avatar sandwich99 avatar takahser avatar troch avatar wbuchwalter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ng-redux's Issues

Default initialState in 3.2.0 breaks code

Assume you had a root reducer that set initial state when called:

const initialState = Map();
function reducer (state = Map(), action) {...}

When upgrading to 3.2.0 from previous minor version, this code breaks, because es6 default parameter no more applied, because state is {} by default. It's really a breaking change.

I think, ng-redux should not set empty object as default initial state. But that will cause problems with packages that depend on that feature.

New connect API with controllerAs?

Hi,

I just tried upgrading to RC-4, and noticed that the connect API has changed, and is now explicit about requiring $scope.

Previously, with

export default class SomeController {
  constructor($ngRedux) {

    $ngRedux.connect(state => state.someSlice, someSlice => {
      this.x = someSlice;
    });
  }

}

Would give the opportunity to use reselect as my selector, and then have a bit more explicit control over how the result of that was bound to my controller. However now, with.

$ngRedux.connect($scope, state => {
  return {
    thing: state.thing
  };
})

It seems like a little bit of control is lost. Since this is now being bound to $scope.x = state.thing, in my template having <input ng-model="vm.thing"/> doesn't work, unless after the initial $ngRedux.connet, I do something like angular.extend(this,$scope.thing)

While getting the callbacks from state updates/actions into the digest lifecycle with the digest middleware is good, and the automatic unbinding of the callbacks is nice - it feels like something was lost with the recent changes.

I also had a case where I was wanting to use $ngRedux.connect within a service - and now needing to bring $rootScope into a service so I can do a $rootScope.$new() to pass into connect seems like a step backwards.

I was also looking into using ImmutableJS - and was wanting to have my re-selectors still return an ImmutableJS object - but redux is now complaining that it's not a POJO - and need to change them to use a .toJS()

To me, it seems like the connect API should have $scope and auto-binding be optional (or be able to pass in this instead of $scope), or maybe $ngRedux.connect that is similar to the previous implementation, and $ngRedux.connectToScope which would be closer to the new implementation.

The digest middleware is an excellent addition - and something along the lines I was thinking of trying to submit a PR for.

Maybe I just need to spend a bit more time with the changes - but if I'm missing something, please let me know, but it almost feels as if the reliance on $scope is a little bit of a step backwards.

Question: How to call a method after state has been mapped to this

Hi William,

thank you very much for creating and maintaining ng-redux, it has helped me a lot!

I have one question:
What is the best approach if I need to call some method after the state has changed and was mapped to this? If I put the method invocation in the mapDispatchToTarget it'll be called before the state has been mapped.

Currently I'm passing a function as target to $ngRedux.connect, however then I have to call _.assign(target, StateSlice, dispatch) by myself. This doesn't seem to be a nice solution (or is it?).

I'm pretty new to all this, so please excuse if this is a silly question.

Best,
Andreas

$scope may not contain the controller-as-key during controller activation (ui-router)

While playing with ng-redux I stumbled upon a case when findControllerAsKey is not able to figure out the controller-as-key, because the key does not exist in the $scope yet.

Repro: http://requirebin.com/?gist=559a4edcfbee14c79e27

  • angular 1.4.5, ui-router 0.2.15
  • ng-redux 1.0.0-rc.4
  • Chrome 44.0.2403.157

The workaround is to delay the $ngRedux.connect call a bit, for example with $scope.$evalAsync (commented out in the repro).

I'm not sure what causes this. Is it worth looking into, considering #12 and bc-1.0.0 changes?

Role of angular services in redux

Hi William,

I am very new to redux (a day old :) ) and while I have started to get the feel for the problems it (redux) may help solve I am having some doubts/confusion around the role of angular services/factories in this new architecture.

The 'state' of a view or even entire application is typically managed by angular services/models in a traditional angular application

Would help if you could throw some light on hat limited use of angular services would be with redux/ng-redux

Regards & thanks
Kapil

Default initial state

Creating a store like this $ngReduxProvider.createStoreWith(myReducer); causes the reducers receive arguments like this:

{ 
   state: {}, 
   action: {type: "@@redux/INIT"}
}

This prevents the reducer from returning initial state on the first run like this:

if (typeof state === 'undefined') {
   return initialState
}

Reducer should be called instead with the following arguments:

{ 
   state: undefined, 
   action: {type: "@@redux/INIT"}
}

shallowEqual need to be enhanced

shallowEqual always return false, cause angular.js create $$hashkey for each vm

image

   var keysA = Object.keys(objA);
   var keysB = Object.keys(objB);

   if (keysA.length !== keysB.length) {
     return false;
   }

redux 2.0 breaking changes

Looking at the redux breaking changes, and the bc-1.0.0 branch, looks like compose was changed which may affect this line

let finalCreateStore = _storeEnhancers ? compose(..._storeEnhancers, createStore) : createStore;

looks like you might just be able to change it to

let finalCreateStore = _storeEnhancers ? compose(..._storeEnhancers)(createStore) : createStore;

ngRedux.connect mapStateToTarget is a direct reference to the state object by consequence is really easy to mutate

The use case is this:

Inside my class I defined my mapStateTarget callback as:
onUpdate (state) { return { model: state.model }; }

On the other side I have an input that needs to modify an attribute of the model (this model can have some data already), so the obvious html would be.

<input type="text" ng-change="$ctrl.actionX($ctrl.model.name)" ng-model="$ctrl.model.name" />

at this point everything looks great but...

mapStateToTarget callback is returning a direct reference from to state.model so any change on the input is mutating the state directly (this because ng-model has double binding implicit) before the action being triggered .

I tried different ways to bind the value to the input without breaking the immutability (no success). angular does not expose any other way to handle changes on inputs[text]

One possible solution can be that mapStateTarget should receive a clone of the state.

any thoughts on this ?

Problems unit testing controllers and ngRedux

I recently posted a question on stackoverflow regarding issues i have unit testing controller in an angular/ES6/Redux app. Unit testing actions and reducers is well documented, and quite simple to implement. However, I am having trouble with controllers - specifically with class constructors, DI and connect functions binding of my actions to lexical 'this', etc.

http://stackoverflow.com/questions/35188646/angular-redux-es6-unit-testing-controllers

To keep this brief, I am wondering if one of you could post an example of testing a controller with ngRedux as a constructor param. I would like to mock redux in this scenario, but I am hitting a wall doing this with an ES6 constructor. I dont see this as an issue per se, but it would definitely help those like me that need to ramp up on Redux (and things that are also new like ES6/modules). Any help would be greatly appreciated.

argument seems to miss in reselect

Here, https://github.com/wbuchwalter/ng-redux/blob/master/src/components/connector.js#L68

function getStateSlice(state, mapStateToScope) {
  const slice = mapStateToScope(state);

A props argument should be passed (I am newbie in redux/reselect, so I can't tell how, sorry).
I tried to follow the documentation of reselect.

Here is my use case :

import {createSelector} from 'reselect';

const applicationSelector = createSelector(
  (state, ownProps) => {
    console.log('applicationSelector 1', state, ownProps); //got state and undefined, I would have {foo: 'bar'}
    return state.router;
  },
  routerState => routerState.name
});

export class LayoutApplicationSwitcherController {
  constructor($scope, $ngRedux) {
    'ngInject';
    this.foo = 'bar';
    $scope.$on('$destroy', $ngRedux.connect(applicationSelector)(this));
  }
}

compare state and prevState

There is an optimization in react-redux which compares previous and current state and do not make slice if they are equal. Is it possible to introduce this optimization in ng-redux?

How to use $exceptionHandler

Hey,

we introduced ng-redux in our app and one thing we're missing so far is proper exception monitoring using $exceptionHandler. Usually Angular exception pop out there which makes it really easy for us to track errors.

Is there any way to connect something similar with the reducers?

This is how we initialize it - I was thinking of hooking in somewere there. :)

$ngReduxProvider.createStoreWith(
  reducer,
  [ thunkMiddleware ],
  window.devToolsExtension ? [ window.devToolsExtension() ] : undefined
);

Angular 2

Hi William,

Have you tried this with Angular 2 at all to see if the concepts and the code would plug in?

Jim

Be able to register multiple reducers with ng-redux

I have an application in which I split different pieces of functionality into Angular modules, and then use all the modules I need in a "core module" that actually bootstraps to the page:

let page = angular.module('CoreModule', ['Feature1', 'Feature2', 'Feature3']);
angular.bootstrap(document, ['CoreModule']);

All of these "feature modules" use ngRedux, so their config stages all resemble the following:

module.config(($ngReduxProvider) => {
  $ngReduxProvider.createStoreWith(reducer, [thunk]);
});

The problem is: createStoreWith only allows a single reducer to be registered, meaning that you cannot register reducers from multiple "feature modules" with $ngReduxProvider; in a example with 3 "feature modules", 2 will get smashed and only 1 will survive.

It would be nice if $ngReduxProvider could register multiple reducers, and then the $get method uses combineReducers to combine all the registered reducers together and makes a store out of these combined reducers to create a single injectable instance of a $ngRedux, thus preserving a single store. Usage may look like this:

module.config(($ngReduxProvider) => {
  $ngReduxProvider.registerReducer(reducer, [thunk]);
});

This allows each "feature module" to be responsible for its own reducers. Without this, the "core module" has to import all possible reducers, combine them, and then register them with $ngReduxProvider, breaking the single responsibility principle. Notice how each "feature module" should be able to register middleware with the $ngReduxProvider.

Dispatches called before being bound

Hi,

In the latest version, I'm using
connect(mapStateToTarget, [mapDispatchToTarget])(target)
But in a number of scenarios - I'm having state changes hit mapStateToTarget before mapDispatchToTarget is bound to the target.
I my case - I issue a dispatch for some http calls when certain state criteria is met - but obviously this blows up if the state is pre-existing, as the dispatch is not bound.

I'm assuming this isn't intended? Or am I doing it wrong?

createStoreWith without middleware fails

If you call $ngReduxProvider.createStoreWith without specifying middleware, then $ngRedux will throw Cannot read property 'Symbol(Symbol.iterator)' of undefined upon injection.

Proposed fix: make $ngReduxProvider.createStoreWith take [] as default parameter for middleware.

Should I make a pull request?


Chrome 44.0.2403.157

Unable to run async example.

To get the async example running I did some hacks...

I had to upgrade babel dependencies to

 "babel-core": "^6.0.0",
 "babel-loader": "^6.0.0",

Then I had to temporarily remove import 'babel-core/polyfill'; from index.js, because I was getting

ERROR in ./index.js
Module not found: Error: Cannot resolve module 'babel-core/polyfill' in /home/tersiusk/WebstormProjects/samples/ng-redux/examples/async
 @ ./index.js 3:0-30
// import 'babel-core/polyfill';
import angular from 'angular';
import ngRedux from 'ng-redux';
...

Question about middleware best practices with angular 1.x

Hi folks,

Thanks for this project!

I had a question around middleware, and what might be the best practices for doing such things as Promises, requests to server etc?

Is anyone creating their own middleware using this with angular 1.x (api, promise, etc...)? If so, have you run into any issues or difficulties? Are you using angular's provided utilities ($http, $q, etc.) or are you pulling in another third party lib for doing this stuff?

Any insight would be much appreciated!

Cheers
Mike

curried connect results in this === udefined

I have the following code in a component"

import angular from 'angular';
import template from './home.html';
import uiRouter from 'angular-ui-router';

const controller = class HomeController {
  constructor($ngRedux, $scope, productsActions) {

    const unsubscribe = $ngRedux.connect(this.mapStateToThis, productsActions)((selectedState, actions) => {
      console.log(this); //undefined
   });

    $scope.$on('$destroy', unsubscribe);
  }

  mapStateToThis(state) {
    const {
      isFetching,
      products,
      sort,
      page,
      pageSize
    } = state.products;

    return {
      isFetching,
      sort,
      page,
      pageSize,
      products
    };
  }

  $onInit() {
    this.fetchNewSortQueryIfNeeded(this.sort);
  }
};

But in the function returned from the initial call to connect, this is undefined.

Initial store state

Hi, the Redux method to create a store is createStore(reducer, [initialState]). Is there a way in ng-redux to supply an initial state to the created store? Otherwise you can't seed the application from the server or localStorage.

I guess this relates to #19 a bit.

ng-model and angular binding concept discution

Hi,
I've been reading about Redux, and it sounds very interesting!
The issue that I want to raise is the conflict in the way we "suppose" to work in angular, like binding, ng-model, etc. and this new way (Redux/Flux).
Using Redux means that we are not suppose to work with ng-model or binding anymore... and only raise an action that will cause a recreation of the model.
Also, when the new state is re-created all the references are changed, and a full redraw will happen in Angular...

What do you guys think about that? I'd love to use all the abilities that we have in Angular (Modules, Injection, Templates, bla bla), with this new way of thinking, and all that comes with it.

Thanks.

Allow dependency injectable reducers

Similar to dependency injectable middleware, allow the reducer to be a string of an Angular service as well, which would then be injected.

The reason why is because currently I can't seem to find a way to use the library in a project that doesn't use modules (not using webpack, browserify, etc). So, import reducers from './reducers'; won't work for me.

My main reducer is an Angular factory, and it consumes other reducers, which are also Angular factories.

It looks like you aren't actually creating the Redux store until after the config phase anyways (since you need to wait for the injectable middleware).

mapDispatchToTarget issues when using middleware and actions that return non-plain objects

Setting up a sample application to use redux-ui-router,

Have a controller like this:

export default class MainController {
  constructor($ngRedux, ngUiRouterActions, $scope) {
    let _onUpdate = (state) => ({
      globalState: state
    });
    let disconnect = $ngRedux.connect(_onUpdate, ngUiRouterActions)(this);
    $scope.$on('$destroy', () => disconnect());

  }

}

In the template I have:

<a ng-click="main.stateGo('app.orders.pending')">Pending Orders</a>

When I click the link, I get an error from redux saying actions must return plain JS objects, to use non-JS objects - to use a middleware.

However, if I put the following into my controller

this.stateGoTest = (state) => ngUiRouterActions.stateGo(state);

and change my template to use main.stateGoTest

Then the action fires, and I don't get any errors. Interestingly though - even with the errors that redux logs, looks like the event fires anyways.

Also tried something like:

$ngRedux.connect(_onUpdate,ngUiRouterActions)((state, dispatch) => {
this.stateGo = dispatch.stateGo; // error
this.stateGo = (state) => dispatch.stateGo(state); // error
this.stateGo = (state) => ngUiRouterActions.stateGo(state); // works
})

I do have the thunk middleware as part of my $ngProvider.createStoreWith - so not sure what is going on.

I'll try and get a smaller stand-alone example together later if needed.

Using ng-redux without ES6 modules

I am consuming ng-redux in a project that does not use any modules. The challenge that I ran into with this approach is with the config block. If you have any suggestions for this, I would greatly appreciate it!

angular.module('counter', [ngRedux])
  .config(($ngReduxProvider) => {
    $ngReduxProvider.createStoreWith(rootReducer, [thunk], [DevTools.instrument()]);
  });

What would be the best way to create reducers here? Should they be $providers so they can be injected in the config block?

If ngRedux provided a factory instead of a provider it could be setup in a run block and everything (reducers, actionCreators, etc.) can be defined as factory.

I understand that using ES6 modules is great and brings lots of benefits. I don't have that setup for my angular project though.

Do not include Redux and other libs in bower component

Currently the bower component includes Redux itself, lodash and other libraries which is making it quite large (~3000 lines vs ~800 lines that has the whole Redux lib). I think Redux should simply be stated as a dependency, not included in the component and the other dependencies should be removed.

ReferenceError: angular is not defined

ReferenceError: angular is not defined
    at Object.<anonymous> (...\node_modules\ng-redux\lib\index.js:11:22)
import ngReduxProvider from './components/ngRedux';

export default angular.module('ngRedux', [])
  .provider('$ngRedux', ngReduxProvider)
  .name;

When I use it in iojs 1.2.0, it seems that angular is not available in lib/index.js 11:22

npm package for v3.1.0 seems to contain older version

I tried to install ng-redux version 3.1.0 using npm:

$ npm install --save ng-redux

But the installed package code still contains references to the complete lodash package. Even after clearing the npm cache. So I have to manually include the lodash to my project as the package is missing in the ng-redux package dependencies.

Feature Request: use an already created store.

I'm aware I'm already pretty far out on a limb here, but my project uses both react (via ngreact) and angular. We've been using redux for the react part of the application, and I'm not working to bring it to the angular portion using your module. (Great work, btw!)

We already have a redux store, and would like to just share it between the react and angular portions instead of keeping two stores in parallel by sharing the reducers. Would that be as simple as adding a .useStore() method to ngReduxProvider?

index.d.ts in base folder is causing issue with TypeScript

I installed latest ng-redux module and put it into my project using browserify + tsify (I'm using TypeScript). I've also included the type definitions from the DT repo.

When I include this lib in my project via import 'ng-redux', I get the following error:

Error TS2306: File `node_modules/ng-redux/index.d.ts` is not a module

If I move index.d.ts outside the folder, it will compile properly and include the lib in my project.

Is it possible to move this file into dist folder or another location?

BTW thanks for making this lib, it's very helpful when using redux with ng1!

Need a way to access the store object

I am migrating my Angular app to React, and I need to retrieve and pass the store object to react-redux.

So, can you guys add a way to retrieve the store object?

assign vs. extend and immutables

In order to get ng-redux to work with immutable.js, I changed one thing -- I swapped assign out and replaced it with extend:

https://github.com/laurelnaiad/ng-redux/commit/0e8238e7ecf7292f1680ea6478cb9ad395613598#diff-e9375d670627d2f5df250504bf7cfc57

I guess the issue is whether or not your state tree is really and truly plain objects vs. immutables... immutables die during assign....

Is there any harm in switching to extend? Could this change go in? Or is this going to wreak havoc with folks who aren't using immutables or terrible in some other way? ;)

Change global .babelrc to local options

If you're using gulp with babel, and include all dependencies in a bundle (when not using browserify or webpack, for example), ng-redux causes an error due to the .babelrc global config file, which babel will read when processing all files.

If you're noticing this error:
Error: Couldn't find preset "es2015-loose" relative to directory "../node_modules/ng-redux"

To get around this bug, the easiest fix is to install babel-preset-es2015-loose in your project. The proper fix is for ng-redux to only include it locally, since the preset is a devDependency and not a dependency, and .babelrc is a global requirement.
Hopefully this helps a few people dealing with the same issue.

How to proceed with multiple modules and reducers

Hey there - I'm currently evaluating ng-redux to bring it into our massive app.

The situation is as follows.
We ship several different modules providing different parts of the app. I'd like to connect all the data of these via the flux/redux structure.

According to the docs:

angular.module('app', [ngRedux])
.config(($ngReduxProvider) => {
    let reducer = combineReducers(reducers);
    $ngReduxProvider.createStoreWith(reducer, ['promiseMiddleware', loggingMiddleware]);
  });

I have to define all the reducers upfront in the configuration of the big big app module. What I'd like to do is to register several reducers and store parts on the config phases of the different dependency modules.

Main idea would be that the modules enrich the global state by itself.

This is currently not possible, as only the createStoreWith function is provided.
I'm kind of thinking of a extendStoreWith function or something similar.

Is this totally off track or am I missing something in here?

Thanks for any advice. :bowtie:

Dist should have source map, min and regular versions

I just installed ng-redux via Bower. I see a ng-redux.js file in the dist folder, and I thought "there should be a minified version". Then I opened the file, to see it is actually minified...

So, I suggest:

  • To name this file ng-redux.min.js to follow common practices;
  • To create also a source map for easy debugging;
  • And / or to provide a non-minified version of this file. I like to include the non-minified version in debug builds and in tests.

add initialState param to createStoreWith in index.d.ts

initialState param is missing in createStoreWith in index.d.ts.

here is createStoreWith function:
this.createStoreWith = (reducer, middlewares, storeEnhancers, initialState)...

here is index.d.ts that does not include initialState param:
createStoreWith(reducer: Reducer, middlewares?: Array<Middleware | string>, storeEnhancers?: Function[]): void;

Any example how to integrate redux-saga with ng-redux?

i'm tried to integrate with redux-saga middleware.
But getting following error
"Before running a Saga, you must mount the Saga middleware on the Store using applyMiddleware(…)"
My code is look like
export function ConfigRedux($ngReduxProvider) {
$ngReduxProvider.createStoreWith(rootReducer, [sagaMiddleware]);
sagaMiddleware.run(helloSaga);
}
My understanding is createStoreWith do applyMiddleware internally. What i'm missing here?

DI-aware middleware

Looking into using redux/ng-redux with a new Angular application I'm working on.

Being able to register middleware with Redux seems really promising, but was having a difficult time getting my head around how to make the middleware be able to leverage Angular's DI - more for core services like $http

For example, the api-middleware, but being able to use $http instead of fetch.

using ng-redux without injecting $scope

A best practice for controllers angular 1.x includes few concepts:

  1. using controllerAs
  2. avoid using $scope
  3. keep logics in services

Is there a way to use ngRedux without injecting "$scope"?
Is there a way to use ngRedux in services?

Thanks.

Use with .component syntax?

Is it possible to use this library with .component in Angular 1.5? I'm getting the error warning.js:14 Store does not have a valid reducer. Make sure the argument passed to combineReducers is an object whose values are reducers., which seems odd. Here's some code

home.component.js

import * as PhotoActions from 'actions/photo.actions';
import template from './home.component.html';

class HomeController {
    constructor($ngRedux, $scope) {
        const unsubscribe = $ngRedux.connect(this.mapStateToThis, PhotoActions)(this);
        $scope.$on('$destroy', unsubscribe);
    }

    // Which part of the Redux global state does our component want to receive?
    mapStateToThis(state) {
        return {
            photos: state.photos
        };
    }
}

export const homeComponent = {
    template: template,
    controller: HomeController
};

This is attached to a module, .component('homeComponent', homeComponent). All registers just fine, and if I remove the ngRedux code it renders fine.

I have a photos.reducer, which is exported using combineReducers:

import { LOAD_PHOTOS } from 'actions/photo.actions';

export default function photos(state = [], action) {
    switch (action.type) {
        case LOAD_PHOTOS:
            return action.payload;
        default:
            return state;
    }
}

...and then exported as rootReducer from reducers/index.js here.

import { combineReducers } from 'redux';
import photos from './photos.reducer';

const rootReducer = combineReducers({
    photos
});

export default rootReducer;

And in the config phase, I register everything.

import rootReducer from './reducers'
// ...
.config($ngReduxProvider => {
    $ngReduxProvider.createStoreWith(rootReducer, [loggerMiddleware]);
})

Am I doing something wrong, or can this library just not be used with .component and only directive?

redux-logger logs wrong nextState with ng-redux

I have such setup:

import createLogger from 'redux-logger';

...

$ngReduxProvider.createStoreWith(reducer, [
  thunk,
  createLogger({collapsed: true})
]);

redux-logger logs actions properly but its nextState is incorrect — it is the same as prevState.

The same redux-logger in react.js application work just fine.
I think the problem is that logger is not the last middleware in chain, because ng-redux appends its own middleware after the logger one.

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.