vaadin / hilla-crm-tutorial

The Unlicense
21 stars 20 forks source link

How could I use AutoCrud with a custom Form-Renderer for company #84

Open smikesmike opened 6 months ago

smikesmike commented 6 months ago

Hi, I want to use AutoCrud in ContactsView.tsx but I don't know how to implement a custom form-renderer for the field company. Could you show me an example?

Thanks in advance Marc

smikesmike commented 6 months ago

I've tried something like this in ContactsView.tsx:

import {AutoCrud} from '@hilla/react-crud';
import {ContactService, CRMService} from "Frontend/generated/endpoints";
import ContactDtoModel from "Frontend/generated/com/example/application/services/ContactDtoModel";
import ContactDto from "Frontend/generated/com/example/application/services/ContactDto";
import {TextArea} from "@hilla/react-components/TextArea";
import {useEffect, useState} from "react";
import {Select, SelectItem} from "@hilla/react-components/Select";

function CompanyRenderer({ item }: { item: ContactDto }) {
    const { company } = item;
    return <span >{company.name}</span>;
}

export function ContactsView() {
    const [companies, setCompanies] = useState<SelectItem[]>([]);

    useEffect(() => {
        getCompanies();
    }, []);

    async function getCompanies() {
        const companies = await CRMService.findAllCompanies();
        const companyItems = companies.map(company => {
            return {
                label: company.name,
                value: company.id + ""
            };
        });
        setCompanies(companyItems);
    }

    return <AutoCrud service={ContactService}
                     model={ContactDtoModel}
                     gridProps={{
                         visibleColumns: ['firstName', 'lastName', 'email', 'company'],
                         columnOptions: {
                             company: { title: 'Foo', renderer: CompanyRenderer},
                         },
                     }}
                     formProps={{
                         visibleFields: ['firstName', 'lastName', 'email', 'company'],
                         fieldOptions: {
                             firstName: { label: 'Name' },
                             company: {
                                 label: 'Company'
                                 , renderer: ({field}) => <Select label="Company" items={companies}  />

                             },
                             description: {
                                 renderer: ({ field }) => <TextArea {...field} label="Full description" />,
                             },
                         },
                     }}
   />;
}

but I habe no idea how to bind the combobox to the ContactDto.company field.

sissbruecker commented 6 months ago

The select component only works with string values, while the property you want to bind contains an object. One option would be to add another property companyId to ContactDto and bind that to the select. In the save method of your CrudService you would use companyId to assign the company to the contact.

The AutoCrud configuration would look like this:

<AutoCrud 
  service={ContactService}
  model={ContactDtoModel}
  gridProps={...}
  formProps={{
    visibleFields: ['firstName', 'lastName', 'email', 'companyId'],
    fieldOptions: {
      firstName: { label: 'Name' },
      companyId: {
        renderer: ({field}) => <Select {...field} label="Company" items={companies}  />
      },
      description: {
        renderer: ({ field }) => <TextArea {...field} label="Full description" />,
      },
    },
  }}
/>
sissbruecker commented 6 months ago

ComboBox makes this a bit easier actually, as it supports binding objects:

// No need to map items when using combo box
const [companies, setCompanies] = useState<CompanyDto[]>([]);

useEffect(() => {
  CRMService.findAllCompanies().then(setCompanies);
}, []);

// In the field renderer, render a combo box and configure it to use name and ID from company
<ComboBox {...field} label="Company" items={companies} itemLabelPath="name" itemValuePath="id" itemIdPath="id"  />
smikesmike commented 6 months ago

Thank you very much. The solution with ComboBox was exactly what I was searching for.

Now, it works very nice;)