Svinjica
Svinjica

Reputation: 2519

I'm losing content of the elements when I'm navigating by Vue Router

I'm trying to create a simple SPA using Vue Router and the Vuetify framework. I have several components connected to my router. When I first reload a view, everything works fine, but when I move from that view and come back, I completely lose the contents of it.

Here is HTML code:

<template>
  <v-layout fill-height id="map" class="cadetblue" style="width: 100%">
    <v-dialog v-model="dialog" width="500">
      <v-card>
        <v-img src="https://cdn.vuetifyjs.com/images/cards/sunshine.jpg" height="200px"></v-img>

        <v-card-title primary-title>
          <div>
            <div class="headline">Select layers</div>
            <span class="grey--text">Some layers are avaliable</span>
          </div>
        </v-card-title>

        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn icon @click="layers = !layers">
            <v-icon>{{ layers ? 'keyboard_arrow_down' : 'keyboard_arrow_up' }}</v-icon>
          </v-btn>
        </v-card-actions>

        <v-slide-y-transition>
          <v-card-text v-show="true">
            <v-checkbox @change="clickMew()" id="dofLayer" label="DOF"></v-checkbox>
            <v-checkbox name="tkLayer" id="tkLayer" label="TK25"></v-checkbox>
          </v-card-text>
        </v-slide-y-transition>
      </v-card>
    </v-dialog>
    <v-flex>
      <v-btn
        absolute
        id="zoomIn"
        @click="zoomIn()"
        dark
        fab
        top
        left
        small
        color="pink"
        class="mt-5"
      >
        <v-icon>add</v-icon>
      </v-btn>
      <v-btn
        absolute
        id="zoomOut"
        @click="zoomOut()"
        dark
        fab
        top
        left
        small
        color="pink"
        class="mt-6"
      >
        <v-icon>remove</v-icon>
      </v-btn>
      <v-btn absolute id="home" @click="home()" dark fab top left small color="green" class="mt-7">
        <v-icon>home</v-icon>
      </v-btn>
      <v-speed-dial
        class="mb-5"
        fixed
        bottom
        right
        direction="top"
        transition="slide-y-reverse-transition"
      >
        <v-btn slot="activator" id="test" color="blue darken-2" dark fab>
          <v-icon>account_circle</v-icon>
        </v-btn>

        <v-btn fab id="addLayer" dark small color="green">
          <v-icon>edit</v-icon>
        </v-btn>

        <v-btn fab @click="dialog = true" dark small color="green">
          <v-icon>layers</v-icon>
        </v-btn>
      </v-speed-dial>
    </v-flex>
  </v-layout>
</template>

And here are script part:

import {
  map,
  initMap,
  interactivity,
  zoomIn,
  zoomOut,
  home,
  addHok,
  consoleMsg
} from "../../scripts/cro";

export default {
  data: () => {
    return {
      links: [
        { icon: "account_circle", color: "blue darken-2" },
        { icon: "edit", color: "green" },
        { icon: "add", color: "indigo" }
      ],
      neven: "TEsting Neven",
      dialog: false,
      layers: false
    };
  },
  methods: {
    zoomIn() {
      zoomIn();
    },
    zoomOut() {
      zoomOut();
    },
    home() {
      home();
    },
    clickMew() {
      addHok();
    }
  },
  created() {
    this.$nextTick(() => {
      initMap();
    });
  },
  mounted() {
    this.$nextTick(() => {
      initMap();
      consoleMsg();
      // interactivity();
    });
  }
};

Here is the router page (router.js):

import Vue from 'vue'
import Router from 'vue-router'
import Dashboard from './views/Dashboard.vue'
import Projects from './views/Projects.vue'
import Team from './views/Team.vue'

    Vue.use(Router)

    export default new Router({
      mode: 'history',
      base: process.env.BASE_URL,
      routes: [
        {
          path: '/',
          name: 'dashboard',
          component: Dashboard
        },
        {
          path: '/projects',
          name: 'projects',
          component: Projects
        },
        {
          path: '/team',
          name: 'team',
          component: Team
        }
      ]
    })

UPDATE

As ljubadr pointed out, there is some workaround with keep-alive. I tried wrapping router-view like this:

<template>
  <v-app>
    <Navbar></Navbar>
    <Modal></Modal>
    <v-content>
        <keep-alive include="projects">
        <router-view></router-view>
        </keep-alive>
    </v-content>
    <Footer></Footer>
  </v-app>
</template>

Here is App.vue

It did not help :(

<template>
  <v-app>
    <Navbar></Navbar>
    <Modal></Modal>
    <v-content>
      <keep-alive include="projects">
        <router-view></router-view>
      </keep-alive>
    </v-content>
    <Footer></Footer>
  </v-app>
</template>

<script>
import Navbar from "@/components/NavBar";
import Footer from "@/components/Footer";
import Modal from "@/components/Modal";

export default {
  name: "App",
  components: { Navbar, Footer, Modal }
};
</script>

Upvotes: 0

Views: 1347

Answers (1)

ljubadr
ljubadr

Reputation: 2254

You can use <keep-alive>. Read more about it here

There are some disadvantages to this approach:

you lose lifecycle hooks like created, mounted, etc. since the component is not being rebuilt from scratch anymore. You can replace those lifecycle hooks with hooks that are specific to keep-alive components

First approach

You can then specify which components to keep alive, by specifying

<keep-alive include="component1,component2">
  <router-view></router-view>
</keep-alive>

where those components need to have the matching name property:

name: 'component1'

Second approach

We can also use <keep-alive> with Route Meta Fields, where we have more granular control in the router on which components to keep alive (I've used the code from this codepen by Linusborg)

Router

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', 
      component: Home,
      meta: { keepAlive: false } 
    },
    { path: '/foo',
      component: Foo,
      meta: { keepAlive: true }
    }
  ]
})

Template

<transition name="fade" mode="out-in">
  <keep-alive v-if="$route.meta.keepAlive">
    <router-view></router-view>
  </keep-alive>

  <router-view v-else></router-view>
</transition>

Upvotes: 3

Related Questions