Sélecteur par tableau
Choisir des fiches liées dans un formulaire.
Utilisez tablePicker lorsqu’une liste ne donne pas assez d’informations pour identifier une relation. Le tableau imbriqué possède son catalogue et ses identifiants stables.
Exemple de configuration
Partez du démarrage React ou du démarrage Vue. Le fichier suivant complète leur catalogue de produits. Passez cette configuration via getTableConfig en React ou config en Vue.
import type { FormConfig } from "@/components/ui/yayaw-table/components/forms/types";
import { customers, orderSchema } from "../shared/orders";
import { customerConfig } from "./order-config";
import { renderProductSelect } from "./product-select";
export const orderForm: FormConfig = {
id: "orders",
title: "Edit order",
presentation: "modal",
width: "64rem",
schema: orderSchema,
fields: [
{ name: "reference", label: "Reference", type: "text", bulkEdit: false },
{
name: "customerId",
label: "Customer",
type: "tablePicker",
tablePicker: {
tableType: "customers",
config: customerConfig,
data: customers,
getRowId: (row) => String(row.id),
multiple: false,
syncUrl: false,
maxHeight: "18rem",
},
},
{
name: "lines",
label: "Order lines",
type: "collection",
collectionMode: "dialog",
addLabel: "Add line",
getItemKey: (line) => String(line.id),
createItem: () => ({
id: crypto.randomUUID(),
productId: "",
quantity: 1,
allocations: [],
}),
columns: [
{ id: "productId", header: "Product" },
{ id: "quantity", header: "Quantity" },
],
validateItem: (line) =>
Number(line.quantity) > 0 && line.productId
? []
: ["Choose a product and a positive quantity."],
validateItems: (lines) =>
lines.length ? [] : ["Add at least one line."],
itemFields: [
{
name: "productId",
label: "Product",
type: "custom",
renderField: renderProductSelect,
},
{
name: "quantity",
label: "Quantity",
type: "number",
min: 1,
step: 1,
},
{
name: "allocations",
label: "Warehouse allocations",
type: "collection",
collectionMode: "inline",
getItemKey: (allocation) => String(allocation.id),
createItem: () => ({
id: crypto.randomUUID(),
warehouse: "",
quantity: 1,
}),
itemFields: [
{ name: "warehouse", label: "Warehouse", type: "text" },
{ name: "quantity", label: "Quantity", type: "number", min: 1 },
],
},
],
},
],
};import type { FormConfig } from "@/components/ui/yayaw-table-vue/types";
import { customers, orderSchema } from "../shared/orders";
import { products } from "../shared/products";
import { customerConfig } from "./order-config";
export const orderForm: FormConfig = {
id: "orders",
title: "Edit order",
presentation: "modal",
width: "64rem",
schema: orderSchema,
fields: [
{ name: "reference", label: "Reference", type: "text", bulkEdit: false },
{
name: "customerId",
label: "Customer",
type: "tablePicker",
tablePicker: {
tableType: "customers",
config: customerConfig,
data: customers,
getRowId: (row) => String(row.id),
multiple: false,
syncUrl: false,
maxHeight: "18rem",
},
},
{
name: "lines",
label: "Order lines",
type: "collection",
collectionMode: "dialog",
addLabel: "Add line",
getItemKey: (line) => String(line.id),
createItem: () => ({
id: crypto.randomUUID(),
productId: "",
quantity: 1,
allocations: [],
}),
columns: [
{ id: "productId", header: "Product" },
{ id: "quantity", header: "Quantity" },
],
validateItem: (line) =>
Number(line.quantity) > 0 && line.productId
? []
: ["Choose a product and a positive quantity."],
validateItems: (lines) =>
lines.length ? [] : ["Add at least one line."],
itemFields: [
{
name: "productId",
label: "Product",
type: "select",
options: products.map((product) => ({
value: product.id,
label: product.name,
})),
},
{
name: "quantity",
label: "Quantity",
type: "number",
min: 1,
step: 1,
},
{
name: "allocations",
label: "Warehouse allocations",
type: "collection",
collectionMode: "inline",
getItemKey: (allocation) => String(allocation.id),
createItem: () => ({
id: crypto.randomUUID(),
warehouse: "",
quantity: 1,
}),
itemFields: [
{ name: "warehouse", label: "Warehouse", type: "text" },
{ name: "quantity", label: "Quantity", type: "number", min: 1 },
],
},
],
},
],
};Fournir le catalogue imbriqué
La recette commande fournit customerConfig, les clients, les actions et le composant d’entrée utilisés ci-dessus. data fournit une liste locale ; actions.list peut charger les choix distants. Gardez syncUrl: false pour ne pas remplacer la requête de la page principale en choisissant une relation.
Identifiants et mode de sélection
getRowId doit produire une chaîne stable. parseValue la convertit en valeur stockée si nécessaire. Utilisez multiple: false pour une relation scalaire et multiple: true pour un tableau. Respectez cette forme dans les valeurs initiales et validez à nouveau la relation côté serveur.
Pour imbriquer ce sélecteur dans un formulaire de catalogue React, reprenez le wrapper Jotai isolé et la résolution avec contexte de la recette commande complète. Le registre vérifié partage les atomes de formulaire entre instances ; le wrapper évite un éditeur en double et conserve la valeur du champ parent. Vue ne demande pas ce wrapper.
Essayer dans la page
Ouvrez la commande existante et choisissez un client avec le sélecteur de tableau. Ajoutez une ligne pour sélectionner un produit.
Données de démonstration. Les modifications restent dans cet aperçu.
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { NuqsAdapter } from "nuqs/adapters/react";
import { useState } from "react";
import { Toaster } from "sonner";
import { DataTable } from "@/components/ui/yayaw-table";
import { getFormConfig } from "./get-order-form";
import { getOrderActions } from "./order-actions";
import { orderConfig } from "./order-config";
import type { ExamplePresentation } from "./presentation";
const getConfig = () => orderConfig;
export default function OrderRecipe(presentation: ExamplePresentation = {}) {
const [queryClient] = useState(() => new QueryClient());
return (
<QueryClientProvider client={queryClient}>
<NuqsAdapter>
<DataTable
{...presentation}
getFormConfig={getFormConfig}
getRowId={(row) => String(row.id)}
getTableActions={getOrderActions}
getTableConfig={getConfig}
tableId="recipe-order"
tableType="orders"
title={presentation.title ?? "Order"}
/>
<Toaster />
</NuqsAdapter>
</QueryClientProvider>
);
}Données de démonstration. Les modifications restent dans cet aperçu.
<script setup lang="ts">
import type { ExamplePresentation } from "./presentation";
defineProps<ExamplePresentation>();
import { YayawDataTable } from "@/components/ui/yayaw-table-vue";
import { getFormConfig } from "./get-order-form";
import { getOrderActions } from "./order-actions";
import { orderConfig } from "./order-config";
const getRowId = (row: Record<string, unknown>) => String(row.id);
</script>
<template>
<YayawDataTable v-bind="$props" table-type="orders" table-id="recipe-order" :title="title ?? 'Order'"
:config="orderConfig" :get-table-actions="getOrderActions" :get-row-id="getRowId"
:get-form-config="getFormConfig" />
</template>