Code Monkey home page Code Monkey logo

ngrx-normalizr's People

Contributors

hoisel avatar jsantha avatar juanpmarin avatar michaelkrone 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ngrx-normalizr's Issues

State stays empty

Thanks for the great library! Looks super useful. I do have one issue though. I set everything up as in the README, but I am not using Effects() to pass in data, because the data is generated on the client side. So I use myStore.dispatch(new AddData<Data>() to add data.

Looking in ngrx-devconsole I can see that the action is going to the store with the correct payload, but my state does not change. It is always empty ...

I just have this as reducer and state:
export interface TemplateState extends NormalizedState { } export const templateReducer: ActionReducerMap<NormalizedState> = { normalized };

Am I missing anything?

Thanks!
Tom

Allow Entity id to be either a number or a string

Hi Michael,

Thanks for building this library, its been very useful so far.

Would it be possible to add support for entities that identifiers of type number?

E.g.

export class SomeEntity {
  SomeEntityId: number;
  otherEntities: AnotherEntity[]'
}

export class AnotherEntity {
  AnotherEntityId: number;
}

export someEntitySchema = new schema.Entity(
  'SomeEntity', 
  {
    otherEntities: [anotherEntitySchema]
  }, 
  {
    idAttribute: 'SomeEntityId'
  });
export anotherEntitySchema = new schema.Entity('AnotherEntity', {}, idAttribute: 'AnotherEntityId'});

Mostly this already works fine, except that I can't use the provided entityProjecter which throws a typescript error:

Argument of type '(entities: {}, id: string) => SomeEntity' is not assignable to parameter of type '(s1: {}, s2: number)

Normalizr itself seems to support ids being numbers and strings, so I modified the interfaces in ngrx-normalizr/normalize.d.ts to allow for numbers and this works (for me at least):

import { MemoizedSelector } from '@ngrx/store';
import { schema } from 'normalizr';
export interface EntityMap {
    [key: string]: {
        [id: string]: any;
        [id: number]: any;
    };
}
export interface NormalizedState {
    normalized: NormalizedEntityState;
}
export interface NormalizedEntityState {
    result: string[];
    entities: EntityMap;
}
export declare function normalized(state: NormalizedEntityState, action: any): {
    result: any;
    entities: any;
};
export declare const getNormalizedEntities: MemoizedSelector<any, EntityMap>;
export declare const getResult: MemoizedSelector<any, any[]>;
export interface SchemaSelectors<T> {
    getNormalizedEntities: MemoizedSelector<any, EntityMap>;
    getEntities: MemoizedSelector<{}, T[]>;
    entityProjector: (entities: {}, id: string | number) => T;
    entitiesProjector: (entities: {}) => T[];
}
export declare function createSchemaSelectors<T>(schema: schema.Entity): SchemaSelectors<T>;

I can create a pull request for you if you prefer, but I had trouble getting the karma tests to run... so thought I'd just ask in case this would be a simple change for you.

Thanks again,

Cam

RemoveData & RemoveChildData not firing change

Im getting used to this library now.. Thanks for creating this. But, I see that my observables are not fired when I remove data. Not sure if Im doing anything wrong here. AddData fires my observables (this.store.select), but the same doesn't fire when I use RemoveData or RemoveChildData.

Here's what Im trying to do:

Say I have the following data:

export class User {
  id: number;
  name: string;
  tasks: Task[];
}

export class Task {
  id: number;
  name: string;
  comments: Comment[];
}

export class Comment{
  id: number;
  text: string;
}

export const userSchema = new schema.Entity('users');
export const commentSchema = new schema.Entity('comments');
export const taskSchema = new schema.Entity('tasks', { comments: [commentSchema] });

Once I use AddData, I get below normalized data

users: [
  "1": {
    id: "1",
    name: 'Example Task',
    tasks: ["2"]
  }
],
tasks: [
  "2": {
    id: "2",
    name: 'Example Task',
    comments: ["4"]
  }
],
comments: [
  "4": {
    id: "4",
    text: "My Comment",
  }
]

Now, if I want to remove a task from the data and use RemoveChildData({id: "2", taskSchema, userSchema, parentId: "1" }), I can see that it removes the task and reference from the tasks property under users.
If I use RemoveData({id: "2", schema: taskSchema, removeChildren: {comments: 'comments'}}), I see that the task and the related comments are removed.

But in both cases, my this.store.select is not fired.

Add reference to normalized parent when updating normalized child

Hey, thanks for this library, really convenient way to handle normalization with ngrx.
I've got a question or suggestion:

Say you have the following data:

export class Task {
  id: number;
  name: string;
  comments: Comment[];
}

export class Comment{
  id: number;
  text: string;
}

export const commentSchema = new schema.Entity('comments');
export const taskSchema = new schema.Entity('tasks', { comments: [commentSchema] });

When I now initially load the Tasks and use the AddData action, the data gets normalized into something like this (example):

tasks: [
  "1": {
    id: "1",
    name: 'Example Task',
    comments: ["4"]
  }
],
comments: [
  "4": {
    id: "4",
    text: "My Comment",
    taskId: "1"
  }
]

This is all fine.

But when I now add a new Comment and receive the response from the server, for example:

{
  id: "8",
  text: "Second Comment",
  taskId: "1"
}

and then use AddData again, it'll probably only get added to the normalized comments array and not added to tasks["1"].comments.

How it should look in the end:

tasks: [
  "1": {
    id: "1",
    name: 'Example Task',
    comments: ["4", // "8" <-- How to add this]
  }
],
comments: [
  "4": {
    id: "4",
    text: "My Comment",
    taskId: "1"
  },
  "8": {
    id: "8",
    text: "Second Comment",
    taskId: "1"
  },
]

Is there any way to achieve this? Or how is one supposed to achieve this behaviour? Sure, it's possible to query the tasks again, with the updated relations, but wouldn't this be a bit overkill? I think there should be a way to achieve this and I think it would be great if this would be possible with this lib (or maybe it already is?).

Hope you can point me in the right direction! ๐Ÿ‘

Deleting items does not remove them from the parent

Hi,

The issue persist, When using RemoveChildData it's deleted well the child but the reference inside the parent still there.

Before Remove child Data

screen shot 2018-06-04 at 11 53 55 am

After Remove child data

screen shot 2018-06-04 at 11 53 44 am

As we can see the group schema inside Policy still have the id.

Thank you.

RemoveData while using ngrx-store-freeze

Hi, we are using ngrx-store-freeze to keep our state from mutating accidentally. While active the following line in the REMOVE_DATA reducer throws an error: delete entities_3[key][id];. I think what happens is __assign({}, state.entities) assigns all the entity keys and the entity dictionaries are still frozen. One would probably have to use an approach similar to lodashs .omit(entities[key], [id]).

Upsert Function

Hi,

I have trouble using the library for the following case. When using entities I have access to the createEntityAdapter upsert and uspertMany.

Scenario:

export interface Post {
    id: number;
    author?: Author[];
}

export interface Author {
    id: number;
}
export const authorSchema = new schema.Entity('author');
export const PostSchema = new schema.Entity('Post', {
    author: [authorSchema]
});

I am able to insert child Author to the Post. However I have a case where I am inserting the author if it's doesn't exist inside the Post and if existing I want to update these specific Author(s) with the value (basically an upsertMany or upsert). Today when using AddChildData the value is updated however the normalised reference is inserted 2 times (Eg. In post I got author[132,132]).

The question shouldn't be useful to have an uspertMany an upsert function?

Thank you

How do you link the feature selector with the schema selector?

I cannot understand how I can create a selector to get the feature entities.
Trying to get them using the schemaSelectors.getEntities selector throws an error:
ERROR TypeError: Cannot read property 'entities' of undefined
at normalize.js:99
at store.js:577
at memoized (store.js:519)
at defaultStateFn (store.js:546)
at store.js:585
at memoized (store.js:519)
at store.js:545
at Array.map ()
at defaultStateFn (store.js:545)
at store.js:585

import {
  ActionReducerMap,
  createFeatureSelector
} from '@ngrx/store';
import {
  NormalizedState,
  normalized,
  createSchemaSelectors
} from 'ngrx-normalizr';
import { Section } from '../../models/section.model';
import { sectionSchema } from '../../schemas/section.schema';

export interface ReportingState extends NormalizedState {
}

export const reducers: ActionReducerMap<NormalizedState> = {
  normalized
};

export const getReportingState = createFeatureSelector<ReportingState>(
  'reporting'
);

export const getReportingSchemaSelectors = createSchemaSelectors<Section>(sectionSchema);

export const getSectionEntities = createSelector(
  fromFeature.getReportingState,
  fromFeature.getReportingSchemaSelectors.getEntities
);

Schemas break the rule of actions being serializable

Normalizr's schema objects aren't serializable.

Instead of having the action hang on to the schema and doing the normalization in the reducer, the normalization should be done in the action's constructor (just like a classic action creator) which then puts the normalized entities in the action's payload. That way, the action is completely serializable at the time it's dispatched.

Updating partial data

If I want to update a certain value (or values) in an object (whether the top-level, a child, or a grandchild), what is the preferred option? If I pass the ID and the name/value of the property and use the Add/Set methods, then any other properties that I'm not passing are removed.

@ngrx/entity (https://github.com/ngrx/platform/blob/master/docs/entity/adapter.md) has update methods which take a Partial<T> to only update the changes - have you considered something similar?

issue or question : How to work in feature module with feature store

Hi and great job for this library !

All is fine, except i can't work with ngrx-normalizr "selectors" correctly when i put it in a feature module.

Example :
I have a store made of 2 feature modules (user and templates), so the root store structure is like this :

{
user : IUser,
templates : {normalized, other props...}
}

So, in my template feature module, i define selectors like this :

const templateFeatureSelector = createFeatureSelector<template_state.ITemplates>('templates');
/** 
 * Get all templates
*/
const templateSchemaSelector = createSchemaSelectors<template_model.ITemplate>(template_model.schemas);
const getAllTemplates = createSelector(templateFeatureSelector,templateSchemaSelector.getNormalizedEntities, templateSchemaSelector.entitiesProjector);

and then in the feature module component, i do this to get all "templates" :

constructor(private store: Store<any>) {
    this.templates$ = this.store.select(templates_selectors.templates.getAllTemplates);
    this.templates$.subscribe((data) => {
      let a = 0;
    });

  }

It doesn't work since the data value in "subscribe" is always returnin the "full" store object.

After few tests, i get that in my selector the input of "createFeatureSelector" is never take into account, it is always ignored.
So, in normalizr.js, the "state" passed to the "getNormalizedState" selector is alway the root Store (with both "user" and "templates" parts) and never the feature module store (only "templates" part)

At this time, the only workaround i found is to do this when i want to select data in my component :
this.templates$ = this.store.select(templates_selectors.templates.feature).select(templates_selectors.templates.getAllTemplates);
==> I must first select the "feature" store slice, then obtain the correct store, then select against this store with ngrx-normalizr "createSchemaSelector" utility to get my data.

Is this by design or am I wrong ?

Thank you

Why normalize is called in the action creator

This more than a issue is a question, but I did not find where to put it
I other implementations using normalizr why saw that they use normalize at the reducer instead of the action creator, why did you decide to call it there ?

Deleting items does not remove them from the parent

When I delete something from my store using the RemoveData-action the item gets deleted from the store, but the reference from the parent does not get removed.

Examples

{ "id": "page1", "sections": [{ "id": "section1" }] }
normalizr turns this into:

{ normalized: { result: [ 'page1' ], entities: { sections: { sektion1: { id: 'sektion1' } }, pages: { seite1: { id: 'seite1', sections: ['sektion1'] } } } }

Now I run this.store.dispatch(new RemoveData({ id: section.id, schema: sectionSchema })); which leads to the following state:
{ normalized: { result: [ 'page1' ], entities: { sections: { }, pages: { seite1: { id: 'seite1', sections: ['sektion1'] } } } }

Which obviously breaks the code then ... any ideas why this is happening?

Remove all action

Following on from #26 which mentions @ngrx/entity (https://github.com/ngrx/platform/blob/master/docs/entity/adapter.md) and its support for updating partial data, it may also be useful to have the equivalent of its 'removeAll' action so that all the normalized entities can be cleared out without needing to call RemoveData multiple times with all the individual IDs

I suppose different users might have different requirements - for some it could be to empty everything, for others it could be to specify a certain key and only empty that and all its children (although in that case I guess it could get a bit messy if the children were shared with other parent entities that had a different key that weren't being cleared).

Feature and Root normalized state

Hi,

I've an existing app using your library with the normalized reducer in the root app module. I'm now trying to add normalized state to a feature module, while also keeping the root normalized state.

To enable the normalizing reducer to store normalized data, you have to add it to your state. The best place for this might be the root state of your application, but feature states may use their own normalized state as well.

My feature module's state extends NormalizedState and I've added the normalized reducer to my reducer map.

How do I ensure that the schema bound actions are only picked up in the feature state? At the moment both the root and the feature normalized reducers are handling schema bound actions, resulting in duplicated state in the store.

Thanks!

Cam

NormalizeActionConfig error

Say, I have below schema

import { schema } from 'normalizr';

export class Foo {
	id: string;	
}
// schema
export const fooSchema = new schema.Entity('foo');

And my api call returns a single object.

{
id: '1'
}

when I do a new AddData<Foo>({ data, fooSchema }) in my @effect, I get below error.

Is this a version problem? I am on @ngrx/store 5.0.0

[ts]
Argument of type '{ data: Foo; fooSchema: Entity; }' is not assignable to parameter of type 'NormalizeActionConfig<Foo>'.
  Object literal may only specify known properties, and 'fooSchema' does not exist in type 'NormalizeActionConfig<Foo>'.

Best practice: add nested child

Hi,

I have a question on best practice of using ngrx-normalizr. If I want to add a child to a deeper nested element, how would you do it?

My element looks like this:

{ "id": "page1", "sections": [{ "id": "section1", "fields": [{ "id": "field1" }] }] }

Now I want to add a new field and of course I have to tell the storage, that I want the new field, within section1, within page1. During updating this is not a problem, since all ids are unique. But when adding I have to tell the store at least the section.

When adding a field using AddAction<Field> it gets added correctly but not linked to any section. How do you solve this in the best way? Adding the field and then linking it to a section? Or basically by taking the section, adding the field to the section and then "updating" the whole section.

Thanks!
Tom

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.