npm.io
2.1.0 • Published 3d ago

ngx-crud-builder

Licence
Version
2.1.0
Deps
1
Size
620 kB
Vulns
0
Weekly
0

ngx-crud-builder

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

npm version Angular License: MIT


Table of Contents


Compatibility

ngx-crud-builder Angular Version
2.x.x Angular 22+
1.x.x Angular 21
0.0.x Angular 20 / 21

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 ^22.0.0
@angular/material ^22.0.0
@angular/router ^22.0.0
@ngx-translate/core ^18.0.0
@ngx-translate/http-loader ^18.0.0
@angular/material-luxon-adapter ^22.0.0
bootstrap ^5.3.8
class-transformer ^0.5.1
ngx-quill ^31.0.1
photoswipe ^5.4.4
reflect-metadata ^0.2.2
sprintf-js ^1.1.3

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 { provideRouter, Router } from '@angular/router';
import { ApplicationConfig, APP_INITIALIZER } from '@angular/core';
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

Add to your styles.scss:

@import 'ngx-crud-builder/styles';

Or in your angular.json file:

{
  "styles": ["node_modules/ngx-crud-builder/src/styles/index.scss"]
}

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 onLoadSuccess(response: any) {
    this.data = response.data;
  }

  override onLoadError(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);
  }
}
Styles

The library provides a default style for the OTP field. If you want to customize it, you can override the .otp-input class in your global styles.

Add styles to styles.scss to include default classes

@import 'ngx-crud-builder/styles';
Variables

The library uses the following CSS variables that you can override in your global styles:

:root {
  /* Fields */
  --form-divider-height: 1px;
  --form-divider-color: gray;
  --form-divider-opacity: 0.25;

  /* File Field */
  --file-field-border-radius: 8px;

  /* OTP Input */
  --otp-input-width: 36px;
  --otp-input-height: 36px;
  --otp-input-border-radius: 8px;
  --otp-input-border-color: #d0ccca;
  --otp-input-border-width: 1px;
  --otp-input-border-style: solid;
  --otp-input-border-color-focus: #007bff;
  --otp-input-border-width-focus: 2px;
  --otp-input-border-style-focus: solid;
}
Classes

The library uses the following CSS classes that you can override in your global styles:

  • .autocomplete-field - Autocomplete field container
  • .avatar-field - Avatar field container
  • .checkbox-group-field - Checkbox group field container
  • .crud-required - Required field indicator (*)
  • .date-field-container - Date field container (Bootstrap theme)
  • .date-field-icon - Date picker icon (Bootstrap theme)
  • .date-field - Date field container
  • .file-field-actions - File field actions
  • .file-field-add-btn - File field add button
  • .file-field-button-col - File field button column
  • .file-field-card - File field card
  • .file-field-item-caption - File field item caption
  • .file-field-item-col - File field item
  • .file-field-item-media - File field item media
  • .file-field-item-remove-btn - File field item remove button
  • .file-field-item - File field item
  • .file-field-label - File field label
  • .file-field-single-file-name-container - File field single file name container
  • .file-field-single-file-name - File field single file name
  • .file-field - File field container
  • .form-divider-label - Form divider label
  • .form-divider - Form divider
  • .form-field-description - Form field description
  • .form-field-icon - Form field icon
  • .form-field-error - Form field error feedback
  • .form-field-subtitle - Form field subtitle
  • .form-field-title-container - Form field title container
  • .form-field-title - Form field title
  • .form-field - Form field container
  • .form-html-editor-field - Form HTML editor field
  • .html-field - HTML field container
  • .list-field - List field container
  • .month-year-field - Month year field container
  • .multiple-autocomplete-field - Multiple autocomplete field container
  • .otp-input - OTP input field
  • .password-field - Password field container
  • .select-field - Select field container
  • .simple-field - Simple field container
  • .toggles-group-field - Toggles group field container

API Reference

provideCrudConfig(config: CrudConfig)
Property Type Description
endpoint string Base API URL
storage string Storage key
iconClass string Icon class prefix (default: fa-light)
routes string[] Additional route paths to include
theme CrudTheme UI theme (default: material)

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 ''
search_placeholder string search Placeholder for the search input
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)
maxString string Maximum value as string (date fields)
minString string Minimum value as string (date fields)
pattern string Regular expression pattern for validation (text fields)
inputmode string Input mode for mobile keyboards (text fields)
uppercase boolean false Convert input to uppercase (text fields)
lowercase boolean false Convert input to lowercase (text fields)
step number Step increment (number fields)
size number 5 Size of the OTP field (OTP 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
preview boolean true Show preview for file fields
catalog Catalog Remote data source config for select and autocomplete fields
feeback boolean false Show feedback message for the field
validator RegExp Regular expression for validation (text fields)
partialValidator RegExp Partial validation pattern (text fields)

Translations

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

{
  "crud": {
    "file": {
      "max_file_size_error": "File size exceeds the maximum allowed size",
      "max_files_error": "Maximum number of files exceeded",
      "file_error": "Error processing file"
    },
    "message": {
      "error": "An error occurred",
      "created": "Created successfully",
      "updated": "Updated successfully"
    },
    "validations": {
      "form_invalid": "Form is invalid",
      // CUSTOM MESSAGES FOR VALIDATIONS
      "required": "This field is required.",
      "minlength": "Must have at least {{requiredLength}} characters.",
      "pattern": "Invalid format or missing uppercase/number.",
      "invalid_format": "Invalid format",
      "invalid_characters": "Invalid characters",
      "mismatch": "Passwords do not match."
    },
    "cruds": {
      "expiry": {
        "invalid_month": "Invalid month",
        "expired": "Card has expired"
      }
    },
    "back": "Back",
    "button_close": "Close",
    // Button to close snack message
    "button_close_x": "Close",
    "cancel": "Cancel",
    "confirm": "Confirm",
    "destroy_title": "Delete confirmation",
    "end_date": "End date",
    "fill": "Please fill in the form",
    "first": "First",
    "hide-password": "Hide password",
    "items_per_page": "Items per page",
    "last": "Last",
    "next": "Next",
    "no_data": "No data",
    "of": "of",
    "prev": "Previous",
    "search_placeholder": "Search...",
    "search": "Search",
    "select_avatar": "Select avatar",
    "select_page": "Select page",
    "start_date": "Start date",
    "submit": "Submit"
  },
  "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

2.1.0

  • Added feedback setting to show feedback message for fields
  • Added validator Regex for validation pattern

2.0.0

  • Angular 22 support

1.2.2

  • Form field hint class added for material theme hints, improving styles and angular 22 compatibility.
1.2.1
  • File field styling improvements
1.2.0
  • Month year field added and otp paste support
1.1.60
  • Pagination fixed
1.1.51
  • Date field fixed
1.1.5
  • Avatar delete button added
  • Global styles added
  • Added inputmode, pattern, uppercase, and lowercase settings
  • Date field improvements
  • Icon class configuration added
Breaking Changes
  • Renamed onCrudLoadonLoadSuccess and onCrudLoadErroronLoadError
  // Before
  override onCrudLoad(response: any) { ... }
  override onCrudLoadError(error: any) { ... }

  // After
  override onLoadSuccess(response: any) { ... }
  override onLoadError(error: any) { ... }
1.1.4
  • Added minString and maxString string properties for date field validation
  • Form validation messages improved
1.1.3
  • Added cancel label to destroy dialog
1.1.2
  • Bootstrap theme support added
  • OTP field added
1.0.2
  • Minor style adjustments
  • Autocomplete search improvements
1.0.0
  • Stable release
0.0.5
  • Extended Angular 21 compatibility to all 21.x.x versions
  • Autocomplete improvements
  • Restructured FormFieldSettings model
Breaking Changes
  • Moved properties from FormField to FormFieldSettings: catalog, maxFiles, maxFileSize, fileType, fileStructure, max, min, step, addButton, removeButton
  // Before
  { name: 'file', type: 'file', maxFiles: 3, fileType: 'image/*' }

  // After
  { name: 'file', type: 'file', settings: { maxFiles: 3, fileType: 'image/*' } }
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