Skip to main content

Editable Table
Ready

Editable Table is a functional component for enhancing tabular data with editable possibilities. It is based upon duet-table but is intended to take a Javascript Map of Records and map them into grouped sections

It’s important to understand that this component only give you the tools to represent a map in a visual way, and connect various "actions" to each line item. What the line item is and which actions you choose to run are your decisions, any action given results an event that contains information about what action was clicked/pressed and which line item it originated from. The rest of any logic will have to be provided by you.

Examples

Open in new window
<duet-layout center>
<div slot="main">
<duet-card padding="large">
<br />
<duet-editable-table></duet-editable-table>
</duet-card>
</div>
</duet-layout>

<script>
const element = document.querySelector("duet-editable-table")

//mock functions to generate Map items
function getSuccessItems() {
return listFromArray([{
name: "This item succeeded and is number 1",
lastModified: "September 2001, 15:50:10",
},
{
name: "This item succeeded and is number 2",
lastModified: "September 2001, 15:50:10",
}
], "success")
}

//mock functions to generate Map items
function getFailedItems() {
return listFromArray([{
name: "This item failed and is number 1",
lastModified: "September 2001, 15:50:10",
},
{
name: "This item failed and is number 2",
lastModified: "September 2001, 15:50:10",
}
], "failure")
}

//mock functions to generate Map items
function getSomeOtherItems() {
return listFromArray([{
name: "This item has Other as category and is number 1",
lastModified: "September 2001, 15:50:10",
}], "other")
}

//Generate List of items from array with defaults
function listFromArray(items, group) {
const fileMap = new Map()

items.forEach(obj => {

const fileItem = {
uid: `${Date.now()}-${Math.random()}`,
item: `<span><duet-link>${obj.name} </duet-link><div>${obj.lastModified}</div></span>`,
group: group
}
fileMap.set(fileItem.uid, fileItem)
})

return fileMap
}

//Example function showing how to delete items, and tell the component to re-render
function deleteFromMap(itemMap, details) {
console.log("deleting: ", details.uid)
itemMap.delete(details.uid)
element.updateTable()
}

// set items to the map
element.items = new Map([...getSuccessItems(), ...getFailedItems(), ...getSomeOtherItems()])

// define groups that we want to show (you can use this to limit which part of the Map is shown
// for instance by dynamically changing this array you can show and hide the other group
element.groups = [{
id: "success",
label: {
fi: "Onnistuneet",
en: "Successful items",
sv: "Gick bra",
}
},
{
id: "failure",
label: {
fi: "Epäonnistui",
en: "Failed items",
sv: "Fejlede",
}
},
{
id: "other",
label: {
fi: "Muut",
en: "Other items",
sv: "Andet",
}
}
]
// define actions that we want to show for each items
// by default all actions are always shown, but by using the
// map attribute you can tell the component, in which context to show the action
element.actions = [
{
variation: "default",
icon: "action-edit-2",
color: "primary",
color_hover: "primary-dark",
id: "edit",
map: ["success"],
label: {
"fi": "Muokkaa luokkaa",
"en": "Edit category",
"sv": "Redigera kategori"
}
},
{
variation: "destructive",
icon: "action-delete",
color: "danger",
color_hover: "primary-dark",
id: "delete",
map: ["success", "failure"],
label: {
"fi": "Poista tiedosto",
"en": "Delete file",
"sv": "Radera fil"
}
},
{
variation: "default",
icon: "navigation-close-small",
color: "secondary",
color_hover: "primary-dark",
id: "cancel",
map: ["other"],
label: {
fi: "Kiinni",
en: "Close",
sv: "Lukk",
},
}, {
variation: "default",
icon: "category-liability-damage",
color: "secondary",
color_hover: "primary-dark",
id: "damage",
label: {
fi: "fi: Label",
en: "en: Label",
sv: "sv: Label",
},
}
]

// listen to the events from the component
element.addEventListener("duetEditableItemAction", (e) => {
console.log("got action", e.detail.action)

if (e.detail.action === "delete") {
this.deleteFromMap(element.items, e.detail)
}

})
</script>
Open in new window
<duet-layout center>
<div slot="main">
<duet-card padding="large">
<br />
<duet-editable-table hide-table-labels></duet-editable-table>
</duet-card>
</div>
</duet-layout>

<script>
const element = document.querySelector("duet-editable-table")

//mock functions to generate Map items
function getSuccessItems() {
return listFromArray([{
name: "This item succeeded and is number 1",
lastModified: "September 2001, 15:50:10",
},
{
name: "This item succeeded and is number 2",
lastModified: "September 2001, 15:50:10",
}
], "success")
}

//mock functions to generate Map items
function getFailedItems() {
return listFromArray([{
name: "This item failed and is number 1",
lastModified: "September 2001, 15:50:10",
},
{
name: "This item failed and is number 2",
lastModified: "September 2001, 15:50:10",
}
], "failure")
}

//mock functions to generate Map items
function getSomeOtherItems() {
return listFromArray([{
name: "This item has Other as category and is number 1",
lastModified: "September 2001, 15:50:10",
}], "other")
}

//Generate List of items from array with defaults
function listFromArray(items, group) {
const fileMap = new Map()

items.forEach(obj => {

const fileItem = {
uid: `${Date.now()}-${Math.random()}`,
item: `<span><duet-link>${obj.name} </duet-link><div>${obj.lastModified}</div></span>`,
group: group
}
fileMap.set(fileItem.uid, fileItem)
})

return fileMap
}

//Example function showing how to delete items, and tell the component to re-render
function deleteFromMap(itemMap, details) {
console.log("deleting: ", details.uid)
itemMap.delete(details.uid)
element.updateTable()
}

// set items to the map
element.items = new Map([...getSuccessItems(), ...getFailedItems(), ...getSomeOtherItems()])

// define groups that we want to show (you can use this to limit which part of the Map is shown
element.groups = [{
id: "success",
label: {
fi: "Onnistuneet",
en: "Successful items",
sv: "Gick bra",
}
},
{
id: "failure",
label: {
fi: "Epäonnistui",
en: "Failed items",
sv: "Fejlede",
}
},
{
id: "other",
label: {
fi: "Muut",
en: "Other items",
sv: "Andet",
}
}
]

// define actions that we want to show for each items
// by default all actions are always shown, but by using the
// map attribute you can tell the component, in which context to show the action
element.actions=[
{
"icon": "action-edit-2",
"color": "primary",
"color_hover": "primary-dark",
"id": "edit",
"map": ["success"],
"label": {
"fi": "Muokkaa luokkaa",
"en": "Edit category",
"sv": "Redigera kategori"
}
},
{
"icon": "action-delete",
"color": "danger",
"color_hover": "primary-dark",
"id": "delete",
"map": ["success", "failure"],
"label": {
"fi": "Poista tiedosto",
"en": "Delete file",
"sv": "Radera fil"
}
}
]
// listen to the events from the component
element.addEventListener("duetEditableItemAction", (e) => {
console.log("got action", e.detail.action)

if (e.detail.action === "delete") {
this.deleteFromMap(element.items, e.detail)
}

})
</script>

Properties #

Property Attribute Description Type Default
actions -- Actions that can be performed on the element { icon: string; color: string; color_hover: string; id: string; map?: string[]; label?: DuetLangObject; }[] undefined
alignment alignment Key used to set vertical alignment of action buttons string "middle"
data -- Object of data itemsused to render the entire row { uid: string; item: string | HTMLElement | Record<string, string>; group: string; } undefined
keyName key-name Key used to identify item, when running actions string ""
theme theme Theme of the empty state component. "" | "default" | "turva" ""

Events #

Event Description Type
duetEditableItemAction Emitted when any action is clicked CustomEvent<{ originalEvent?: Event; uid: string; keyName: string; action: string; group: string; component: "duet-editable-table-item"; }>

Usage #

This section includes guidelines for designers and developers about the usage of this component in different contexts.

This Component has template support, if you define a <template></template> section within the editable-table element, editable-table will use this to render any data items in you item array.
Instead of passing a html string in the DuetEditableTableItems you can then pass an object containing any data you want to display with that previously defined template.

See the with_template example for details on implementation

The component is automatically Theme aware, and will try to add the given theme to any colors set in actions.

When to use #

  • When you need to display tabular data with actions associated with them.
  • When you want the user to be able to interact with each line item.

When not to use #

  • To display name/value pairs such as terms and definitions. Use list component instead.
  • To display a glossary list. Use list component instead.

Accessibility #

This component has been validated to meet the WCAG 2.1 AA accessibility guidelines. You can find additional information regarding accessibility of this component below.


Integration

For integration, event and theming guidelines, please see Using Components. This documentation explains how to implement and use Duet’s components across different technologies like Angular, React or Vanilla JavaScript.



Tutorials

Follow these practical tutorials to learn how to build simple page layouts using Duet’s CSS Framework, Web Components and other features:

Tutorials

Building Layouts

Tutorials

Using CLI Tools

Tutorials

Creating Custom Patterns

Tutorials

Server Side Rendering

Tutorials

Sharing Prototypes

Tutorials

Usage With Markdown

Tutorials

VS Code

Tutorials

Zeplin


Troubleshooting

If you experience any issues while using a component, please head over to the Support page for more guidelines and help.