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 🙏

© 2026 – Pkg Stats / Ryan Hefner

ngx-crud-builder

v1.0.2

Published

Angular library for dynamic CRUD generation with configurable routes, forms and views

Readme

ngx-crud-builder

Angular library for dynamic CRUD generation with configurable routes, forms and views.

npm version Angular License: MIT


Table of Contents


Features

  • ✅ Dynamic CRUD route generation
  • ✅ Configurable list, form and detail views
  • ✅ Built-in API service with HTTP methods
  • ✅ Angular Signals support
  • ✅ Zoneless compatible
  • ✅ Angular Material ready
  • ✅ i18n with @ngx-translate

Requirements

| Dependency | Version | | --------------------------------- | --------- | | @angular/core | ^21.0.0 | | @angular/material | ^21.0.0 | | @angular/router | ^21.0.0 | | @ngx-translate/core | ^17.0.0 | | @ngx-translate/http-loader | ^17.0.0 | | @angular/material-luxon-adapter | ^21.0.0 |


Installation

npm install ngx-crud-builder

Setup

1. Configure providers in app.config.ts

Register the library providers and initialize dynamic routes using APP_INITIALIZER. The initializer finds your existing admin route and injects the generated CRUD routes as children, preserving your guards and wrapper components.

import { ApplicationConfig, APP_INITIALIZER } from '@angular/core';
import { provideRouter, Router } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import {
  provideCrudConfig,
  provideCrudSession,
  provideCrudLibrary,
  CrudRouteService,
} from 'ngx-crud-builder';
import { routes, routesConfig } from './app.routes';
import { SessionService } from './session.service';

export function initializeCrudRoutes(crudRouteService: CrudRouteService, router: Router) {
  return () => {
    const crudRoutes = crudRouteService.load({
      role: 'admin',
      items: [...routesConfig],
      includeRole: true,
      editPrefix: 'edit',
    });

    const currentRoutes = router.config;
    const adminRoute = currentRoutes.find((r) => r.path === 'admin');

    if (adminRoute) {
      adminRoute.children = [...(adminRoute.children || []), ...crudRoutes];
      router.resetConfig([...currentRoutes]);
    }
  };
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withInterceptors([YourInterceptor])),
    provideRouter(routes),
    provideCrudConfig({
      endpoint: 'https://api.yourapp.com',
      storage: 'yourStorageKey',
    }),
    provideCrudLibrary(),
    provideCrudSession(SessionService),
    {
      provide: APP_INITIALIZER,
      useFactory: initializeCrudRoutes,
      deps: [CrudRouteService, Router],
      multi: true,
    },
  ],
};

2. Implement CrudSessionService

Provide your own session service by implementing the CrudSessionService interface:

import { Injectable } from '@angular/core';
import { CrudSessionService } from 'ngx-crud-builder';

@Injectable({ providedIn: 'root' })
export class SessionService implements CrudSessionService {
  can(permission: string): boolean {
    // Implement your permission logic here
    return true;
  }
}

3. Styles

For file field components and avatar field components preview, add the following to your global styles file (e.g., styles.css or styles.scss):

@import 'photoswipe/dist/photoswipe.css';

Or in your angular.json file:

{
  "styles": ["node_modules/photoswipe/dist/photoswipe.css"]
}

Usage

Route Configuration

Define your CRUD routes and pass them to crudRouteService.load(). By default, all four actions (index, create, edit, show) are generated. Use actions to restrict which ones are created.

import { CrudRoute } from 'ngx-crud-builder';

export const routesConfig: CrudRoute[] = [
  {
    path: 'users',
    group: 'users',
    endpoint: 'admin/users',
    searchEnabled: true,
    fields: [
      { name: 'name', label: 'Name', type: 'text', required: true },
      { name: 'email', label: 'Email', type: 'email', required: true },
      { name: 'role', label: 'Role', type: 'select', required: true },
    ],
  },
  {
    path: 'products',
    group: 'products',
    endpoint: 'admin/products',
    actions: [{ type: 'index' }, { type: 'create' }, { type: 'edit' }],
    fields: [
      { name: 'name', label: 'Product Name', type: 'text', required: true },
      { name: 'price', label: 'Price', type: 'number', required: true },
    ],
  },
];

The following routes are generated automatically for a users resource:

| Path | Action | Component | | ------------------------- | ------ | ------------ | | admin/users | index | CrudList | | admin/users/create | create | CrudForm | | admin/users/:id/edit | edit | CrudForm | | admin/users/:id/details | show | CrudDetail |


Custom Route Components

Replace the default component for any action by specifying it in the route configuration:

export const routesConfig: CrudRoute[] = [
  {
    path: 'users',
    group: 'users',
    endpoint: 'admin/users',
    actions: [
      { type: 'index' },
      { type: 'create', component: { component: UsersForm, route: '/create' } },
      { type: 'edit', component: { component: UsersForm, route: '/:id/edit' } },
      { type: 'show', component: { component: UsersDetail, route: '/:id' } },
    ],
    fields: [
      { name: 'name', label: 'Name', type: 'text', required: true },
      { name: 'email', label: 'Email', type: 'email', required: true },
    ],
  },
];

Alternatively, define the routes directly in app.routes.ts and they will take precedence over generated ones:

export const routes: Routes = [
  {
    path: 'admin',
    children: [
      { path: 'users/create', component: UsersForm },
      { path: 'users/:id/edit', component: UsersForm, data: { action: 'edit' } },
      {
        path: 'users/:id/details',
        component: DetailModal,
        data: { action: 'show', backRoute: '/admin/users' },
      },
    ],
  },
];

Extending the Crud Base Class

Extend Crud to build custom views. The base class provides access to the API service, route data, signals for loading state, and built-in actions like create, edit, destroy and download.

import { Component } from '@angular/core';
import { Crud } from 'ngx-crud-builder';

@Component({
  selector: 'app-users-list',
  standalone: true,
  template: `
    @if (loading()) {
      <p>Loading...</p>
    } @else {
      <table>
        @for (user of data.items; track user.id) {
          <tr>
            <td>{{ user.name }}</td>
            <td>{{ user.email }}</td>
            <td>
              <button (click)="action({ method: 'edit', params: user })">Edit</button>
              <button (click)="action({ method: 'destroy', params: user })">Delete</button>
            </td>
          </tr>
        }
      </table>
    }
  `,
})
export class UsersListComponent extends Crud {
  override onInit() {
    this.load();
  }

  override onCrudLoad(response: any) {
    this.data = response.data;
  }

  override onCrudLoadError(error: any) {
    console.error('Failed to load users', error);
  }
}

Form Builder

Use crud-form-builder to render a dynamic form from a FormFieldInput[] definition:

import { Component } from '@angular/core';
import { CrudFormBuilderComponent, FormFieldInput } from 'ngx-crud-builder';

@Component({
  selector: 'app-user-form',
  standalone: true,
  imports: [CrudFormBuilderComponent],
  template: `<crud-form-builder [fields]="fields" (onSubmit)="handleSubmit($event)" />`,
})
export class UserFormComponent {
  fields: FormFieldInput[] = [
    { name: 'name', label: 'Full Name', type: 'text', required: true },
    { name: 'email', label: 'Email', type: 'email', required: true },
    {
      name: 'role',
      label: 'Role',
      type: 'select',
      settings: {
        options: [
          { value: 'admin', label: 'Administrator' },
          { value: 'user', label: 'User' },
        ],
      },
    },
    {
      name: 'country',
      label: 'Country',
      type: 'autocomplete',
      settings: {
        catalog: {
          endpoint: 'admin/countries',
          type: 'paginate',
          valueKey: 'id',
          labelKey: 'name',
        },
      },
    },
    {
      name: 'avatar',
      label: 'Avatar',
      type: 'file',
      settings: {
        fileType: 'image/*',
        fileStructure: 'base64',
        maxFileSize: 2,
      },
    },
    {
      name: 'addresses',
      label: 'Addresses',
      type: 'list',
      settings: { addButton: true, removeButton: true },
      children: [
        { name: 'street', label: 'Street', type: 'text', required: true },
        { name: 'city', label: 'City', type: 'text', required: true },
      ],
    },
  ];

  handleSubmit(formValue: any) {
    console.log('Form submitted:', formValue);
  }
}

API Reference

provideCrudConfig(config: CrudConfig)

| Property | Type | Description | | ---------- | -------- | ------------ | | endpoint | string | Base API URL | | storage | string | Storage key |


CrudRoute

| Property | Type | Description | | --------------- | ------------------- | ------------------------------- | | path | string | URL path segment | | group | string | Permission group name | | endpoint | string | API endpoint | | searchEnabled | boolean | Enable search in list view | | fields | FormFieldInput[] | Form fields definition | | filters | FormFieldInput[] | Filter fields for the list view | | actions | CrudRouteAction[] | Override default actions |


CrudRouteService.load(config)

| Property | Type | Description | | ------------- | ------------- | ------------------------------------ | | role | string | Role prefix (e.g. admin) | | items | CrudRoute[] | Routes to generate | | includeRole | boolean | Prefix generated paths with the role | | editPrefix | string | Prefix used for edit routes |


ApiService

| Method | Description | | ------------------------------- | ------------------------------------------------- | | call(request) | Generic HTTP call (GET, POST, PUT, PATCH, DELETE) | | uploadFile(service, formData) | Upload files with progress reporting | | download(service, callback) | Download a file and trigger browser download | | open(service, callback) | Open a file in a new browser tab |


FormFieldInput

All properties are optional. FormFieldInput is a Partial of FormField with settings typed as Partial<FormFieldSettings>.

| Property | Type | Default | Description | | ---------------------- | ---------------------------- | ------------ | ---------------------------------------- | | name | string | '' | Field key in the form value | | label | string | '' | Display label | | type | FieldType | 'text' | Input type | | required | boolean | false | Whether the field is required | | disabled | boolean | false | Whether the field is disabled | | placeholder | string | '' | Placeholder text | | description | string | '' | Hint text shown below the field | | icon | string | '' | CSS class for the prefix icon | | colClass | string | 'col-lg-6' | Bootstrap column class for layout | | customContainerClass | string | '' | Extra CSS class on the field container | | full | boolean | false | Whether the field spans full width | | value | any | — | Initial value | | children | FormFieldInput[] | [] | Nested fields (used in list/complex) | | settings | Partial<FormFieldSettings> | — | Advanced settings (see below) |


FormFieldSettings

| Property | Type | Default | Description | | --------------- | -------------------- | ---------- | ----------------------------------------------------------------------------------------------- | | opened | boolean | false | Allow free-text input in autocomplete fields | | search | string | search | Enable remote search, where search is the query parameter name, to disable search set to '' | | addButton | boolean | true | Show add button (list/complex fields) | | removeButton | boolean | true | Show remove button (list/complex fields) | | full | boolean | false | Full width layout inside the field | | fileType | string | '' | Accepted MIME types or extensions (e.g. 'image/*') | | fileStructure | FileStructureType | 'base64' | File output format: 'base64' or { [fileKey]: File } | | fileKey | string | '' | Key used when fileStructure is object-based | | fetchKey | string | '' | Response key for the stored file value (file/avatar fields) | | fetchLargeKey | string | '' | Response key for a large/preview URL (file fields) | | max | number | — | Maximum value (number fields) | | min | number | — | Minimum value (number fields) | | step | number | — | Step increment (number fields) | | maxFiles | number | 1 | Maximum number of files (file fields) | | maxFileSize | number | 5 | Maximum file size in MB | | options | FormFieldOptions[] | [] | Static options for checkbox, radio and toggle fields | | catalog | Catalog | — | Remote data source config for select and autocomplete fields |


Translations

Add the following keys to your translation file (e.g. public/i18n/en.json):

{
  "crud": {
    "destroy_title": "Delete confirmation",
    "back": "Back",
    "confirm": "Confirm",
    "select_avatar": "Select avatar",
    "form_invalid": "Form is invalid",
    "no_data": "No data",
    "search": "Search",
    "search_placeholder": "Search...",
    "submit": "Submit",
    "fill": "Please fill in the form",
    "select_page": "Select page",
    "hide-password": "Hide password",
    "date_format": "MM/DD/YYYY",
    "date_range_format": "MM/DD/YYYY – MM/DD/YYYY",
    "start_date": "Start date",
    "end_date": "End date",
    "items_per_page": "Items per page",
    "next": "Next",
    "prev": "Previous",
    "first": "First",
    "last": "Last",
    "of": "of",
    "button_close": "Close",
    "file": {
      "max_file_size_error": "File size exceeds the maximum allowed size"
    },
    "message": {
      "error": "An error occurred",
      "created": "Created successfully",
      "updated": "Updated successfully"
    }
  },
  "file": {
    "select": "Select file(s)",
    "selected": "Selected",
    "remove": "Remove",
    "view": "View",
    "download": "Download",
    "error": {
      "maxFiles": "Maximum {max} files allowed",
      "maxSize": "File size exceeds {max}MB limit",
      "type": "Invalid file type"
    }
  }
}

For export file names, add a key following the pattern {role}.{group}.export:

{
  "admin.users.export": "users_export"
}

Changelog

1.0.1

  • Minor style adjustments and autocomplete search improvements

1.0.0

  • Initial release

0.0.5

  • Extended Angular 21 compatibility to support all 21.x.x versions
  • Autocomplete improvements
  • Restructured FormFieldSettings model

⚠️ Breaking Changes

  • catalog, maxFiles, maxFileSize, fileType, fileStructure, max, min, step, addButton, removeButton properties moved from FormField to FormFieldSettings

0.0.4

  • Added FormFieldSettings to FormField model

0.0.3

  • README updated

0.0.2

  • Renamed package from crud-component to ngx-crud-builder
  • Migrated to Angular 21
  • Migrated to inject() API
  • Fixed injection context errors with zoneless change detection

0.0.1

  • Initial release