Auto CRUD Hilla React
Auto CRUD is a component that provides CRUD functionality (i.e., Create, Read, Update, Delete) based on a Java backend service. It includes a sortable, filterable and lazy-loaded grid, as well as a form for creating, updating and deleting items.
Important
|
Scaled down examples
The examples on this page are scaled down so that their viewport-size-dependent behavior can be demonstrated.
Some examples also change their behavior based on your browser viewport size.
|
Basic Usage
Auto CRUD requires a Java service that implements the CrudService<T, ID>
interface. In the example here, the EmployeeService
class extends CrudRepositoryService<T, ID, R>
, which in turn implements the CrudService<T, ID>
:
import com.vaadin.flow.server.auth.AnonymousAllowed;
import com.vaadin.hilla.BrowserCallable;
import com.vaadin.hilla.crud.CrudRepositoryService;
@BrowserCallable
@AnonymousAllowed
public class EmployeeService
extends CrudRepositoryService<Employee, Long, EmployeeRepository> {
}
Hilla generates TypeScript objects for each @BrowserCallable
service implementing the CrudService<T, ID>
interface. These TypeScript objects have callable methods that execute the corresponding Java service methods, enabling the Add, Update, and Delete operations as well as lazy data loading with sorting and filtering.
For the example above, the generated TypeScript objects can be imported into the React view and the component configured like so:
<AutoCrud service={EmployeeService} model={EmployeeModel} />
Here’s what the rendered component looks like:
new tab
import { AutoCrud } from '@vaadin/hilla-react-crud';
import { EmployeeService } from 'Frontend/generated/endpoints';
import EmployeeModel from 'Frontend/generated/com/vaadin/demo/fusion/crud/EmployeeModel';
function Example() {
return <AutoCrud service={EmployeeService} model={EmployeeModel} />;
}
As you can see in the previous example, Auto CRUD renders a grid with columns for all of the Employee
entity’s properties, next to a form with fields for editing those properties. Selecting an entity in the grid populates the form with data from that entity. The new button allows one to create a new entity. When submitting the form, the data is submitted to the save
method of the configured CrudService
, and the row in the grid is updated. When an existing entity is selected, the form also shows a Delete button. Clicking on it, the button calls the delete
method of the configured CrudService
, clears the form and removes the row in the grid.
Auto CRUD supports working with plain, non-JPA classes. This can be useful, for example, if you want to use the Data Transfer Object (DTO) pattern. See the Working with Plain Java Classes section.
Customizing the Grid
As you may have noticed in the previous example, the Auto CRUD component by default rendered the grid with all the properties of the entity, with default filtering and sorting options. The underlying Auto Grid offers a number of properties that allows you to customize the grid and its columns:
-
visibleColumns
: An array of strings that specifies the names and also the order of appearance for the properties to be displayed as columns in the grid. -
columnOptions
: An object that specifies the options for each column. -
customColumns
: An array of<GridColumn />
components that specifies the custom columns to be added to the grid. -
noHeaderFilters
: Auto Grid has column-based filtering enabled by default. You can disable the built-in column filters by setting thenoHeaderFilters
flag. -
Grid Props: Since the Auto CRUD component is composed of the Auto Grid component, and it’s internally using the Grid component, you can use all the properties of the Grid component to customize the grid. The way to pass the properties to the Auto CRUD component is by using the
gridProps
property.
You can customize the grid by providing any of these options to the gridProps
property. The following example shows how to provide the visibleColumns
property to the gridProps
to set the visibility and order of the columns. Additionally, it shows how to provide the columnOptions
property to the gridProps
to change the default header title of firstName
column, and to provide a custom renderer for the active
column.
new tab
function ActiveRenderer({ item }: { item: Employee }) {
const { active } = item;
const color = active ? 'green' : 'red';
return <span style={{ fontWeight: 'bold', color }}>{active ? 'Yes' : 'No'}</span>;
}
return (
<AutoCrud
service={EmployeeService}
model={EmployeeModel}
gridProps={{
visibleColumns: ['firstName', 'lastName', 'active', 'version'],
columnOptions: {
firstName: { header: 'Name' },
active: { renderer: ActiveRenderer },
},
}}
/>
);
Caution
|
Don’t Expose Sensitive Data on Client-Side
When using Auto CRUD, it’s important to check that you don’t expose sensitive data to the client-side. For example, if you have a password property in your entity, hiding it using the visibleColumns property won’t prevent the data from being sent to the client-side. Make sure your service implementation doesn’t expose sensitive data to the client-side. You could do this by using a @JsonIgnore annotation on the property.
|
For more detailed examples of customizing the underlying grid, please refer to the Auto Grid component documentation.
Customizing the Form
As you may have seen in the previous examples, Auto CRUD component renders by default a form with input components for all properties of the Employee
entity along with a Save button that associates with the respective save
method of the provided CrudService<Employee, Long>
. It also includes a Discard button — which is hidden initially — that calls the form binder’s reset
operation, which is only visible when there are changes. It renders a Delete button when a row is selected in the Grid, and the Form is in edit mode.
The underlying Auto Form offers a number of properties that allows you to customize the form and its fields:
-
visibleFields
: Auto Form component renders by default fields for all data properties in a Form Layout, except for the fields annotated by@Id
and@Version
. UsingvisibleFields
, you can choose which fields to render in the form and in what order. -
fieldOptions
: This is an object that specifies the options for each field. -
colspan
: In case you want to render the form in a two or more column layout, you can set thecolspan
property for each field throughfieldOption
props to make it span over more than one column. -
formLayoutProps
: This is an object that specifies the options for the Form Layout. -
layoutRenderer
: This is a function that takes theAutoFormLayoutRendererProps
as a parameter and returns any React element. TheAutoFormLayoutRendererProps
contains a read-only list of bound fields calledchildren
, and the form binder instance calledform
. You can use this function to achieve any custom layout, and also to have more control over binding and validations.
You can customize the form rendered by Auto CRUD by providing any of these options the formProps
property. The example below shows how to provide the visibleFields
property to the formProps
to set the visibility and the order of the fields. Additionally, it shows how to provide the fieldOptions
property to the formProps
to change the default label of firstName
field, and to render a Text Area for the description
field:
new tab
<AutoCrud
service={EmployeeService}
model={EmployeeModel}
formProps={{
visibleFields: ['firstName', 'lastName', 'active', 'version', 'description'],
fieldOptions: {
firstName: { label: 'Name' },
description: {
renderer: ({ field }) => <TextArea {...field} label="Full description" />,
},
},
}}
/>
Caution
|
Don’t Expose Sensitive Data on Client-Side
When using Auto CRUD, it’s important to check that you don’t expose sensitive data to the client-side. For example, if you have a password property in your entity, hiding it using visibleFields does not prevent the data from being sent to the client-side. Make sure your service implementation doesn’t expose sensitive data to the client-side. You could do this by using a @JsonIgnore annotation on the property.
|
For more detailed examples of customizing the underlying form, please refer to the Auto Form component documentation.
Working with Plain Java Classes
Auto CRUD supports working with plain, non-JPA Java classes. This can be useful, for example, if you want to use the Data Transfer Object (DTO) pattern to decouple your domain from your presentation logic, or you want to avoid serializing your JPA entities to the client due to performance concerns.
Implementing a Custom Service
To use plain Java classes, you need to provide a custom implementation of the CrudService<T>
interface, as the CrudRepositoryService<T>
base class only works with JPA entities. The following methods have to be implemented:
-
List<T> list(Pageable pageable, Filter filter)
: Returns a list of paginated, sorted and filtered items. -
T save(T value)
: Either creates a new item or updates an existing one, depending on whether the item has an ID or not. Returns the saved item. -
void delete(ID id)
: Deletes the item with the given ID.
The following example shows a basic implementation of a custom CrudService
that wraps a JPA repository. The service only exposes DTO instances to the client and maps between the DTO instances and JPA entities, internally.
@BrowserCallable
@AnonymousAllowed
public class ProductDtoCrudService implements CrudService<ProductDto, Long> {
private final ProductRepository productRepository;
public ProductDtoCrudService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Override
@Nonnull
public List<@Nonnull ProductDto> list(Pageable pageable, @Nullable Filter filter) {
// Basic list implementation that only covers pagination,
// but not sorting or filtering
Page<Product> products = productRepository.findAll(pageable);
return products.stream().map(ProductDto::fromEntity).toList();
}
@Override
public @Nullable ProductDto save(ProductDto value) {
Product product = value.id() != null && value.id() > 0
? productRepository.getReferenceById(value.id())
: new Product();
product.setName(value.name());
product.setCategory(value.category());
product.setPrice(value.price());
return ProductDto.fromEntity(productRepository.save(product));
}
@Override
public void delete(Long id) {
productRepository.deleteById(id);
}
}
The example above only has a very basic implementation of the list
method. It doesn’t support sorting and filtering. For a proper implementation of that method, see the corresponding section in the Auto Grid documentation. It shows how to implement a ListService
, in which the list
method has the same signature as for CrudService
.