npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@guillotinaweb/ngx-state-traverser

v1.5.4

Published

NgRX state/actions/reducers for angular-traversal

Downloads

20

Readme

ngx-state-traverser

Build Status

ngx-state-traverser brings angular-traversal power to (ngrx)[https://ngrx.io/].

Principle

Most of modern apps uses routing.

Routes are declared locally (like /posts/{{id}}), they are mapped to components (PostComponent), those components get the necessary information from the route and its parameters (like /posts/2 is parsed as posts + 2 so we deduce the id 2 is a post id) in order to build the appropriate backend endpoint (probably something quite close to https://my-backend.net/posts/2). The backend response might contain an attribute like relatedPost: "/posts/10"), so in the template we can display a link like <a routerLink="/posts/10">.

Routes are not flexible (all the posts are supposed to be accessed with the /posts prefix), but even more annoyingly, they implies we know in advanced what will be the returned resource for a given link in order to render it properly.

That's the opposite of web. When navigating on the web, any link might lead to any kind of resource (maybe another page? maybe a file? we don't know, and the browser does not need to know in advanced), at the time we click and then load the resource, depending on its type, the browser will behave accordingly.

Traversing replaces routing by implementing the same principle. Instead of mapping routes to components, we map resource types to component, and when we load the resource (whatever it is), we use the appropriate component to render it.

It also allows to map several views for a given type (like the @@edit view for a post will use a different component than the default view).

See angular-traversal for more details.

ngx-state-traverser stores each traversed context in a the TraverserState. It contains the current context and a collection of all the previously traversed pathes.

Type mapping

We declare some views for our data type (view is the default view name):

traverser.addView('view', 'post', PostComponent);
traverser.addView('edit', 'post', EditPostComponent);
traverser.addView('view', 'user', UserProfileComponent);

And we connect traversing to our state:

this.store.dispatch({ type: TraverserActions.Types.Watch});

Then the app is able to expose the following pathes:

  • http://localhost:4200/introduction
  • http://localhost:4200/introduction/@@edit
  • http://localhost:4200/2019/07/new-post
  • http://localhost:4200/eric

(assuming the backend exposes /introduction, 2019/07/new-post, and /eric as posts and user profile)

The <traverser-outlet></traverser-outlet> will load the current context according the current path, and instanciate the component corresponding to the context type (and view).

Navigate

Any template might contain some links like:

<a traverseTo="/2019/07/new-post">
<a [traverseTo]="relatedPost">
<a traverseTo="..">

Note: here and later on, the provided link can be either a full path (/2019/07/new-post), a relative path (../eric), or a backend URL (https://my-backend.net/introduction).

In code, we can navigate by dispatching an action:

this.store.dispatch(new TraverserActions.Traverse('../eric'))

Get the current context

The component gets the context from the state.

We can be the raw context (any) using the getContext selector:

context = this.store.pipe(select(TraverserSelectors.getContext));

But the TraverserContext function allows to get a typed context:

context = TraverserSelectors.TraverserContext<UserProfile>(this.store);

State-first resolver

Our angular-traversal resolver is triggered everytime we traverse to a given path. A typical implementation would just make the corresponding backend call to get the object.

As ngx-state-traverser stores all the traversed objects in TraverserState, we could use it as a cache ervider.

To do so, we just need to put the @StateResolver decorator on our resolve method. Example:

@StateResolver({
    maxAge: 60 * 1000,
})
resolve(path: string, view: string, queryString?: string): Observable<any> {
    const headers = new HttpHeaders()
        .append('Accept', 'application/json')
        .append('Content-Type', 'application/json');
    return this.http.get(this.backend + path, { headers });
}

This decorator will return the requested object from TraverserState (if iterists).

maxAge parameter allows to force backedn call if the stored object is older than maxAge. It is optional, if not defined, stored objects are systematically used.

Important: @StateResolver will only work if we inject a TraverserState store (named store) in our Resolver service. The StateFirst interface will make sure it is the case (er will require store to be public).

Accessing other resources

Sometimes the current context does not contain all the information we need.

Let's say we need the list of all the posts from the current month when displaying a given post.

We can get the folder content from the state:

folder = TraverserSelectors.TraverseTo<Folder>(this.store, '..');

Assuming the current context path is /2019/07/10, it retrieves the content of /2019/07.

All the traversed resources are stored in the state, but if the requested resource is not yet in the state, the TraverserResource() function will load it from backend.

As the state acts as a cache system, it can be cleaned on demand:

this.store.dispatch(new TraverserActions.CleanTraverserResources(['../eric', '/2019/*']))

And it can be updated:

this.store.dispatch(new TraverserActions.UpdateTraverserResource({
    path: '/2019/07/03',
    changes: {
        title: "New title"
    }
}));

Tiles

angular-traversal allows to manage the main page view.

Since version 1.3.0, it also allows to define small blocks within the current page (named "tiles").

See the angular-traversal documentation for more details.

We can load a context in a tile by doing:

this.store.dispatch(new TraverserActions.LoadTile({tile: 'details', path}));

and remove it by doing:

this.store.dispatch(new TraverserActions.EmptyTile({tile: 'details'}));

NgRX state

Due to a bug in NgRX 9.0, we need to set strictStateImmutability and strictActionImmutability to false.

StoreModule.forRoot({}, { runtimeChecks: {
    strictStateImmutability: false,
    strictActionImmutability: false,
}}),