packages/data/src/lib/crud/crud.component.ts
The CrudComponent takes at least a model name to render an entry list with create/edit/delete functionality out of the box.
```html
OnInit
WithLoader
WithNotifications
selector | ec-crud |
templateUrl | ./crud.component.html |
Properties |
Methods |
|
Inputs |
Outputs |
constructor(sdk: SdkService, auth: AuthService, loaderService: LoaderService, modelConfig: ModelConfigService, notificationService: NotificationsService, symbol: SymbolService, cdr: ChangeDetectorRef, router: Router, route: ActivatedRoute)
|
||||||||||||||||||||||||||||||
Parameters :
|
config | |
Type : CrudConfig<EntryResource>
|
|
Default value : {}
|
|
CrudConfig for customization of the crud's UI. |
model | |
Type : string
|
|
The model that should be crud'ed. |
selection | |
Type : Selection<EntryResource>
|
|
The selection that should be used |
columnClicked | |
Type : EventEmitter<any>
|
|
Emits when a list element is clicked |
selected | |
Type : EventEmitter<any>
|
|
Emits when the selection has changed |
Public hasMethod | ||||||
hasMethod(method: string)
|
||||||
Returns true if the given method is part of the methods array (or if there is no methods array)
Parameters :
Returns :
boolean
|
Private loadEntry | ||||
loadEntry(item)
|
||||
Loads the clicked entry item, depending on the configured levels. Reloads the entry if the form has fields the which list has not.
Parameters :
Returns :
any
|
Public mustReload | ||||
mustReload(item)
|
||||
Returns true if the visible fields in the list differ from the visible fields in the form
Parameters :
Returns :
boolean
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
Public selectEntry | ||||
selectEntry(item)
|
||||
Is called when an item in the list is clicked.
Parameters :
Returns :
void
|
entryPop |
Type : EntryPopComponent
|
Decorators :
@ViewChild(EntryPopComponent, {static: true})
|
The Pop inside the template. |
list |
Type : EntryListComponent
|
Decorators :
@ViewChild(EntryListComponent)
|
The EntryList inside the template. |
loader |
Type : LoaderComponent
|
Decorators :
@ViewChild(LoaderComponent, {static: true})
|
The lists loader |
notifications |
Type : Notification[]
|
Default value : []
|
Emitted Notifications |
Public route |
Type : ActivatedRoute
|
Decorators :
@Optional()
|
Public router |
Type : Router
|
Decorators :
@Optional()
|
import { Component, EventEmitter, Input, OnInit, Optional, Output, ViewChild, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { CrudConfig } from './crud-config.interface';
import { EntryListComponent } from '../entry-list/entry-list.component';
import { SdkService } from '../sdk/sdk.service';
import { Selection } from '@ec.components/core';
import { LoaderComponent } from '@ec.components/ui';
import { NotificationsService, LoaderService } from '@ec.components/ui';
import { AuthService } from '../auth/auth.service';
import { EntryPopComponent } from '../entry-pop/entry-pop.component';
import { WithLoader } from '@ec.components/ui';
import { Notification, WithNotifications, SymbolService } from '@ec.components/ui';
import { ModelConfigService } from '../model-config/model-config.service';
import EntryResource from 'ec.sdk/lib/resources/publicAPI/EntryResource';
/** The CrudComponent takes at least a model name to render an entry list with create/edit/delete functionality out of the box.
* ```html
* <ec-crud model="muffin"></ec-crud>
* ```
* <example-url>https://components.entrecode.de/entries/crud?e=1</example-url>
* */
@Component({
selector: 'ec-crud',
templateUrl: './crud.component.html',
})
export class CrudComponent implements OnInit, WithLoader, WithNotifications {
/** The model that should be crud'ed. */
@Input() model: string;
/** CrudConfig for customization of the crud's UI.*/
@Input() config: CrudConfig<EntryResource> = {};
/** The selection that should be used */
@Input() selection: Selection<EntryResource>;
/** The EntryList inside the template. */
@ViewChild(EntryListComponent) list: EntryListComponent;
/** The Pop inside the template. */
@ViewChild(EntryPopComponent, { static: true }) entryPop: EntryPopComponent;
/** The lists loader */
@ViewChild(LoaderComponent, { static: true }) loader: LoaderComponent;
/** Emits when a list element is clicked */
@Output() columnClicked: EventEmitter<any> = new EventEmitter();
/** Emits when the selection has changed */
@Output() selected: EventEmitter<any> = new EventEmitter();
/** Emitted Notifications */
notifications: Notification[] = [];
constructor(
private sdk: SdkService,
private auth: AuthService,
private loaderService: LoaderService,
private modelConfig: ModelConfigService,
private notificationService: NotificationsService,
private symbol: SymbolService,
private cdr: ChangeDetectorRef,
@Optional() public router: Router,
@Optional() public route: ActivatedRoute,
) {
/* if (route) {
merge(route.data, route.params, route.queryParams)
.subscribe(({ model }) => {
if (model) {
this.model = model;
}
});
} */
}
ngOnInit() {
this.auth.getAllowedModelMethods(this.model, this.config.methods).then((methods) => {
this.config.methods = methods;
this.cdr.markForCheck();
});
this.modelConfig.generateConfig(this.model).then(config => {
this.config = {
...config,
...this.config
};
});
}
/** Returns true if the given method is part of the methods array (or if there is no methods array) */
public hasMethod(method: string) {
return this.config.methods && this.config.methods.indexOf(method) !== -1;
}
/** Returns true if the visible fields in the list differ from the visible fields in the form*/
public mustReload(item) {
return !Object.keys(item.config.fields).reduce((equal, property) => {
return equal && (item.config.fields[property].list !== false || item.config.fields[property].form === false);
}, true);
}
/** Loads the clicked entry item, depending on the configured levels. Reloads the entry if the form has fields the which list has not. */
private loadEntry(item) {
return this.modelConfig
.getMinLevel(this.model, this.config.fields)
.then((minLevel) => {
const levels = Math.max(minLevel, this.config.levels || 1);
if (!this.config.alwaysLoadEntry && !this.mustReload(item) && levels === 1) {
return item.getBody();
}
return this.sdk.api.entry(this.model, item.id(), levels);
})
.then((loadedEntry) => {
this.entryPop.edit(loadedEntry);
this.notificationService.emit({ hide: this.notifications });
})
.catch((err) => {
console.log('error while loading entry to edit', err);
this.notificationService.emit({
title: this.symbol.resolve('error.load'),
error: err,
sticky: true,
hide: this.notifications,
replace: this.notifications,
});
});
}
/** Is called when an item in the list is clicked. */
public selectEntry(item) {
if (!item) {
return;
}
if (this.columnClicked.observers.length) {
this.columnClicked.emit(item);
return;
}
this.loaderService.wait(this.loadEntry(item), this.loader);
}
}
<div class="ec-crud">
<header class="ec-crud-header">
<a (click)="entryPop.create()" *ngIf="hasMethod('post')" class="btn" [class.btn_square]="!config?.createLabel">
<span *ngIf="config?.createLabel">{{ config?.createLabel }}</span>
<span *ngIf="!config?.createLabel">
<ec-icon name="add"></ec-icon>
</span>
</a>
</header>
<div class="ec-crud-body">
<ec-entry-list
[model]="model"
[config]="config"
[solo]="true"
*ngIf="hasMethod('get')"
[selection]="selection"
[loader]="config?.loader || loader"
(columnClicked)="selectEntry($event)"
>
</ec-entry-list>
</div>
<ec-loader class="ec-loader loader is-global"></ec-loader>
<ec-entry-pop [model]="model" [config]="config"></ec-entry-pop>
</div>