by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Jul 26 05:47
    amithegde commented #20
  • Jul 26 05:46
    amithegde commented #20
  • Jul 06 09:12
    the0rem commented #20
  • Oct 15 2019 16:45
    johannesjo commented #20
  • Sep 21 2019 04:04
    JimTheMan closed #16
  • May 04 2019 00:15
    felixunivers edited #17
  • Apr 29 2019 21:30
    felixunivers opened #17
  • Apr 10 2019 21:15
    rezord opened #16
  • Jan 31 2019 20:44
    alex-okrushko commented #1511
  • Jan 31 2019 20:21
    brandonroberts edited #1538
  • Jan 31 2019 20:20
    brandonroberts edited #1538
  • Jan 31 2019 20:18
    brandonroberts labeled #1538
  • Jan 31 2019 20:18
    brandonroberts labeled #1538
  • Jan 31 2019 20:18
    brandonroberts opened #1538
  • Jan 31 2019 12:11
    timdeschryver closed #1536
  • Jan 31 2019 12:11
    timdeschryver commented #1536
  • Jan 31 2019 12:08
    timdeschryver closed #1537
  • Jan 31 2019 12:08
    timdeschryver commented #1537
  • Jan 31 2019 11:59
    olefrank commented #1036
  • Jan 31 2019 11:59
    olefrank commented #1036
Kevin Taleb Dehkordi
@kebabCase_twitter

Ok I found the problem.

export const reducers: ActionReducerMap<FeatureState> = {
  [fromChoice.featureKey]: fromChoice.reducer,
  [fromCreditsDeclaration.featureKey]: fromCreditsDeclaration.reducer
};

This doesn't work with AOT Compilation.

We should use combineReducers


export function reducers(state: FeatureState | undefined, action: Action) {
  return combineReducers({
    [fromChoice.featureKey]: fromChoice.reducer,
    [fromCreditsDeclaration.featureKey]: fromCreditsDeclaration.reducer
  })(state, action);
}
Derek
@derekkite
@kebabCase_twitter that is strange, I pass actionreducermaps to the StoreModule without issue. It may be the barrel, index.ts that is causing the issue.
Kim Biesbjerg
@biesbjerg
It seems that my on() reducers are not type-safe (I can return state with non-existent keys) - is it supposed to be like that, or am I doing something wrong?
export const reducer = createReducer(
    initialState,
    on(PlayerEngineActions.stateChange, (state, { state: playerState }) => ({
        ...state,
        playerStateWithTypeInKey: playerState
    })),
I need to tack on :State to hint about the function's return value to make it complain, but I don't see that done in examples or in the wild
Using typescript 3.8.3 btw
Kim Biesbjerg
@biesbjerg
Huh, seems its an old issue rooted in TypeScript: https://github.com/microsoft/TypeScript/issues/241#issuecomment-540162369
BertrandMarechal
@BertrandMarechal
@biesbjerg I experienced the same, my way to cover it is with unit testing my reducers
Kim Biesbjerg
@biesbjerg
Yeah, you should probably have unit tests anyhow, but on(PlayerEngineActions.stateChange, (state, { state: playerState }): State => ... works too (notice : State
Tushar Nerkar
@tusharnerkar8_gitlab
I am starting a new ngrx based project. I am following https://itnext.io/ngrx-best-practices-for-enterprise-angular-applications-6f00bcdf36d7 Please let me know is this a right approach?
Another question I have, whenever I see the example of createEntityAdapter, I see all the selectors in reducer file.. why are not they in the selector's file?
Irv
@ilennert
Is the default build ng build an aot build for angular 9?
Tushar Nerkar
@tusharnerkar8_gitlab
I want to combine two different feature store and aggregate it and store the aggregated data into store again as a summary-store (feature store). How should be my flow? I created selector which gives me my aggregated data but, I want to store it back to into the store.
How can I dispatch action from the selector?
Derek
@derekkite
@tusharnerkar8_gitlab why do you want to store it. If you compose the selector it won't fire unless the data changes
Derek
@derekkite
@tusharnerkar8_gitlab if you need to do this, have your action be handled in an effect, getLatestFrom the two stores, put the data together and return an action with the payload
Tushar Nerkar
@tusharnerkar8_gitlab

@tusharnerkar8_gitlab why do you want to store it. If you compose the selector it won't fire unless the data changes

@derekkite that's true, after composing the state from two or more selectors, I need to call another websocket service and keep updating the part of that state

To make this easier I want to store the computed state back into the store. Am I doing it right?

@tusharnerkar8_gitlab if you need to do this, have your action be handled in an effect, getLatestFrom the two stores, put the data together and return an action with the payload

@derekkite Yes this is what I did now. Thanks.

Tushar Nerkar
@tusharnerkar8_gitlab

Hi all,

Am I doing it right?

How can I be sure, the dom rendering happens only for the key getting changed in the store.

My state is as follows. I am getting countries and diseases in array format. I am then using selector to get the hashmap and store it back inside the ngrx store. Now my store looks like below.

Now I have a websocket service which keeps sending me updates int he form [{country: "australia", disease:"corona", count: 30}]
I need to update my appstate.aggregatedSummary['australia']['corona'].count = 30

I need to know your architectural approach to achieve this?

  1. Also I need to make sure, the UI Dom rendering happens only for the one getting changed. So, with above update received from websocket, it should update the dom showing only Australia corona count and not australia flu related dom.
  2. Also the aggregatedSummary should be computed only once

My Approach

What I did is I created selctors

 let aggregatedSelector = createSelector(
    selectCountries,
    selectDiseases,
    (countriesState, diseaseState) => {
        // compute
        return aggregatedSummary
    }
)

Then I dispatched action from component


  aggregateSummary$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SummaryActions.loadSummarySuccess),
      switchMap((_) => {
        return this.store.select(selectAndComposeSummary).pipe(
          map((summaryState) => {
            // saving back to store
            return SummaryActions.saveSummary({summary: summaryState});
          })
        );
      })
    )
  )

My App state is now like below

{
   "countries": [
        {
            "name": "australia"
        },
        {
            "name": "usa"
        }
    ],
   "diseases": [
        {
            "name": "corona";
        },
        {
            "name": "flu";
        }

    ]
  "aggregatedSummary": {
    "australia": {
      "corona": {
        "count": 10
      },
      "flu": {
        "count": 22
      }
    },
    "usa": {
      "corona": {
        "count": 10
      },
      "flu": {
        "count": 22
      }
    }
  }
}
Alex
@alvipeo

hey guys! question on router-store.
I have the url like concerts/edit/some-concert and I need to select some-concert I use:

export const getSelectedConcertFriendlyUrl = selectRouteParam("friendlyUrl");

so this returns some-concert.

and then I have a url when a user edits concert's song - https://localhost:4200/concerts/edit/some-concert/songs/1. in this case the previous selector returns undefined. what am I missing?

Sarthak Rout
@SarthakRout
Hi everyone. There is an issue with importing StoreModule from @ngrx/strore while it is clearly exported there. Also, I am unable to add node-sass properly. I am trying to install the dependencies for this project: https://github.com/UltimateAngular/ngrx-store-effects-app
Martin Chung
@mwchung24
Hi everyone. Is it possible to add data (used in multiple components) to the global store without using a component store?
new to NGRX so any guidance would be helpful :)
John McArthur
@BigBadJock
I'm having an issue with ngrx/data where I'm getting the error: entities.reduce is not a function. Not sure where I'm going wrong.
Alexander Escamilla
@alexesca
@mwchung24 you can dispatch actions from anywhere such as components, services, resolvers, guards, even factories. The global store can be accessed by any component in the application using selectors. I used to add the selectors in my component, but a better approach is creating a service with the sole purpose of getting the data from the store. The component doesn't know about the store, it only knows about this service. It makes your component/view cleaner and keeps the SRP(Single responsibility principle). This should make the first part of your question clear. Then... "...the global store without using a component store?" I believe I answered this at the beginning of my response.
@BigBadJock are you sure you entity/data is registered in the store
?
@alvipeo I hope you are using ngrx to track the routing navigation. Once this is clear, it depends on how you declared your paths and nested routes in your routing module. You should be able to pull each parameter defined in your routes/paths. {component: MyComponent, path: "concerts/edit/:concert/songs/:id"}
dev-ster
@dev-ster
How do you keep your many to many data in a ngrx store in sync when updating or deleting one entity?
Alexander Escamilla
@alexesca
@dev-ster can you explain more?
dev-ster
@dev-ster
@alexesca Sure. Imagine this strucutre.
On the product entity you would store categoryIds and on the category entity you would store productIds
If you delete on product entity it should be reflected in the category entity that still holds that product id inside the productIds array
Derek
@derekkite
@dev-ster both reducers can respond to the same action.
dev-ster
@dev-ster
Can you do that using an array of actions?
// product.reducer.ts
on([ProductActions.deleteProduct, CategoryActions.deleteCategory], (state, action) => { ...
Where do you check if the product should be deleted if a category of a certain id gets deleted?
Derek
@derekkite
in the product reducer, watch for a deletecategory, and edit the products as required. The category reducer would delete the category. Same with a delete product, the category reducer would watch for that action and edit the categories as required.
usually you would have a specific action to delete the many to many data keys
dev-ster
@dev-ster
That means I need to get all the product ids from that category and deleteMany in the product reducer correct?
Derek
@derekkite
Something like that. I don't know how you have set up your keys, but you can iterate through the entities, make a list of ids, and deleteMany.
dev-ster
@dev-ster
Sure I’ll take that approach
How do you normalize your data retrieved from the api?
Derek
@derekkite
Typically I shape the data for the view. Whatever that means, adding, deleting, selectors, ease of posting changes.
dev-ster
@dev-ster

Should .upsertMany() delete ids from a relation property inside the entity?

Imagine a product entity that has categoryIds: [1, 2, 3, 4, 5, 6, 7, 8] as property to reference the categories it belongs to.
If I load products with some other data from some endpoint I can normalize it and send it to the product reducer. This product doesn’t have all categories attached to it as the api has a limit on relations. The categoryIds in the product entity shouldn’t be remove though.
If I load the product with categoryIds: [1, 2, 3, 4, 5] the ids 6, 7, 8 will be removed after upsertMany.

Is that behavior wanted and correct in ngrx?

Derek
@derekkite
@dev-ster no it shouldn't. https://github.com/ngrx/platform/blob/master/modules/entity/src/unsorted_state_adapter.ts#L27 is what gets done.
you could have an instance of the array that is getting modified outside the reducer
Mike Herbert
@mherbert71_twitter
so I have an interesting ‘leak’, where after resetting a property (this property is a complex object) in the state, the state is correctly represented (property and it’s sub-properties), however there is an Object in memory (found using Chrome DevTools -> Memory Heap Snapshot) that still seems to be referenced. thoughts anyone? using @ngrx/store 8.6.0
Derek
@derekkite
@mherbert71_twitter if you have a reference to the object somewhere it won't get rid of it. let p = myobject means p has a reference to myobject.
dev-ster
@dev-ster
Can we combine the selectors to tidy that up?
export const selectAll = createSelectorFactory<{}, Dictionary<OrderView>>(arrayMemoizer)(
        selectEntities,
        UserSelectors.selectEntities,
        DentistSelectors.selectEntities,
        PatientSelectors.selectEntities,
        MaterialSelectors.selectEntities,
        WorkTypeSelectors.selectEntities,
        ToothColorSelectors.selectEntities,
        (
            entities: Dictionary<Order>,
            users,
            dentists,
            patients,
            materials,
            workTypes,
            toothColors
        ) => Object.values(entities).reduce((acc, entity) => {
            if ( entity.completeness === 2 ) acc.push(createOrderView(
                entity,
                users,
                dentists,
                patients,
                materials,
                workTypes,
                toothColors
            ));

            return acc;
        }, [])
    );


    export const selectById = (id: number) => createSelectorFactory<{}, OrderView>(objectMemoizer)(
        selectEntities,
        UserSelectors.selectEntities,
        DentistSelectors.selectEntities,
        PatientSelectors.selectEntities,
        MaterialSelectors.selectEntities,
        WorkTypeSelectors.selectEntities,
        ToothColorSelectors.selectEntities,
        (
            entities: Dictionary<Order>,
            users,
            dentists,
            patients,
            materials,
            workTypes,
            toothColors
        ) => createOrderView(
            entities[id],
            users,
            dentists,
            patients,
            materials,
            workTypes,
            toothColors
        )
    );
It’s redundant
Ohm0n
@thecyberd3m0n_gitlab
Hi people
I have some problems regarding writing tests to ngrx/store based chat library
  fit('should be able to create and join session', async (done) => {
    // let's create session
    dispatchers.init();

    const mainSub = selectors.mode$.subscribe((mode) => {
      if (mode === SecureChatMode.EMPTY) {
        dispatchers.setupProfile({
          name: 'test'
        });
      } else if (mode === SecureChatMode.READY) {
        dispatchers.startSession();
        const pendingSessionsSub1 = selectors.pendingSessions$.subscribe((pendingSessions: PendingSession[]) => {
          if (pendingSessions.length > 0) {
            expect(pendingSessions[0].id).toBeTruthy();
            const id = pendingSessions[0].id;
            mainSub.unsubscribe();
            pendingSessionsSub1.unsubscribe();
            TestBed.resetTestEnvironment();
            dispatchers.init();
            const secondSub = selectors.mode$.subscribe((mode) => {
              debugger;
              if (mode === SecureChatMode.EMPTY) {
                dispatchers.joinSession({ sessionId: id });
                done();
              }
            });
          }
        });
      }
    });
  });

});
That's how test looks like now. The problem is I need 2 instances of store to test creating session and joining to that session