An unknown error is showing with ngrx and angular. When i use store.select of ngrx in my component with state variable. than it is giving an unknown error.
component file
#Component({
selector: 'app-all-user',
templateUrl: './all-user.component.html',
styleUrls: ['./all-user.component.css']
})
export class AllUserComponent implements OnInit {
constructor(private userService: UsersService, private readonly store: Store) { }
users: Users[] = []
isLoading:boolean = false
isLoaded: boolean = false
p: number = 1;
ngOnInit() {
this.getAllUsers()
}
getAllUsers(){
this.store.dispatch(new UserListAction())
this.userService.getAllUser().subscribe((res:any) => {
this.store.dispatch(new UserListCreatorSuccess(res.users))
})
this.store.select(getUserStateUser).subscribe((res:any) => {
this.users = res.users
})
}
}
Index reducer
export interface RootReducerState {
usersstate: fromUser.userReducerState
}
export const RootReducer: ActionReducerMap<RootReducerState> = {
usersstate: fromUser.userReducer
};
// get user state
export const getUserState = (state:fromUser.userReducerState) => state
export const getUserStateLoaded = createSelector(getUserState, (state:fromUser.userReducerState) => state.loaded)
export const getUserStateLoading = createSelector(getUserState, (state:fromUser.userReducerState) => state.loading)
export const getUserStateUser = createSelector(getUserState, (state:fromUser.userReducerState) => state.users)
export const metaReducers: MetaReducer<RootReducerState>[] = !environment.production ? [] : [];
It is working fine with angular 10 but on working with angular 14. It is giving issue of overload.
Please have a look at the screenshot
getUserState selector is not correct. it should be
export const getUserState = createFeatureSelector<fromUser.userReducerState>('usersstate')
Related
Mobx giving me this error, and I don't know what is going on, there is no error in my code, what I make wrong? I tried so much fix this problem, hours and hours, someone knows what wrong I do??
stores/index.ts
import ProductStore from './product.store';
class RootStore {
products: ProductStore;
constructor() {
this.products = new ProductStore();
}
}
const store = new RootStore();
export {RootStore, ProductStore};
export default store;
stores/product.store.ts
import {WalmartApi} from '../api';
import {action, makeAutoObservable, runInAction} from 'mobx';
export default class ProductStore {
products = [];
constructor() {
makeAutoObservable(this);
}
#action
getProducts = async (searchQuery: string): Promise<void> => {
const snapshot = await WalmartApi.getProductsBySegment(searchQuery);
console.log({snapshot});
runInAction(() => {
this.products = snapshot;
});
};
}
hooks/userStores.tsx
import React from 'react';
import {MobXProviderContext} from 'mobx-react';
import store from '#stores';
export const useStores = (): typeof store => {
return React.useContext(MobXProviderContext).rootStore;
};
screens/Home.tsx
const {products} = useStores();
const onInit = () => {
products.getProducts('Playstation5');
};
useEffect(() => {
onInit();
});
Building state with ngxs in angular
//Component.ts
ngOnInit(): void {
const dataInsdeStore = this.store.selectSnapshot(MarketState);
if(!dataInsdeStore.loaded){
const category = this.marketplaceService.getMarketplaceCategories().subscribe(cat => {
const item = this.marketplaceService.getMarketplaceItems().subscribe(i => {
const obj = {
categories: cat,
items: i,
loaded: true
}
this.store.dispatch(new SetMarketAction(obj))
})
})
}
const test = this.store.selectSnapshot(MarketState);
this.store.dispatch(new GetMarketStateAction())
}
Upon checking wether the state is empty or not, and dispatching SetMarketAction I get empty object anyways
//Market.actions.ts
import { MarketStateInterface } from "../interfaces/interfaces";
class SetMarketAction {
static readonly type = '[MARKET] Set';
constructor(public marketState : MarketStateInterface){}
}
class GetMarketStateAction {
static readonly type = '[MARKET] Get';
}
export { SetMarketAction, GetMarketStateAction };
//Market.state.ts
import { Action, State, StateContext } from '#ngxs/store';
import { MarketStateInterface } from '../interfaces/interfaces';
import { Injectable } from '#angular/core';
import { GetMarketStateAction, SetMarketAction } from './market.actions';
#State<MarketStateInterface>({
name: 'market',
defaults: {
categories: [],
items: [],
loaded: false,
},
})
#Injectable()
export class MarketState {
constructor() {}
#Action(GetMarketStateAction)
getMarket(ctx: StateContext<MarketStateInterface>) {
const state = ctx.getState();
console.log(state);
return state;
}
#Action(SetMarketAction)
setMarket(ctx: StateContext<MarketStateInterface>, action: SetMarketAction) {
ctx.setState(action.marketState);
}
}
Every time I conosle.log the state at any given time I get the empty array, the interface of the state is correct
I'm currently doing a setup of an ngrx app. One of the goal is to use ngrx to train myself even if the application is too small.
It's a small project for beer inventory management.
I've a component in which I want to display my beer list:
export class BeerListComponent implements OnInit {
availableBeers$: Beer[];
constructor(private breadcrumbService: BreadcrumbService,
private beerService: BeersService,
private store: Store<fromBeer.BeerState>) {
this.breadcrumbService.setItems([
{ label: 'Beers' },
{ label: 'List' }
]);
}
ngOnInit() {
this.store.select(fromBeer.getAvailableBeers).subscribe((beers: Beer[]) => {
console.log(beers);
this.availableBeers$ = beers;
})
console.log('fetching beers');
this.beerService.fetchBeersList();
}
}
my beer service does the following:
export class BeersService {
private firebaseSubscription: Subscription[] = [];
constructor(
private db: AngularFirestore,
private store: Store<fromBeers.BeerState>) { }
fetchBeersList() {
this.firebaseSubscription.push(this.db
.collection('beers')
.valueChanges()
.subscribe((beers: Beer[]) => {
console.log("Received a firebase change");
console.log(beers);
this.store.dispatch(new SetAvailableBeers(beers));
}, error => {
console.log(error);
}));
}
}
and here are my reducer/actions:
Actions
export enum BeersActionTypes {
SET_AVAILABLE_BEERS = '[Beers] SET_AVAILABLE_BEERS'
};
export class SetAvailableBeers implements Action {
readonly type = BeersActionTypes.SET_AVAILABLE_BEERS;
constructor(public payload: Beer[]) {
console.log(payload);
}
}
export type BeersActions
= SetAvailableBeers;
Reducer
export interface BeerState {
availableBeers: Beer[];
};
const initialState: BeerState = {
availableBeers: []
};
export function beersReducer(state = initialState, action: BeersActions): BeerState {
switch (action.type) {
case BeersActionTypes.SET_AVAILABLE_BEERS: {
console.log("Setting available beerse")
return {
...state,
availableBeers: action.payload
};
}
default: {
return state;
}
}
}
export const getAvailableBeers = (state: BeerState) => state.availableBeers;
What I cannot understand:
I receive beers from firebase, but my component never gets the update. If I check the chrome dev tools, I only get one this undefined but this doesn't get updated after.
Here are my logs:
I feel I did not register correctly to my ngrx state, but I cannot figure out what I did wrong?
I think I found my error!
I was subscribing directly to the beerReducers.getAvailableBeers and not the one of my app.reducer(which contains the CreateSelector and stuff)
I am using ngrx in an Angular 6 app and I can successfully load data from a database and display it on the screen. However, when I navigate to a new page in the app and then navigate back, the state is not preserved and it appears the #Effect is called again and loads the data from the database again. Here is my code:
Effect
export class ProductEffects {
constructor(private productService: ProductService, private actions$: Actions) { }
#Effect()
loadProducts$: Observable<Action> = this.actions$.pipe(
ofType(productActions.LOAD_ACTION),
switchMap(action =>
this.productsService.getProductDetails().pipe(
map(product => new productActions.LoadSuccess(product)),
catchError(err => of(new productActions.LoadError(err)))
)
)
);
Reducer
export interface ProductState {
product: Product;
}
const initialState: ProductState = {
product: {}
};
export function reducer(state = initialState, action: Action) {
switch (action.type) {
case SET_PRODUCT:
return { ...state, product: (action as SetProductAction).payload };
case LOAD_SUCCESS:
return { ...state, product: (action as LoadSuccess).payload, error: '' };
default: return state;
}
}
Actions
export const SET_PRODUCT = '[Product] Set Product';
export const LOAD = '[Product] Load';
export const LOAD_SUCCESS = '[Product] Load Success';
export const LOAD_ERROR = '[Product] Load Error';
export class SetProductAction implements Action {
readonly type = SET_PRODUCT;
constructor(public payload: Product) { }
}
export class Load implements Action {
readonly type = LOAD;
}
export class LoadSuccess implements Action {
readonly type = LOAD_SUCCESS;
constructor(public payload: Product) { }
}
export type ProductActions = SetProduct | Load | LoadSuccess;
Store
export interface State extends fromRoot.AppState {
product: fromProduct.ProductState;
}
// selectors
const getProductState = createFeatureSelector<fromProduct.ProductState>('product');
export const getProduct = createSelector(
getProductState,
state => state.product
}
Component
products$: Observable<Product>;
constructor(private store: Store<fromProduct.State>) { }
ngOnInit() {
this.store.dispatch(new Load());
this.products$ = this.store.pipe(select(fromProduct.getProduct));
}
Your ngrx implementation seems all ok to me. What you describe is an absolutely normal behavior. As soon as you navigate away from a page, the component destroyed and the new one is created, i.e. the ngOnInit is called. If you put the Loading logic in the ngOnInit, the state is loaded everytime you navigate to this page.
I have some code in index.js that I got from this tutorial: https://angularfirebase.com/lessons/angular-stripe-payments-part-2-firebase-cloud-functions-backend/
Here's the code:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase);
const stripe = require('stripe')(functions.config().stripe.testkey)
exports.stripeCharge = functions.database
.ref('/payments/{userId}/{paymentId}')
.onWrite(event => {
const payment = event.data.val();
const userId = event.params.userId;
const paymentId = event.params.paymentId;
// checks if payment exists or if it has already been charged
if (!payment || payment.charge) return;
return admin.database()
.ref(`/users/${userId}`)
.once('value')
.then(snapshot => {
return snapshot.val();
})
.then(customer => {
const amount = payment.amount;
const idempotency_key = paymentId; // prevent duplicate charges
const source = payment.token.id;
const currency = 'usd';
const charge = {amount, currency, source};
return stripe.charges.create(charge, { idempotency_key });
})
.then(charge => {
admin.database()
.ref(`/payments/${userId}/${paymentId}/charge`)
.set(charge)
})
});
How do I pass a "SUCCESS" message to my component, for example: make-payment.component.ts, which is in TypeScript.
i don't know if is best way to do it but you can use custom Event to communicate to your Component
On your Component or what ever :
import { Component } from '#angular/core';
import {fromEvent} from 'rxjs';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
constructor() {
fromEvent(window,'myEvent').subscribe((e:any) => {
console.log(e.detail);
});
}
}
And out of your angular application (example here : index.ts but can be anywhere)
platformBrowserDynamic().bootstrapModule(AppModule).then(ref => {
// create and dispatch the event
var event = new CustomEvent("myEvent", {
detail: {
foo: 'bar'
}
});
// be sure to dispatch event after you add listener.
window.dispatchEvent(event);
}).catch(err => console.error(err));
online code here