# List

The list page is the main UI entry point of your resource where you can do all sort of resources browsing operations, as paginating, sorting, filtering, exporting, etc. It's the best place to put a VaList data iterator component that will use getList data provider with all the search context. The traditional UI layout data list stay the good old full data table by using VaDataTable components, but it can be totally replaced by anything you want.

list

PAGE CUSTOMIZATION

Note that for every CRUD pages you are free to put anything you want, and you have not forced to use provided optimized components.

Since all data provider methods are available in a dedicated store module for each resource, it's not that complicated to create your own list components that will fetch your data. And you can of course use the current global $axios instance if you need to fetch all sort of custom data that coming out of data provider logic. See usage here.

# Data Iterator

VaList

List data iterator component, perfect for list CRUD page as well as any resource browsing standalone component. Allow resource paginating and filtering. Use current query string context for initial state by default. The list layout on default slot is fully customizable and can be used for separate VaDataTable component.

MIXINS

Resource

Search

PROPS

Props Type Description
filters array Exposed filters, editable through advanced filter form, update URL query string if not disabled. Sent to your data provider inside filter params. Use specific alwaysOn property for each filter you want to be visible and not removable. Valid properties are source, type, label, alwaysOn, attributes.
itemsPerPageOptions array List of available selections of items per page.
disableQueryString boolean Disable real time update of URL query string on any browsing action as pagination, sorting, filtering, etc.
hideDefaultFooter boolean Hide default footer, notably default pagination.
disablePagination boolean Disable pagination, will hide default footer.
hideHeader boolean Hide all header toolbar, so neither filters nor any create or export actions.
disableCreate boolean Force disabling of create button, shown by default if create resource action available.
disableExport boolean Disable the export button. The export allows client-side CSV download and keep active filters while disabling pagination.
disableCreateRedirect boolean Disable create redirection. Will force create button to show.
disableGlobalSearch boolean Disable the global search.
globalSearchQuery string Key parameter of the global search query.
association object Association infos object in case of this list is related to a current show or edit resource page. Enable the association between resources directly by an autocomplete an associate action.

SLOTS

Name Description
bulk.actions Custom bulk actions, ideal place for VaBulkActionButton.
default Custom component filters.
actions Put here some global action with components based on VaActionButton.
footer Best place for any custom pagination.

EVENTS

Name Description
update:options Triggered on pagination change.
update:filter Triggered on filter change.
action Allows you to use global action event for custom action on your side.
associated Triggered on successful association of resource item.

Here a quick sample usage within the VaDataTable component :

<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-list>
      <va-data-table :fields="fields"></va-data-table>
    </va-list>
  </base-material-card>
</template>

<script>
export default {
  props: ["resource", "title"],
  data() {
    return {
      fields: [
        { source: 'name', link: 'show' },
        { source: 'type', type: 'select' },
        'founder',
        'headquarter',
        { source: 'url', type: 'url' },
        { source: 'active', type: 'boolean' },
        { source: 'opening_date', type: 'date' },
      ],
    };
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

It will produce this simple structure :

list

Note that VaList will try to be synchronized on real time within query string in order to allow any bookmark or keep state on every browser refresh. All browsing action as paginate, filter and sorting will be updated into the URL query string.

DISPLAY DATA

VaList is only responsible for data iteration UI controls. You still need to display the data list on your own or use the provided VaDataTable.

# Data Table

VaDataTable

Data table component, you will need data iterator as VaList in order to make it usable. This component allows you to template all fields columns.

PROPS

Props Type Description
rowClick string|boolean Make each row clickable. Use predefined function as edit or show.
fields array List of columns for each property of resource data. Each column can be a simple string or a full object with advanced field properties. Valid properties are source, type, label, sortable, align, link, attributes, editable.
dense boolean Reduce height of each row.
multiSort boolean Enable multi sort feature, enabled by default.
showExpand boolean Enable row expand mode. Use it for quick detail view.
singleExpand boolean Only one row can expanded at once
disableSelect boolean Disable select feature.
disableSort boolean Disable sorting.
disableShow boolean Disable show action row.
disableEdit boolean Disable show action row.
disableClone boolean Disable clone action row.
disableDelete boolean Disable delete action row.
disableActions boolean Disable actions column.
disableCreateRedirect boolean Disable create redirection. Will force clone button to show.
disableShowRedirect boolean Disable show redirection. Will force show button to show.
disableEditRedirect boolean Disable edit redirection. Will force edit button to show.
association object Association infos object in case of this list is related to a current show or edit resource page. Enable the dissociation between resources directly by an additional dissociation action.
rowCreate boolean Allow new item row.
rowEdit boolean Allow editable row.
createData object Additional form object data to merge with row-create form.
updateData object Additional form object data to merge with row-edit form.

SLOTS

Name Description
default Use for field cell templating.
cell.actions Full cell template which contains all row actions.
item.actions Use it for additional custom row actions with components based on VaActionButton.
expanded-item Place for full width cell which contains additional item infos. Visible when row is expanded.

EVENTS

Name Description
dissociated Triggered on successful dissociation of resource item.
deleted Triggered on successful deletetion of ressource item.
row-click Generic row-click event if you set rowClick on true with selected item.
item-action Triggered on action on specific row. This event will return a freshed item Object from your API.

CONTEXT SYNCHRONIZATION

As the VaDataTable is a dumb component, it needs to be synchronized with a context data. As seen at the above code example, the simplest way is to use VaList as data browsing control that will automatically inject following behaviors :

  • Current resource and items : Pass all result data from iterator into data table with total.
  • Loading state : for activating busy mode when fetching on API.
  • Selected items : Keep selected items used for bulk operation synchronized, all selected items in data table will be reflected on data iterator and vice-versa.
  • Current search context: Keep current search query context synchronized between all components, as the data table will add sorting support.

# Fields

fields

Use fields prop in order to define all columns. It's an array of string or object where can precise the best suited field formatter for data display. You need at least to set source property which defined the field of resources you want to fetch, then the type for data formatter if different than simple text format. For all supported fields, check the fields section.




 









 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-list>
      <va-data-table :fields="fields"></va-data-table>
    </va-list>
  </base-material-card>
</template>

<script>
export default {
  props: ["resource", "title"],
  data() {
    return {
      fields: [
        { source: "isbn", link: "show" },
        {
          source: "cover",
          type: "image",
          link: "show",
          attributes: {
            src: "thumbnails.small",
          },
        },
        { source: "category", type: "select", attributes: { chip: true } },
        {
          source: "publisher",
          type: "reference",
          attributes: {
            reference: "publishers",
            text: "name",
            chip: true,
            color: "orange",
          },
        },
        { source: "title", sortable: true },
        {
          source: "price",
          type: "number",
          sortable: true,
          attributes: {
            format: "currency",
          },
        },
        { source: "commentable", type: "boolean", editable: true },
        {
          source: "formats",
          type: "array",
          attributes: {
            select: true,
            color: "yellow",
            small: true,
            column: true,
          },
        },
        {
          source: "publication_date",
          type: "date",
          sortable: true,
        },
        "authors",
      ],
    };
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

See all supported field properties :

Property Type Description
source string Resource property to display.
type string Type of field to use.
label string Column title header, use localized property source by default.
labelKey string Override default source as i18n key message
sortable boolean Activate server-side sort.
align string You can Use left, right, center for each cell align attribute.
link string Use any valid show or edit action if you want to wrap field inside resource action link.
input string Type of input to use for editable form rows. Override above type props which is used by default.
attributes object All props or attributes to merge to the under field or input component.
editable boolean Replace field by a live edit input. Ideal for quick live toggle switch updates.

SHORTHAND

You can use a simple string for each field column, "my-property" is similar to { source: "my-property" }.

# Field templating

In case of all above field options doesn't suit your needs, you can perfectly use advanced slot templating for each field. You can even use all VA fields inside it. Very useful when you need to nest this field component within parent component as shown next :





 
 
 
 
 
 
 
 
 
 
 
 
 
 












 









<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-list>
      <va-data-table :fields="fields">
        <template v-slot:[`field.authors`]="{ value }">
          <v-chip-group column>
            <va-reference-field
              reference="authors"
              v-for="(item, i) in value"
              :key="i"
              color="primary"
              small
              chip
              :item="item"
            >
            </va-reference-field>
          </v-chip-group>
        </template>
      </va-data-table>
    </va-list>
  </base-material-card>
</template>

<script>
export default {
  props: ["resource", "title"],
  data() {
    return {
      fields: [
        //...
        "authors",
        //...
      ],
      //...
    };
  },
  //...
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

You just have to use a slot named as field.{source} for that, where source is the name of field. This slot will provide to you full row resource item and value of the cell that will be rendered as default.

# Expandable row

expandable

You can use the expanded-item slot with enabled show-expand prop for an additional full colspan cell under the item row. Ideal for quick view.




 
 
 
 
 




<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-list>
      <va-data-table :fields="fields" show-expand>
        <template v-slot:expanded-item="{ item }">
          {{ item.description }}
        </template>
      </va-data-table>
    </va-list>
  </base-material-card>
</template>
1
2
3
4
5
6
7
8
9
10
11

# Custom row actions

If you need other item actions in addition to classic crud operations, use the dedicated item.actions slot.





 
 
 
 
 
 
 





<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-list>
      <va-data-table :fields="fields">
        <template v-slot:[`item.actions`]="{ resource, item }">
          <impersonate-button
            :resource="resource"
            :item="item"
            icon
          ></impersonate-button>
        </template>
      </va-data-table>
    </va-list>
  </base-material-card>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

A global search filter will be enabled by default. To disable it, use disableGlobalSearch prop.

This filter will send the string search query on backend via the key configured on globalSearchQuery, which is q by default.

Then you have to deal on backend side for SQL processing, for example via a multi columns LIKE search. If you use the separate Laravel package (opens new window) for your Laravel app, you can use the dedicated SearchFilter for that.

INTERNAL FILTERS

In addition to exposed filters, you may need some internal filters that user cannot modify through UI. Use filter prop for that. It's an simple key-value object that will be automatically sent to your data provider, merged with any other active filters.

# Advanced filters

In addition to global search, VaList supports advanced custom filters as well with many supported inputs as shown here :

filters

Use the "Add filter" button for adding more filters that will add a new AND condition. The supported inputs for filtering are text, number, boolean, date, rating, select, autocomplete. Each filter are removable.

In order to define new filters, use the filters props. Here are a code sample usage of this advanced filters :




 









 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-list :filters="filters">
      <!-- VaDataTable -->
    </va-list>
  </base-material-card>
</template>

<script>
export default {
  props: ["resource", "title"],
  data() {
    return {
      filters: [
        {
          source: 'book',
          type: 'autocomplete',
          optionText: 'title',
          multiple: true,
          reference: 'books',
        },
        { source: 'rating', type: 'rating' },
        {
          source: 'status',
          type: 'select',
          multiple: true,
        },
        'author',
        {
          source: 'published_before',
          type: 'date',
        },
        {
          source: 'published_after',
          type: 'date',
        },
      ],
    };
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

You will mainly use mandatory source property as well as type for input type. Each added filter will be added to the "Add filter" dropdown button for on-asking filter activation, unless alwaysOn property is set to true. In that case, filter will be always visible and not removable.

Use attributes property in order to merge specific attributes into input component. See dedicated inputs section for further detail on valid props for each filterable inputs.

See all supported field properties :

Property Type Description
source string Resource property to display.
type string Type of input to use.
label string Column title header, use localized property source by default.
labelKey string Override default source as i18n key message
alwaysOn boolean Keep filter always active and visible. Not removable.
attributes object All props or attributes to merge to the input component.

# Filter templating

As same way as field templating you can even template your filter directly by using filter.{source} slot, where source is the name of filter. However, as your custom filter component must return input on change in order to work with current active filter, you will need to expose the internal filter of VaList by filter.sync, and then update the filter with new value on each input change.

Here is a full working sample :



 
 
 
 
 
 
 
 
 










 



 








 
 
 
 
 
 




<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-list :filters="filters" :filter.sync="filter">
      <template v-slot:filter.headquarter="props">
        <va-text-input
          hide-details
          :filled="false"
          v-bind="props"
          @input="(val) => update('headquarter', val)"
        ></va-text-input>
      </template>
      <va-data-table :fields="fields"></va-data-table>
    </va-list>
  </base-material-card>
</template>

<script>
export default {
  props: ["resource", "title"],
  data() {
    return {
      filter: {},
      filters: [
        "name",
        "founder",
        "headquarter",
        { source: "active", type: "boolean" },
      ],
      fields: [
        //...
      ],
    };
  },
  methods: {
    update(source, value) {
      this.filter = {
        ...this.filter,
        [source]: value,
      };
    },
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# Global actions

This VaList component comes with 2 provided global actions, which are create and export. The create button will only appear if current resource has create action and if authenticated user has create permission on this resource.

ACTION EVENTS

You're not forced keep the default redirect behavior button. If you prefer a create event, just subscribe to action event and disable create redirect via disableCreateRedirect prop for preventing create button to redirect to linked action page.

You will have the same behavior for show, edit and clone actions inside VaDataTable. Use item-action event and disable default redirect if you need custom behavior on your side as aside or dialog edition.

Note that all of this buttons will auto hide if no action exist for each related button. Deactivation of each relevant action redirect will force buttons to reappear.

This action events will always provide you the freshed item from the API as well as the adapted CRUD title. See the users list of Vue CLI Plugin for full example with aside.

# Export

The export button will process a CSV file download on client side. It simply takes the current search context and refetch data on server side, while keeping current filters and sorts without any pagination infos.

SERVER-SIDE EXPORT

Because the client-side exports has it's own limits and limited to basic CSV, you can always create a custom action that do an export on server-side. Create a custom href button as shown below and use disableExport prop. Your href should contain all search context provided by options without any pagination infos and redirect to a valid API endpoint that return a response with attachment content in order to provoke a file download.

# Custom actions

You can add custom actions via actions slot :




 
 
 





<template>
  <base-material-card>
    <va-list>
      <template v-slot:actions>
        <my-custom-button></my-custom-button>
      </template>
      <!-- VaDataTable -->
    </va-list>
  </base-material-card>
</template>
1
2
3
4
5
6
7
8
9
10

# Bulk actions

The data iterator support all sort of bulk operations, whether it be updating or deleting. This feature will use updateMany and deleteMany methods of you data provider. All available bulk actions will appear at header as soon as you have selected some items.

bulk-actions

# Custom bulk actions

By default VA provides a bulk delete action, but you can add any multiple bulk actions as needed by using bulk.actions slots and VaBulkActionButton that will use updateMany under the hood. This last component needs a required action prop that will be the object to send to your API. This object will contain all properties you want to bulk update.

The next example will show you a bulk publish / unpublish bulk actions :




 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





<template>
  <base-material-card>
    <va-list>
      <template v-slot:actions>
        <va-bulk-action-button
          :label="$t('users.enable')"
          icon="mdi-publish"
          color="success"
          :action="{ active: true }"
          text
        ></va-bulk-action-button>
        <va-bulk-action-button
          :label="$t('users.disable')"
          icon="mdi-download"
          color="orange"
          :action="{ active: false }"
          text
        ></va-bulk-action-button>
      </template>
      <va-data-table :fields="fields"></va-data-table>
    </va-list>
  </base-material-card>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

SELECTED ITEMS

VaBulkActionButton will automatically use injected search state to get all items to interact.

# Pagination

By default, VaList will use the default vuetify pagination control which allows direct page control navigation as well as number of shown item per page. Use itemsPerPage and itemsPerPageOptions in order to initialized the maximum number of shown item per page.

This default control is totally replaceable by your own pagination control. Use footer slot property for that and set hideDefaultFooter prop to true. This slot will provide all pagination context infos as well as server-side total of items.

# Usage outside list page

relationship

You're not forced to use VaList on list page ! As the same way for most of VA components, it can be used anywhere on any page or context thanks to resource prop which is present on all resource aware VA components. When not defined, the default resource will be the one linked to the current route.

Next example shows a good use case of VaList inside a VaEditLayout page in order to show some related resources linked to the current edited item resource.






 
 
 
 
 









<template>
  <va-edit-layout>
    <publishers-form :id="id" :title="title" :item="item"></publishers-form>
    <base-material-card icon="mdi-book" title="Books">
      <va-list
        resource="books"
        disable-query-string
        :filter="{
          publisher: id,
        }"
      >
        <va-data-table :fields="fields">
          <!-- VaDataTable -->
        </va-data-table>
      </va-list>
    </base-material-card>
  </va-edit-layout>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Note that the only thing to do is to provide explicitly the resource to fetch and use the filter which allows us to add internal filters, perfect place for adding the current resource as filter.

QUERY STRING

For this case usage, you may disable default query string update in order to prevent unexpected behavior. Use disable-query-string for that.

# Associations

associations

You can go even further by managing associations thanks to provided association prop object that give us the ability of attach or detach relationship between related resources directly from the list. It will automatically generate a autocomplete search on given list resource that allow us to attach via the associate button. Each row item can be detach via dissociate button.

See this example :















 











 















 
 
 
 
 





<template>
  <va-edit-layout>
    <authors-form :id="id" :title="title" :item="item"></authors-form>
    <base-material-card
      icon="mdi-book"
      :title="$tc('resources.books.name', 10)"
    >
      <va-list
        resource="books"
        disable-global-search
        disable-pagination
        disable-query-string
        disable-create
        disable-export
        :association="association"
        :filter="{
          authors: id,
        }"
        :include="['publisher', 'reviews']"
      >
        <va-data-table
          resource="books"
          disable-sort
          disable-select
          disable-clone
          disable-delete
          :association="association"
          :fields="fields"
        ></va-data-table>
      </va-list>
    </base-material-card>
  </va-edit-layout>
</template>

<script>
export default {
  props: ["id", "title", "item"],
  data() {
    return {
      fields: [
        //...
      ],
      association: {
        resource: "authors",
        source: "author_id",
        id: this.id,
      },
    };
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

Expected properties of association :

Property Type Description
resource string Resource that you want to link / unlink. Just for localization purpose.
source string Name of request key data to send on backend.
id number ID of current resource to detach.

For both associate and dissociate actions, the update data provider method will be called on the listed resource (which is books for this example) with this data : { <type>_<source>: <id> }. type will correspond to the type of operation, which is add or remove. It's up to you to make the effective association from server-side.

LARAVEL EXAMPLE

Here is a code sample you can use on your update endpoint of your controller for a pivot relation :

if ($id = $request->input('add_author_id')) {
    $book->authors()->attach($id);
}

if ($id = $request->input('remove_author_id')) {
    $book->authors()->detach($id);
}
1
2
3
4
5
6
7

# Editable rows

For simple resources, you can enable the direct row form mode :

editable-rows

Use both row-create and row-edit props to enable it :

  • row-create will add a new plus button inside header actions column. You may use disable-create inside direct parent VaList in order to disable normal creation behavior or simply disable create action for the concerned resource. On click it will show a empty new form at first row.
  • row-edit will change the default edit button behavior. On click it will transform the entire row into form row with pre filled values.















 



 
 
 
 
 






<template>
  <va-edit-layout>
    <books-form :id="id" :title="title" :item="item"></books-form>
    <base-material-card
      icon="mdi-comment"
      :title="$admin.getResource('reviews').pluralName"
    >
      <va-list
        resource="reviews"
        disable-query-string
        :items-per-page="10"
        :filter="{
          book: id,
        }"
        :filters="filters"
        disable-create
      >
        <va-data-table
          :fields="fields"
          row-create
          row-edit
          :create-data="{
            book_id: id,
          }"
        ></va-data-table>
      </va-list>
    </base-material-card>
  </va-edit-layout>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

FORM DATA

You may use create-data and update-data props for merging some external data into respective create and edit forms. Ideal for passing required properties for creation as the mandatory related book for any reviews.

# Custom layout

As you have seen, VaList is mainly a data iterator that will provide items result into his default slot children components, which is VaDataTable here. As the browsing UI structure is totally separated from the data list display, you can use any custom list layout as you want.

It will allow you to have this kind of nice card list layout while conserving all UI resource browsing controls with full pagination and filters.

custom-list-layout

The only thing to do is to use the default slot of VaList which allows you to implement your custom template item list from the provided items binding value as shown here :







 
 
 
 
 
 
 
 
 
 
 
 
 
 
 




<template>
  <base-material-card>
    <va-list
      :items-per-page="8"
      :items-per-page-options="[4, 8, 16, 32]"
    >
      <template v-slot="{ items }">
        <v-row>
          <v-col lg="3" v-for="item in items" :key="item.id">
            <v-card
              class="my-3 fill-height"
              flat
              :to="{ name: 'authors_show', params: { id: item.id } }"
            >
              <v-card-title>
                {{ item.name }}
              </v-card-title>
            </v-card>
          </v-col>
        </v-row>
      </template>
    </va-list>
  </base-material-card>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Aside usage sample

Instead of have separate CRUD pages for each action, it's possible to regroup all CRUD view operations into single page list thanks to VaAsideLayout component. It's perfect if you show and form views are relatively small.

aside

# AsideLayout

VaAsideLayout

Component to use for showing information on aside from any components. Use Portal Vue plugin internally for integrate within VaAside.

PROPS

Props Type Description
title string Title of aside.

SLOTS

Name Description
default Main content of the aside.

USELESS ROUTES

If you use aside for crud operations, you may disable related show, create and edit routes. As shown in resources guide section, use actions or except resource properties for that :

src/resources/index.js







 




export default [
  //...
  {
    name: "users",
    icon: "mdi-account",
    label: "name",
    actions: ["list", "delete"],
    permissions: ["admin"],
  },
];
1
2
3
4
5
6
7
8
9
10

The default users template generated by Vue CLI Plugin is a good showcase for that :



 
 
 
 




 






 





















 
 
 
 
 
 
 
 
 
 




<template>
  <div>
    <va-aside-layout :title="asideTitle">
      <users-show v-if="show" :item="item"></users-show>
      <users-form v-else :id="id" :item="item" @saved="onSaved"></users-form>
    </va-aside-layout>
    <base-material-card :icon="resource.icon" :title="title">
      <va-list
        ref="list"
        disable-create-redirect
        @action="onAction"
      >
        <va-data-table
          :fields="fields"
          disable-create-redirect
          disable-show-redirect
          disable-edit-redirect
          @item-action="onAction"
        ></va-data-table>
      </va-list>
    </base-material-card>
  </div>
</template>

<script>
export default {
  props: ["resource", "title"],
  data() {
    return {
      fields: [
        //...
      ],
      asideTitle: null,
      id: null,
      item: null,
      show: false,
    };
  },
  methods: {
    async onAction({ action, title, id, item }) {
      this.asideTitle = title;
      this.id = id;
      this.show = action === "show";
      this.item = item;
    },
    onSaved() {
      this.asideTitle = null;
      this.$refs.list.fetchData();
    },
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

It's mainly a combination of all available event actions via action and item-action which retrieve the freshed item from the API and CRUD title. Then all that's left is to disable default redirect and made some additional logic for show or hide the view or form while auto open aside via value prop of VaAsideLayout. Check the users CRUD sample for further detail.

# Treeview

This component will be ideal for all hierarchical data management as categories, menus or any generic taxonomies. It supports inline node edition and deletion with additional create form at the bottom, while keeping each node fully customizable via slots. Moreover it uses the customized Vuetify original Treeview under the hood which adds draggable support !

treeview

# API

VaTreeview

Treeview component which support fully editable items with draggable feature and hierarchical data.

MIXINS

Resource

PROPS

Props Type Description
value array All selected items via checkbox, can be use via v-model.
itemKey string Unique identifier for each node, id by default.
itemText string Label text for each node, name by default.
selectable boolean Enable checkbox selection.
openAll boolean Open all nodes by default. Can't be used with lazy.
dense boolean Reduce height of each node.
lazy boolean Enable lazy items loading while node opening. Use getNodes data provider method instead of getTree.
editable boolean Enable full editable mode with drag & drop.
disableCreate boolean Disable new item creation form.
disableEdit boolean Disable item edit button.
disableDelete boolean Disable item deletion button.
disableInlineEdit boolean Disable default inline edit form behavior. You may use item-edit event in order to add your custom edit logic.
filter object Internal active filter. Sent to your data provider inside filter params.
createData object Additional form object data to merge when new item created.
updateData object Additional form object data to merge when specific item updated.

SLOTS

Name Description
item Use for full node templating.

EVENTS

Name Description
input Triggered when nodes are selected via checkboxes.
item-moved Triggered when node moved.
item-edit Triggered when node enter edit mode.
item-created Triggered when new node created.
item-updated Triggered when node updated.
item-deleted Triggered when node deleted.

# Tree data provider methods

Know that you will need to implement following specific data providers methods in order to allow hierarchical data manipulation.

const dataProvider = {
  getTree:    (resource, params) => Promise,
  getNodes:   (resource, params) => Promise,
  moveNode:   (resource, params) => Promise,
}
1
2
3
4
5

# Tree methods call signatures

Method Description Parameters format
getTree Get full hierarchical data as tree format. { filter: Object }
getNodes Get sibling nodes of optional given parent. load only root nodes if parent empty. { filter: Object, parent: Object }
moveNode Allow node moving to specific position of specific optional parent. { id: Any, source: Object, destination: Object, position: int }
// Fetching categories as tree
let { data } = await provider.getTree("categories", { filter: { type: 'book' } });
console.log(data)

// Fetching root categories
let { data } = await provider.getNodes("categories", { filter: { type: 'book' } });
console.log(data)

// Fetching children of given parent category
let { data } = await provider.getNodes("categories", { parent: { id: 1, name: "BD" } });
console.log(data)

// Move category to specific position at specific other category
await provider.moveNode("categories", { source: { id: 10, name: "Marvel" }, destination: { id: 1, name: "BD" }, position: 3 });
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# Tree API call formats

Operation API call format Response format
getTree GET /categories/tree { data: Resource[] }
getNodes GET /categories/nodes/{parentId?} { data: Resource[] }
moveNode PATCH /categories/{categoryId}/move { data: Resource }

Note as the getTree method will wait for a valid tree formatted list. Each node item must have a specific children property which contain all sub-nodes as following :

[
  {
    id: 1,
    name: "Comics",
    children: [
      { id: 3, name: "Detective Comics" },
      { id: 4, name: "Manga" },
      { id: 2, name: "Marvel" },
    ],
  },
  {
    id: 10,
    name: "Culture",
    children: [
      { id: 11, name: "History" },
      { id: 12, name: "Biography" },
      { id: 13, name: "Cinema" },
      { id: 14, name: "Music" },
      { id: 15, name: "Politics" },
      { id: 16, name: "Economy" },
    ],
  },
  ...
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

KEY AND DISPLAYED TEXT

By default treeview will use id as key and name as displayed label. But it can be changed thanks to itemKey and itemText props.

# Component usage

Once all above data provider methods implemented, you can finally use treeview component as following :



 
 
 
 
 
 
 









<template>
  <base-material-card :icon="resource.icon" :title="title">
    <va-treeview
      open-all
      dense
      editable
      :filter="{ type: 'book' }"
      :create-data="{ type: 'book' }"
    ></va-treeview>
  </base-material-card>
</template>

<script>
export default {
  props: ["resource", "title"],
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

As other resource based components, treeview will use linked resource of current route as default (use resource prop for override). It will automatically fetch all nodes (or only root nodes if lazy prop active) as tree format.