ng-on-rest-core
TypeScript icon, indicating that this package has built-in type declarations

1.0.0-alpha.0 • Public • Published

ng-on-rest-core

This module allows you to transform your angular application in a REST admin

First of all you need to install the dependency using yarn or npm.

  npm install ng-rest-core -S
  yarn add ng-rest-core

The package comes with different bundles

  • umd
  • esm5
  • esm2015

Thanks to ng-packagr. So feel free to use what suits you best.

Additionaly, you will find typedoc documentation in docs folder.

Usage

Configuration


First, the module must be imported

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgorCoreModule } from 'ng-on-rest-core';
import { AppComponent } from './components/app.component';
import { CreatePostComponent } from './components/create-post.component';
import { DeletePostComponent } from './components/delete-post.component';
import { EditPostComponent } from './components/edit-post.component';
import { PostsComponent } from './components/posts.component';

@NgModule({
  bootstrap: [AppComponent],
  declarations: [
    AppComponent,
    PostsComponent,
    CreatePostComponent,
    DeletePostComponent,
    EditPostComponent,
  ],
  entryComponents: [
    PostsComponent,
    CreatePostComponent,
    DeletePostComponent,
    EditPostComponent,
  ],
  imports: [
    BrowserModule,
    NgorCoreModule.forRoot({
      resources: [
        {
          components: {
            create: CreatePostComponent,
            delete: DeletePostComponent,
            detail: EditPostComponent,
            list: PostsComponent,
          },
          endPoint: 'http://jsonplaceholder.typicode.com',
          name: 'posts',
        },
      ],
    }),
  ],
})
export class AppModule { }

Let's see what this code does

NgorCoreModule.forRoot({
  resources: [
    {
      components: {
        create: CreatePostComponent,
        delete: DeletePostComponent,
        detail: EditPostComponent,
        list: PostsComponent,
      },
      endPoint: 'http://jsonplaceholder.typicode.com',
      name: 'posts',
    },
  ],
}),

It imports NgorCoreModule with posts resource served by JSONPlaceholder.

You tell the module what component to display on each administrative action.

The application router is configured this way

posts => PostsComponent

posts/create => CreatePostComponent

posts/{id} => EditPostComponent

posts/{id}/delete => DeletePostComponent

By default router will display a NgorBaseComponent on each route matching pattern

:resource/:stepOrId?/:step?

This component will look in resource component lists. 2 possibilities

1. :resource parameter only is present => it takes list component

2. :stepOrId parameter is present => 2 new possibilities

1. :stepOrId parameter matches a components list key => it takes key component

2. :stepOrId parameter does not match a component key => it takes it as an id, request corresponding entity and 2 new possibilities

1. :step parameter is missing => it takes detail component

2. :step parameter is present => it takes component matching step

If the component to display is not found or if the request fails, base component will prevent route of activate.

If it founds the component, it's dynamically compiled. This is why you need to add entryComponenents.

entryComponents: [
  PostsComponent,
  CreatePostComponent,
  DeletePostComponent,
  EditPostComponent,
],

list key is mandatory for a resource detail is optional if no detail but mandatory for route :resource/:id create is optional but used by convention by other modules ``delete` is purely specific here so feel free to add your steps

components: {
  create: CreatePostComponent,
  delete: DeletePostComponent,
  detail: EditPostComponent,
  list: PostsComponent,
  myStep: MyStepComponent,
},

MyStepComponent will be loaded for routes posts/myStep && posts/:id/myStep so be aware of that and take care of your links && guards.

Your first component


Let's see PostsComponent

import { Component, OnInit } from '@angular/core';
import { INgorGenericClient, INgorListComponent, INgorResource } from 'ng-on-rest-core';
import {
  IPostCreateDto,
  IPostDto,
  IPostParams,
  IPostQueryParams,
  IPostUpdateDto,
} from '../interfaces/dtos/posts';

@Component({
  selector: 'posts',
  template: `
    <h1>Posts</h1>
    <header class="d-flex justify-content-end mb-5">
      <a class="btn btn-primary" routerLink="create">
        Create
      </a>
    </header>
    <table class="table">
      <thead>
        <tr>
          <th>id</th>
          <th>userId</th>
          <th>title</th>
          <th></th>
          <th></th>
        </tr>
      </thead>
      <tfoot></tfoot>
      <tbody>
        <tr *ngFor="let post of posts">
          <td>{{post.id}}</td>
          <td>{{post.userId}}</td>
          <td>{{post.title}}</td>
          <td>
            <a class="btn btn-secondary" [routerLink]="post.id + '/delete'">
              Delete
            </a>
          </td>
          <td>
            <a class="btn btn-secondary" [routerLink]="post.id">
              Edit
            </a>
          </td>
        </tr>
      </tbody>
    </table>
  `,
})
export class PostsComponent
  implements INgorListComponent<IPostQueryParams, IPostParams, IPostCreateDto, IPostUpdateDto, IPostDto>, OnInit {
  public resource: INgorResource<IPostQueryParams, IPostParams, IPostCreateDto, IPostUpdateDto, IPostDto>;
  public client: INgorGenericClient<IPostQueryParams, IPostParams, IPostCreateDto, IPostUpdateDto, IPostDto>;
  public posts: IPostDto[];

  public ngOnInit() {
    this.client.query({
      _end: 5,
      _start: 0,
    })
      .then((p) => this.posts = p);
  }
}

My pretty much concise advice to avoid verbosity.

  type PostResource = INgorResource<IPostQueryParams, IPostParams, IPostCreateDto, IPostUpdateDto, IPostDto>;
  type PostClient = INgorGenericClient<IPostQueryParams, IPostParams, IPostCreateDto, IPostUpdateDto, IPostDto>;
  type PostListComponent = INgorListComponent<IPostQueryParams, IPostParams, IPostCreateDto, IPostUpdateDto, IPostDto>;


  class PostsComponent implements PostListComponent, OnInit {
    public resource: PostResource;
    public client: PostClient;
    public posts: IPostDto[];

    public ngOnInit() {
      this.client.query({
        _end: 5,
        _start: 0,
      })
        .then((p) => this.posts = p);
    }
  }

You'll easily understand that CreatePostComponent, DeletePostComponent and EditPostComponent are similar and implements respectively INgorStepComponent, INgorEntityDetailComponent and INgorEntityStepDetailComponent.

Advanced usages


If your requests need to be authenticated, you can provide an AuthentcatedHttp.

import { HttpClient, HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthenticatedHttp extends HttpClient {
  constructor(handler: HttpHandler) {
    super(handler);
  }

  public request<R>(req: HttpRequest<any>): Observable<HttpEvent<R>> {
    // Modify request to add authorization here
    return super.request(req);
  }
}

// ...

NgorCoreModule.forRoot({
  provideHttp: {
    provide: HttpClient,
    useClass: AuthenticatedHttp,
  },
})

By default ng-on-rest use NgorGenericClient from ngx-resource-core as REST connector and NgorGenericHandler as REST handler. If it does not fit your needs, you can provide your own GenericClient and your own GenericHandler. The only constraint is to implements INgorGenericClient and INgorGenericHandler interfaces. Mandatory properties of these interfaces are used in the core module and optional by other modules.

import { INgorGenericClient } from 'ng-on-rest-core';

export class MyGenericClient<Query, Params, EntityCreateDto, EntityUpdateDto, EntityDto>
  implements INgorGenericClient<Query, Params, EntityCreateDto, EntityUpdateDto, EntityDto> {
    // ... Your implementation
}
import { INgorGenericHandler } from 'ng-on-rest-core';

export class MyGenericHandler implements INgorGenericHandler {
    // ... Your implementation
}

These classes are not @Injectable decorated as provided by factories. You'll have to provide these factories

function myGenericHandlerFactory(deps1, deps2) { // Your deps here
  return () => new MyGenericHandler(deps1, deps2);
}
function myGenericClientFactory(deps1, deps2) { // Your deps here
  // endpoint provided by the resource
  return (endPoint: string) => new MyGenericClient(deps1, deps2, endPoint);
}
import { NGOR_GENERIC_CLIENT_FACTORY, NGOR_GENERIC_HANDLER_FACTORY, NgorCoreModule } from 'ng-on-rest-core';

// ...

NgorCoreModule.forRoot({
  provideGenericClientFactory: {
    provide: NGOR_GENERIC_CLIENT_FACTORY,
    useFactory: myGenericClientFactory,
    deps: [DEPS1, DEPS2], // Your deps here
  },
  provideGenericHandlerFactory: {
    provide: NGOR_GENERIC_HANDLER_FACTORY,
    useFactory: myGenericHandlerFactory,
    deps: [DEPS1, DEPS2], // Your deps here
  },
});

Package Sidebar

Install

npm i ng-on-rest-core

Weekly Downloads

17

Version

1.0.0-alpha.0

License

MIT

Last publish

Collaborators

  • paulsouche