loading...
Cover image for Ionic Framework with VueJS: Split-View Menu with Authentication Flow Using, Vuex & Vue Composition

Ionic Framework with VueJS: Split-View Menu with Authentication Flow Using, Vuex & Vue Composition

aaronksaunders profile image Aaron K Saunders Updated on ใƒป4 min read

Remember: Ionic VueJS Support is Still in Beta

Overview

Ionic Framework with VueJS build a Split-View user interface with Side menu. The application uses the official vuejs state manager, vuex, for authentication state management in the login flow. We also use information from the store to protect routes and hide the side-menu when the user is not authenticated.

The second part of the blog post, we show how to do the same but using the new Vue Composition API to manage state and implement the same functionality.

Since Vue Composition API is for v3.x, we re using a plugin to provide that functionality to this v2.x application

This post is to cover the important pieces of the code; the bulk of the details are contained in the two video showing each of the specific implementations

๐Ÿ“บ You can jump to end of post to see the videos...

Using Vuex

Setup

Import the store in main.js

import store from "./store";

Checking for user when app starts up

store.dispatch("user/checkAuth").then(() => {
  new Vue({
    render: h => h(App),
    store,
    router
  }).$mount("#app");
});

Protecting Routes

We need to get access to the state information in our beforeEnter handler to protect routes. Since we are using namespaces, the user state is at store.state.user and the actual user is store.state.user.user in this case we are checking for the existence of a user to determine if we should allow access to the specific route

const privateRoute = (to, from, next) => {
  let userStore = store.state.user;
  let isAuthenticated = userStore.user !== null;
  console.log("isAuthenticated:" + isAuthenticated);

  if (!isAuthenticated) {
    next({ name: "login" });
  } else {
    next();
  }
};

Logging Into Application

For logging into the application we can access the store using $store and dispatch the login function the combination of the namespace and the action and passing the payload.

// login.vue
export default {
  name: "Login",
  methods: {
    async doLogin() {
      let result = await this.$store.dispatch("user/login", {
        email: this.email,
        password: this.password
      });
      if (result) {
        console.log(this.$store.state);
        this.$router.push("/");
      }
    }
  },

Controlling Menu Display and Content

we use a computed property to get the currentUser

computed: {
  currentUser() {
    return this.$store.state.user.user;
  }
},

For logging out we dispatch the logout action in the same manner that we dispatched the login action above

async logout() {
  let menuController = document.querySelector("#main-menu");
  await menuController.close(true);
  await store.dispatch("user/logout");
  this.$router.replace("/login");
}

To hide the menu we use currentUser computed property from the component, we could have used isLoggedIn

<template >
  <ion-menu content-id="main" side="start" 
            id="main-menu" v-if="currentUser"
...rest of template code
</template>

The Store

Since we we are using namespaces we need to do a bit more setup on the store.

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './auth-store'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    user,
  },
})
export default {
  namespaced: true,

  state: {
    user: null,
    authChecked: false,
  },

  // ACTIONS (asynchronous)
  actions: {
    checkAuth({ commit }) {
      let state = this.state.user;
      return new Promise((resolve) => {
        commit("checkAuth", { authChecked: true, user: state.user });
        resolve(true);
      });
    },
    login({ commit }, payload) {
      if (payload.email !== "") {
        commit("hasUser", { ...payload });
        return true;
      } else {
        commit("clearUser", {});
        return false;
      }
    },
    logout({ commit }) {
      return new Promise((resolve) => {
        commit("clearUser", {});
        resolve(true);
      });
    },
  },

  // MUTATIONS ( set the state )
  mutations: {
    hasUser(state, payload) {
      state.user = { ...payload };
    },
    clearUser(state, payload) {
      state.user = null;
    },
    checkAuth(state, payload) {
      state.user = payload.user;
      state.authChecked = payload.authChecked;
    },
  },
};

Using Vue Composition

Setup

// main.js
import VueCompositionApi from "@vue/composition-api";
Vue.use(VueCompositionApi);

Protecting Routes

We need to get access to the state information in our beforeEnter handler to protect routes

const privateRoute = (to, from, next) => {

let { state } = useAuth();
let isAuthenticated = state.value.loggedIn;
... rest of the code

Logging Into Application

For logging into the application we don't need to use the setup approach as we did above, you can just import useAuth and call the function on the module

<script>
import useAuth from "../useAuth";
export default {
  name: "Login",
  methods: {
    async doLogin() {
      let { login } = useAuth();
      login();
      this.$router.push("/");
    }
  },
... rest of script
</script>

Controlling Menu Display and Content

<script>
import useAuth from "../useAuth";

export default {
  name: "Menu",
  // VUE COMPOSITION
  setup() {
    let { state, logout } = useAuth();
    return {
      state: state.value,
      logout
    };
  },

In this component, we are using the new setup functionality to incorporate the information returned from the vue composition api in the the component as data properties.

Now to call the logout function you must use this.logout. To hide the menu we can get the loggedIn state from the component now

<template >
  <ion-menu content-id="main" side="start" 
            id="main-menu" v-if="state.loggedIn">
...rest of template code
</template>

The Store

I tried to keep the store straight forward with no real code for authentication, this is really to demonstrate the approach.

So just calling the login function will log the user in and set the appropriate state values.

The logout function clears the user object and sets loggedIn to false.

// useAuth.js
import Vue from "vue";
import VueCompositionApi, { computed, ref } from "@vue/composition-api";
Vue.use(VueCompositionApi);

// STATE
const state = ref({
  user: {},
  loggedIn: false,
  error: {},
});

export default function() {
  return {
    state: computed(() => state.value),
    login: () => {
      state.value.user = { id: 100, name: "aaron" };
      state.value.loggedIn = true;
    },
    logout: () => {
      state.value.user = {};
      state.value.loggedIn = false;
    },
  };
}

๐Ÿ“บ Videos


Posted on Jun 1 by:

aaronksaunders profile

Aaron K Saunders

@aaronksaunders

See more, like and subscribe ๐Ÿ‘‰๐Ÿพ โ€ชAaron Saunders ๐Ÿ“บ https://www.youtube.com/aaronsaundersci?sub_confirmation=1

Discussion

markdown guide
 

When you access the code in github, make sure you are checking the branches... the vue-composition code is on a separate branch "vue-composition"