Link List Rows to Read and Update Views
Turn one list column into a Row Link, so each row's value opens that row's update or read view. Pick a column that identifies the record, such as a purchase order's reference.
You need a working CRUD surface (Create a CRUD Surface). Configure list/read/create/update Views describes how model config overrides combine.
Set detailLinkField
Choose a column that the list already displays. The link wraps that column's value and adds no column of its own.
Name it in
detailLinkFieldin the model'slistoverride. Register the override when the application starts:jsimport { storeModelConfig } from "@vueda/stores/storeModelConfig.js"; export function setupModelConfig(pinia) { storeModelConfig(pinia).setConfig({ app: "catalog", model: "purchaseorder" }, null, { list: { displayFields: ["reference", "supplier", "total_value"], detailLinkField: "reference", }, }); }Each
setConfigcall replaces the levels that it names, so passnullfor a level that you leave alone. Register Overrides withsetConfigdescribes when to call it.detailLinkFielddefaults tonull, which turns row links off. Set it tonullin alistoverride to turn off a model-wide value.Keep the linked field in the list request. The list fetches the columns that it displays unless you set
fetchFields. If you setfetchFields, include the linked field.Check that the model's serializer includes Available Actions. VuedaSerializer declares the
available_actionsfield. WhendetailLinkFieldis set, the list addsavailable_actionsand the primary key to its requested fields. It does this even when thelistFieldsprop replaces the fetch list. Neither field becomes a visible column.
ViewList then reads each row's available_actions to pick the link's destination:
Row's available_actions | Link destination |
|---|---|
Includes update | The row's update view |
Includes retrieve, without update | The row's read view |
| Includes neither, or the field is not present | Displayed value without a row link |
Each row picks its own destination. A user who can retrieve a purchase order but cannot update it gets a read link on its reference. An editable row in the same list gets an update link.
The link controls navigation in the UI only. Route guards and server permissions still decide access when the user follows it.
Check Which Columns Get the Link
ViewList wraps the configured column only when its Column Adapter is one of these built-in adapters. The adapter keeps its display props.
The check uses the adapter that the column resolves to, so a columnComponents override that names one of these adapters keeps the link. Other adapters render without a row link:
- ColumnModelLink already links to the related record and keeps that target.
- ColumnFile already links to the stored file and keeps that target.
- A custom adapter may contain links, buttons, or other controls, so VUEDA leaves its navigation alone. Use a field slot (next section) to link custom content.
- A column whose override does not name a component renders no cells, and the list shows an error for that column. Customize List Column Rendering describes the override chain.
A field(<name>) slot on the configured column replaces the automatic link. Remove the slot to use the row link.
The link is an anchor with the row's URL in both table and card layouts. The cell's content is the link text. A plain click navigates inside the application. The browser handles a modified click, such as Ctrl+click, so opening in a new tab works.
Link a Custom Cell With LinkModelView
Use LinkModelView in a field(<name>) slot when the cell needs custom content or its own destination rule. LinkModelView does not check permissions, so the slot reads the row's available_actions itself.
This list view applies the same update-then-read rule to custom content in the reference column:
<script setup>
import LinkModelView from "@vueda/navigation/link-model-view/LinkModelView.vue";
import ViewList from "@vueda/views/ViewList.vue";
defineProps({
app: { type: String, required: true },
model: { type: String, required: true },
});
defineOptions({ inheritAttrs: false });
const detailView = (obj) => {
const actions = obj.available_actions || [];
return actions.includes("update") ? "update" : actions.includes("retrieve") ? "read" : null;
};
</script>
<template>
<view-list v-bind="{ ...$props, ...$attrs }">
<template #[`field(reference)`]="{ pk, obj, formatted }">
<link-model-view v-if="detailView(obj)" :app="app" :model="model" :pk="pk" :view="detailView(obj)">
{{ formatted }}
</link-model-view>
<span v-else>{{ formatted }}</span>
</template>
</view-list>
</template>To render this component as the model's list view, return it from a list loader passed to setCrudComponents. View Component Resolution Order describes the loader.
Without detailLinkField, the list does not request available_actions. Add it to fetchFields, or to the listFields prop when you pass one, and leave it out of displayFields. Do not put another link or control inside the LinkModelView.
Verify the Result
- Open the list as a user with a mix of editable, read-only, and unavailable rows. Confirm update links, read links, and plain values on the matching rows.
- In the browser's network panel, confirm that the list request's fields include the primary key, the displayed columns, and
available_actions. Confirm that no extra column appears. - Check both table and card layouts, keyboard activation, and a modified click on the linked value.