dile-crud-single
The dile-crud-single
component is designed to display the details of a record from a REST API, along with the available actions for it and any related resources.
Installation
npm i @dile/crud
Usage
Import the dile-crud component.
import '@dile/crud/components/single/crud-single.js';
Use the component.
<dile-crud-single
relatedId="1"
.config="${this.config}"
></dile-crud-single>
Properties
- config: Object, the configuration object that customizes the behavior and appearance of the
dile-crud-single
component. - relatedId: String, the identifier of the specific record that is being displayed and managed by the component.
- element: Object, the item object containing the details of the record to be displayed.
- actionIds: Array, containing the identifier of the item being managed in the
dile-crud-single
component. This identifier is used to trigger batch actions in the CRUD system. Although this component displays a single record, an array is used for actions, with a single identifier in the array. - language: String, the interface and feedback messages language. Available 'en', 'es'. Fallback to 'en'.
Methods
- refresh(): Reloads the current data for the record being displayed. This method is used to update the view after changes have been made to the record.
- edit(): Opens the form to edit the current record being displayed by the
dile-crud-single
component.
Events
This component is built on multiple components from the @dile/crud
catalog. As a result, it can dispatch a large number of events, such as those detailed in dile-crud
, dile-crud-update
, dile-crud-item-delete
, and others.
Particularly useful events include:
- crud-action-success: Dispached when an action succeed. The detail of this event includes the properties the
action
name, themsg
anddata
with any additional data that the backend may have sent as a response. - crud-item-detail-loaded: This event is dispatched when the item details have been successfully loaded from the API. The event detail includes the loaded data.
- crud-update-success: Dispatched when an update operation is successfully completed. It sends the same detail that is received from the
dile-ajax-form
component.
Refer to the documentation of other components to discover many more events available in dile-crud-single
.
Configuration
Please refer to the general documentation to find the established mechanisms for configuring the dile-crud
component.
Examples
Configuration object
Find the guides for creating the configuration object on the resource configuration page.
<script type="module">
import { html } from 'lit';
import { CrudConfigBuilder } from '@dile/crud/lib/CrudConfigBuilder';
import '@dile/ui/components/pages/pages';
// For the correct functioning of this declaration in the demo system, we have defined the variable with the configuration object globally. Normally, it would be created in a module and exported.
window.countryConfig = new CrudConfigBuilder('https://timer.escuelait.com/api/countries', {
templates: {
item: (country) => html`<demo-country-item .country=${country}></demo-country-item>`,
insertForm: () => html`<demo-country-form id="insertform"></demo-country-form>`,
updateForm: () => html`<demo-country-form id="updateform"></demo-country-form>`,
help: () => html`<p>This is the help provided to the countries resource.</p>`,
detail: (country) => html`<demo-country-detail .country="${country}"></demo-country-detail>`,
relations: (country) => html`<demo-country-relations .country=${country}></demo-country-relations>`,
formSingleActions: (actionName, country) => html`
<dile-pages attrForSelected="action" selected="${actionName}">
<demo-set-europe-as-continent-action action="SetEurope" .country=${country}></demo-set-europe-as-continent-action>
<demo-set-asia-as-continent-action action="SetAsia" .country=${country}></demo-set-asia-as-continent-action>
</dile-pages>
`,
},
customization: {
disablePagination: true,
disableHelp: false,
disableKeywordSearch: false,
disableSort: false,
disableFilter: false,
},
actions: {
single: [
{
name: "SetEurope",
label: "Set Europe as continent"
},
{
name: "SetAsia",
label: "Set Asia as continent"
},
]
},
labels: {
helpTitle: 'Country help',
},
sort: {
options: [
{
name: 'name',
label: 'Name',
direction: 'desc'
},
],
initialSortField: 'name',
},
availableFilters: [
{
name: 'continent',
label: 'Continent',
active: false,
value: false,
type: 'select',
options: [
{
name: 'Europe',
label: 'Europe'
},
{
name: 'Africa',
label: 'Africa'
},
{
name: 'Asia',
label: 'Asia'
},
]
},
],
});
</script>
Resource form component
The resource form provides the necessary fields for editing the record.
Instructions on how to create these forms can be found in the dile-crud-insert
and dile-ajax-form
component documentation.
<script type="module">
import { LitElement, html, css } from 'lit';
import '@dile/ui/components/input/input.js';
import '@dile/ui/components/select/select.js';
import { DileForm } from '@dile/ui/mixins/form'
export class DemoCountryForm extends DileForm(LitElement) {
static styles = [
css`
:host {
display: block;
}
`
];
render() {
return html`
<dile-input label="Country name" name="name" id="name" hideErrorOnInput></dile-input>
<dile-input label="Slug" name="slug" id="slug" hideErrorOnInput></dile-input>
<dile-select name="continent" id="continent" label="Continent" hideErrorOnInput>
<select slot="select">
<option value="">Select...</option>
<option value="Europe">Europa</option>
<option value="South America">América del Sur</option>
<option value="North America">Norte América</option>
<option value="Asia">Asia</option>
<option value="Africa">Africa</option>
<option value="Oceania">Oceania</option>
</select>
</dile-select>
`;
}
}
customElements.define('demo-country-form', DemoCountryForm);
</script>
<demo-country-form></demo-country-form>
Detail template component
Technically, it's not necessary to build a component to define the details of the item you want to display, as a simple template would be enough. However, to keep things organized and reusable, you would typically use a component dedicated to displaying the details, which also allows you to include additional functionality if needed.
<script type="module">
import { LitElement, html, css } from 'lit';
export class DemoCountryDetail extends LitElement {
static styles = [
css`
:host {
display: block;
color: #303030;
}
p {
margin: 0 0 1rem;
}
.last {
margin-bottom: 0;
}
`
];
static get properties() {
return {
country: { type: Object }
};
}
render() {
return html`
<p>Name: ${this.country.name}</p>
<p class="last">Continent: ${this.country.continent}</p>
`;
}
}
customElements.define('demo-country-detail', DemoCountryDetail);
</script>
Action components
Some actions that can be performed from the crud-single
component include:
<script type="module">
import { LitElement, html, css } from 'lit';
import { DileForm } from '@dile/ui/mixins/form';
class DemoSetEuropeAsContinentAction extends DileForm(LitElement) {
static styles = [
css`
:host {
display: block;
}
`
];
static get properties() {
return {
country: { type: Object }
};
}
render() {
return html`
<p>Do you really want to set Europe as continent of ${this.country?.name}?</p>
`;
}
}
customElements.define('demo-set-europe-as-continent-action', DemoSetEuropeAsContinentAction);
class DemoSetAsiaAsContinentAction extends DileForm(LitElement) {
static styles = [
css`
:host {
display: block;
}
`
];
static get properties() {
return {
country: { type: Object }
};
}
render() {
return html`
<p>Do you really want to set Asia as continent of ${this.country?.name}?</p>
`;
}
}
customElements.define('demo-set-asia-as-continent-action', DemoSetAsiaAsContinentAction);
</script>
Component for Relationships
The single pages of a CRUD can display records of related entities using dile-crud
components, filtered by the belongsTo
and relationId
properties.
For this relationship to work, we need the components required by the board games CRUD itself.
Configuration object
Find the guides for creating the configuration object on the resource configuration page.
<script type="module">
import { html } from 'lit';
import { CrudConfigBuilder } from '@dile/crud/lib/CrudConfigBuilder';
import { ResponseApiAdapter } from '@dile/crud/lib/ResponseApiAdapter';
class BoardGameResponseApiAdapter extends ResponseApiAdapter {
getElementList() {
return this.response.data.result.data;
}
}
// For the correct functioning of this declaration in the demo system, we have defined the variable with the configuration object globally. Normally, it would be created in a module and exported.
window.boardGameConfig = new CrudConfigBuilder('https://timer.escuelait.com/api/board-games', {
customization: {
hideCountSummary: false,
hideCheckboxSelection: false,
disablePagination: false,
disableHelp: true,
disableKeywordSearch: false,
disableSort: false,
disableFilter: false,
},
sort: {
options: [
{
name: 'name',
label: 'Name',
direction: 'asc'
},
{
name: 'year',
label: 'Year',
direction: 'desc'
},
],
initialSortField: 'year',
},
availableFilters: [
{
name: 'essential',
label: 'Is essential',
active: false,
value: false,
type: 'boolean',
},
],
responseAdapter: new BoardGameResponseApiAdapter(),
actions: {
list: [
{
label: 'Delete board games',
name: 'DeleteAction'
},
{
label: 'Change Essential',
name: 'DemoChangeEssentialAction'
},
],
},
templates: {
item: (boardGame) => html`<demo-board-game-item .boardGame=${boardGame}></demo-board-game-item>`,
insertForm: (belongsTo, relationId) => html`<demo-board-game-form id="insertform" belongsTo="${belongsTo}" relationId="${relationId}"></demo-board-game-form>`,
updateForm: () => html`<demo-board-game-form id="updateform"></demo-board-game-form>`,
formActions: (actionName, actionIds) => html`
<dile-pages attrForSelected="action" selected="${actionName}">
<dile-crud-delete-action action="DeleteAction"></dile-crud-delete-action>
<demo-change-essential-action action="DemoChangeEssentialAction" .actionIds=${actionIds}></demo-change-essential-action>
</dile-pages>
`,
},
});
</script>
Item component
The item component to display each of the elements in the list.
<script type="module">
import { LitElement, html, css } from 'lit';
export class DemoBoardGameItem extends LitElement {
static styles = [
css`
:host {
display: block;
color: #303030;
}
`
];
static get properties() {
return {
boardGame: { type: Object }
};
}
render() {
return html`
${this.boardGame.name} - (${this.boardGame.year})
`;
}
}
customElements.define('demo-board-game-item', DemoBoardGameItem);
</script>
Resource form component
The resource form.
<script type="module">
import { LitElement, html, css } from 'lit';
import '@dile/ui/components/input/input.js';
import '@dile/ui/components/input/input-integer.js';
import '@dile/ui/components/checkbox/checkbox.js';
import '@dile/crud/components/ajax-select-crud/ajax-select-crud';
import { DileForm } from '@dile/ui/mixins/form'
export class DemoBoardGamesForm extends DileForm(LitElement) {
static styles = [
css`
:host {
display: block;
}
`
];
static get properties() {
return {
belongsTo: { type: String },
relationId: { type: String },
};
}
firstUpdated() {
if(this.belongsTo == "country" && this.relationId) {
this.shadowRoot.getElementById('countryselect').value = this.relationId;
}
}
render() {
return html`
<dile-input label="Nombre" name="name" id="name" hideErrorOnInput></dile-input>
<dile-input label="Slug" name="slug" id="slug" hideErrorOnInput></dile-input>
<dile-input-integer name="year" label="Year" hideErrorOnInput id="year"></dile-input-integer>
<dile-ajax-select-crud
id="countryselect"
idProperty="id"
name="country_id"
label="País"
endpoint="https://timer.escuelait.com/api/countries"
queryStringVariable="keyword"
placeholder="Buscar país"
resultDataProperty="data"
displayProperty="name"
selectDefaultPlaceholder="Seleccionar país..."
></dile-ajax-select-crud>
<p><dile-checkbox name="essential">Essential</dile-checkbox></p>
`;
}
}
customElements.define('demo-board-game-form', DemoBoardGamesForm);
</script>
<demo-board-game-form></demo-board-game-form>
Action component
The board game custom batch action.
<script type="module">
import { LitElement, html, css } from 'lit';
import { DileForm } from '@dile/ui/mixins/form';
import '@dile/ui/components/select/select.js';
export class DemoChangeEssentialAction extends DileForm(LitElement) {
static styles = [
css`
:host {
display: block;
}
`
];
static get properties() {
return {
actionIds: { type: Array }
};
}
constructor() {
super();
this.actionIds = [];
}
render() {
return html`
<p>Change essential game state of ${this.actionIds.length} elements.</p>
<dile-select name="essential">
<select slot="select">
<option value="0">Not Essential</option>
<option value="1">Essential</option>
</select>
</dile-select>
`;
}
}
customElements.define('demo-change-essential-action', DemoChangeEssentialAction);
</script>
Single relations component
This is the component that allows you to define relationships. In this component, we use a dile-crud
, but technically you could include any type of content.
<script type="module">
import { LitElement, html, css } from 'lit';
export class DemoCountryRelations extends LitElement {
static styles = [
css`
:host {
display: block;
}
`
];
static get properties() {
return {
boardGameConfig: { type: Object },
country: { type: Object },
};
}
constructor() {
super();
this.boardGameConfig = boardGameConfig.getConfig();
}
firstUpdated() {
console.log(this.country);
}
render() {
return html`
${this.country
? html `
<dile-crud
title="Juegos de ${this.country.name}"
.config="${this.boardGameConfig}"
belongsTo="country"
relationId="${this.country.id}"
></dile-crud>
`
: ''
}
`;
}
}
customElements.define('demo-country-relations', DemoCountryRelations);
</script>
Crud single Component
<script type="module">
import { LitElement, html, css } from 'lit';
import '@dile/crud/components/single/crud-single'
export class DemoCountrySingle extends LitElement {
static styles = [
css`
:host {
display: block;
}
`
];
static get properties() {
return {
config: { type: Object },
};
}
constructor() {
super();
this.config = window.countryConfig.getConfig();
}
render() {
return html`
<dile-crud-single
relatedId="1"
.config="${this.config}"
></dile-crud-single>
`;
}
}
customElements.define('demo-country-single', DemoCountrySingle);
</script>
<demo-country-single></demo-country-single>