EDIT - This all works if I configure redux-state-sync to use localstorage. I made a repository https://bitbucket.org/em-aitch/sync-app/src/master/ that contains example of working code. If broadcastchannel type (app.component.ts : 76) is changed from 'localstorage' to 'native' the bindings (both @select and {{ property }} don't work anymore!
EDIT2 - Question How to find out what breaks Angular binding? answers this question
I have setup using redux-state-sync described below. The redux state change is synced to other browser window but @select does not work.
When I log in in one window app-nav-menu appears because ngIf evaluates true. Also both subsriptions write to console:
new login state = true app.component.ts:20
subsribed to local observable : true app.component.ts:24
However other browser window does not work the same way even though the login state change done in the other window is synced there. Console ouput is the same:
new login state = true app.component.ts:20
subsribed to local observable : true app.component.ts:24
The problem however is that the app-nav-menu DOES NOT appear. Below first is the code directly related to this and in the end the redux definitions.
app.component.html
<body>
<app-nav-menu *ngIf="(isLoggedIn | async)"></app-nav-menu>
<div class="container">
<router-outlet></router-outlet>
</div>
</body>
app.component.ts
export class AppComponent {
title = 'app';
@select((state: IApplicationState) => state.login.isLoggedIn) isLoggedIn: Observable<boolean>;
subscription;
constructor(private ngRedux: NgRedux<IApplicationState>) {
this.subscription = this.ngRedux.select<ILoginState>('login')
.subscribe(newState => {
console.log('new login state = ' + newState.isLoggedIn);
});
this.isLoggedIn.subscribe(newState =>
console.log('subsribed to local observable : ' + newState));
}
}
app.module.ts
import { createStateSyncMiddleware, initStateWithPrevTab } from 'redux-state-sync';
import { Store, createStore, applyMiddleware } from 'redux';
export const store: Store<IApplicationState> = createStore(
rootReducer,
applyMiddleware(createStateSyncMiddleware())
);
export class AppModule {
constructor(ngRedux: NgRedux<any>) {
ngRedux.provideStore(store);
initStateWithPrevTab(store);
}
}
store/index.ts
import { combineReducers } from 'redux'
import { ILoginState, loginReducer } from './login'
import { withReduxStateSync } from 'redux-state-sync'
export interface IApplicationState {
login: ILoginState;
}
export const INITIAL_STATE : IApplicationState = {
login : { isLoggedIn: false, tokenInfo : null }
}
const appReducer = combineReducers<IApplicationState>({
login: loginReducer
})
export const rootReducer = withReduxStateSync(appReducer);
Like I said in edit in the top. This works if I configure this to use localstorage:
applyMiddleware(createStateSyncMiddleware(
{ broadcastChannelOption: { type: 'localstorage' } })));
If the state is already in sync, likely the problem is not in redux-state-sync, I would like to help you to solve the problem, however, I have limited knowledge of Angular and @select.
But I can share with you that how redux-state-sync works to sync the data across the browser tabs.
The tabs that opened after the first tab will dispatch GET_INIT_STATE action to the other tab's store, once they received this action, they will dispatch SEND_INIT_STATE along with there existing state. At the same time your last opened tab will receive this SEND_INIT_STATE event along with the other tab's entire state and triggers RECEIVE_INIT_STATE with the state.
Basically, withReduxStateSync will listen on RECEIVE_INIT_STATE action, and replace the entire state with this action's payload.
From what I see, the problem that you are facing is probably the observable is not detecting any changes on the state, so that it doesn't trigger the update.
Hope this helps, sorry that I couldn't give you more useful suggestions. Let me know if you need more information from me and if you solved this problem please let me know as well. ;-)