Comment intégrer un système d’onglets

Prérequis

Afin de pouvoir suivre ce guide, il faut préalablement avoir intégré un composant AP4.

Introduction

On se propose ici de mettre en place un système d’onglets pour chaque section. Le premier onglet comportera la grille créée précédemment. Un clic sur le rang de la grille ouvrira le Smart Element correspondant dans un nouvel onglet, en mode consultation. Un clic sur le boutton d’ajout d’un onglet ouvrira un formulaire de création du Smart Element.

Recommandation

Pour vous familiariser avec l’utilisation du système d’onglets proposé par Anakeen Platform 4, il est fortement recommandé de consulter la documentation associée disponible ici.

Comment configurer le store de notre application

Afin de garder un état persistent des onglets par section dans notre application, nous utiliserons le store Vue directement inclus dans Nuxt.js

Recommandation

Si vous n’êtes pas familier avec le concept de Vuex et de store, il est fortement recommandé de lire la documentation associée disponible ici.

Il est également recommandé de consulter la documentation d’utilisation du store avec Nuxt.js disponible ici.

Créer le répertoire store à la racine :

mkdir store

Créer les fichiers store/boisson.js, store/menu.js et store/plat.js avec le contenu identique suivant :

touch store/boisson.js store/menu.js store/plat.js
export const state = () => ({
  tabs: [],
});

export const mutations = {
  pushTab(state, tab) {
    state.tabs.push(tab);
  },
  removeTab(state, tabId) {
    state.tabs = state.tabs.filter((tab) => tab.tabId !== tabId);
  },
};

export const getters = {
  getTabs: (state) => state.tabs,
};

l’arborescence du répertoire store est alors :

store
├── boisson.js
├── menu.js
└── plat.js

Comment configurer les onglets Anakeen Platform 4

Recommandation

Dans l’exemple suivant, nous utiliserons le routeur Vue intégré à Nuxt.js. Si vous n’êtes pas familier avec ces concepts, il est fortement recommandé de lire la documentation associée disponible ici.

Modifier le fichier le composant de section components/RestauratecSection.vue :

<template>
  <div class="restauratec-section">
    <ank-tabs
      v-model="selectedTab"
      ref="ankTabs"
      @tabRemove="onTabRemove"
      @tabClick="onTabClick"
      @tabAdd="onTabAdd"
      :addable="!isCreationTabOpened"
    >
      <ank-tab tabId="grid" label="Smart Elements">
        <div class="restauratec-grid">
          <ank-se-grid
            :collection="gridConfig.collection"
            :columns="gridConfig.columns"
            :actions="gridActions"
            @rowActionClick="onRowActionClick"
          />
        </div>
      </ank-tab>
      <ank-smart-tab
        v-for="(tab, index) in tabs"
        :identifier="tab.initid"
        :tabId="tab.tabId"
        :key="tab.tabId"
        :viewId="tab.viewId"
        closable
      />
    </ank-tabs>
  </div>
</template>
<script>
import Vue from "vue";
import AnkTabs from "@anakeen/user-interfaces/components/lib/AnkTabs.esm";
import AnkSmartTab from "@anakeen/user-interfaces/components/lib/AnkSmartElementTab.esm";
import AnkTab from "@anakeen/user-interfaces/components/lib/AnkTab.esm";
import AnkSmartElementGrid from "@anakeen/user-interfaces/components/lib/AnkSmartElementGrid.esm";
import setup from "@anakeen/user-interfaces/components/lib/setup.esm";
Vue.use(setup);

export default {
  components: {
    "ank-se-grid": () =>
      new Promise((resolve) => {
        Vue.$_globalI18n.recordCatalog().then(() => {
          resolve(AnkSmartElementGrid);
        });
      }),
    AnkTabs,
    AnkSmartTab: () => AnkSmartTab,
    AnkTab,
  },
  props: ["section", "gridConfig"],
  data() {
    return {
      gridActions: [
        {
          action: "display",
          title: "Afficher",
          iconClass: "fa fa-eye",
        },
      ],
    };
  },
  computed: {
    selectedTab: {
      get: function () {
        return this.$route.params.tab ? this.$route.params.tab : "grid";
      },
      set(tab) {
        this.$router.push(`/${this.section}/${tab}`);
      },
    },
    tabs() {
      return this.$store.getters[`${this.section}/getTabs`];
    },
    isCreationTabOpened() {
      return this.tabs.filter((tab) => tab.tabId === "creation").length > 0;
    },
  },
  methods: {
    onRowActionClick(e) {
      if (e.data.type === "display") {
        e.preventDefault();
        const initid = e.data.row.properties.initid.toString();
        const tab = {
          initid,
          tabId: initid,
          viewId: "!defaultConsultation",
        };
        this.addTab(tab);
        this.selectTab(tab.tabId);
      }
    },
    addTab(tab) {
      this.$store.commit(`${this.section}/pushTab`, tab);
    },
    onTabRemove(tabId) {
      this.removeTab(tabId);
      const nextTabId = this.tabs.length ? this.tabs[this.tabs.length - 1].tabId : "grid";
      this.selectTab(nextTabId);
    },
    removeTab(tabId) {
      this.$store.commit(`${this.section}/removeTab`, tabId);
    },
    onTabClick(e) {
      this.selectTab(e.tabId);
    },
    selectTab(tabId) {
      this.selectedTab = tabId;
    },
    onTabAdd() {
      const tab = {
        initid: this.gridConfig.collection,
        tabId: "creation",
        viewId: "!defaultCreation",
      };
      this.addTab(tab);
      this.selectTab(tab.tabId);
    },
  },
};
</script>
<style lang="scss">
.restauratec-section {
  display: flex;
  flex-direction: column;
  align-items: center;

  .ank-tabs {
    width: 100%;

    .ank-tab-pane {
      display: flex;
      flex-direction: column;
      align-items: center;

      .restauratec-grid {
        height: 39rem;
        width: 80%;
        margin-top: 5rem;
        border: 1px solid;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }
    }
  }
}
</style>

Recommandation

Nous allons utiliser le système de routes dynamiques de Nuxt.js. Si vous n’êtes pas familier avec ces concept, il est fortement recommandé de lire la documentation associée disponible ici.

Déplacer le fichier /pages/Boisson.vue vers /pages/boisson/_tab.vue :

mkdir pages/boisson && mv pages/Boisson.vue pages/boisson/_tab.vue

Faire de même avec Plat et Menu:

mkdir pages/plat && mv pages/Plat.vue pages/plat/_tab.vue
mkdir pages/menu && mv pages/Menu.vue pages/menu/_tab.vue

Modifier le contenu de chaque fichier _tab.vue :

  • pages/boisson/_tab.vue :


 
















 








<template>
  <div class="restauratec-boisson-wrapper">
    <restauratec-section :gridConfig="gridConfig" :section="section" />
  </div>
</template>
<script>
import RestauratecSection from "../../components/RestauratecSection";
export default {
  components: { RestauratecSection },
  key(route) {
    return route.name;
  },
  data() {
    return {
      gridConfig: {
        collection: "BOISSON",
        columns: [
          { field: "consommable_title" },
          { field: "consommable_creator" },
          { field: "consommable_price_incl_vat" },
        ],
      },
      section: "boisson",
    };
  },
};
</script>
  • pages/menu/_tab.vue :


 












 








<template>
  <div class="restauratec-menu-wrapper">
    <restauratec-section :gridConfig="gridConfig" :section="section" />
  </div>
</template>
<script>
import RestauratecSection from "../../components/RestauratecSection";
export default {
  components: { RestauratecSection },
  key(route) {
    return route.name;
  },
  data() {
    return {
      gridConfig: {
        collection: "MENU",
        columns: [{ field: "menu_title" }, { field: "menu_price" }],
      },
      section: "menu",
    };
  },
};
</script>
  • pages/plat/_tab.vue :


 












 








<template>
  <div class="restauratec-plat-wrapper">
    <restauratec-section :gridConfig="gridConfig" :section="section" />
  </div>
</template>
<script>
import RestauratecSection from "../../components/RestauratecSection";
export default {
  components: { RestauratecSection },
  key(route) {
    return route.name;
  },
  data() {
    return {
      gridConfig: {
        collection: "PLAT",
        columns: [{ field: "consommable_title" }, { field: "consommable_creator" }, { field: "plat_type" }],
      },
      section: "plat",
    };
  },
};
</script>

L’arborescence finale du répertoire pages est alors :

pages
├── boisson
│   └── _tab.vue
├── index.vue
├── menu
│   └── _tab.vue
└── plat
    └── _tab.vue

Tester nos modifications

Lancez le serveur Anakeen Platform 4 :

make env-start

Puis lancez le serveur de développement :

npm run dev

Vous pouvez voir les onglets sous chaque section, par exemple http://localhost:3000/plat :

RestauratecTabs

Et ensuite ?

Comment internationaliser notre application