rguttersohn
rguttersohn

Reputation: 484

Router view will not update when when clicking on router link embedded within view using Vue Router

I have a Related Content section at the bottom of my posts page that shows other related posts.

When clicking on the Related Content, I am hoping for the router to update the page. However, this is not happening. The url is changing, but the view does not update.

Components

Post.Vue

<template>
  <div class="post-container" >
    <router-view name="PostContent">
      <h2>test</h2>
    </router-view>
    <div v-if="currentPost !== ''">
      <img :src="currentPost.jetpack_featured_media_url" />
      <!-- <h1 v-html="currentPost.title.rendered"></h1> -->
      <div
        v-html="currentPost.excerpt.rendered"
        class="post-excerpt-container"
      ></div>
      <div
        v-html="currentPost.content.rendered"
        class="post-content-container"
      ></div>
    </div>
    <section class="related-content">
       <h2>Related Content:</h2>
       <p v-if="currentPost.title !== undefined">If you enjoyed {{currentPost.title.rendered}}, we think you'll like:</p>
      <div class="related-content-container" v-for="relatedPost in relatedPosts" :key="relatedPost.id" :data-id="relatedPost.id">
          <router-link :to="{name:'Post',params:{id:relatedPost.id}}">
          <RelatedCard :post='relatedPost' />
          </router-link>
      </div>
    </section>
  </div>
</template>

<script>
import { mapState } from "vuex";
import RelatedCard from '@/components/RelatedCard.vue';
export default {
  name:"Post",
  components:{RelatedCard},
  data() {
    return {
      currentPost: "",
      id: this.$route.params.id,
      relatedPosts: []
    };
  },
  computed: {
    ...mapState({
      baseAPIURL: (state) => state.baseAPIURL,
      posts: (state) => state.posts,
    }),
  },
  created() {
    console.log('created')
    fetch(`${this.baseAPIURL}/posts/${this.id}?_embed`)
      .then((resp) => resp.json())
      .then((post) => {
        this.currentPost = post;
      });
  },
  methods: {
    pushToRelated() {      
      this.posts.forEach((post) => {
        post.relatedScore = 0;
        if (post.id !== this.currentPost.id) {
          post._embedded['wp:term'][0].forEach(el=>{
            for(let i  = 0;i < this.currentPost._embedded['wp:term'][0].length;i++){
              if (el.name === this.currentPost._embedded['wp:term'][0][i].name){
                post.relatedScore = post.relatedScore + 3
              }
            }
          })
          post._embedded['wp:term'][1].forEach(el=>{
            for(let i  = 0;i < this.currentPost._embedded['wp:term'][1].length;i++){
              if (el.name === this.currentPost._embedded['wp:term'][1][i].name){
                post.relatedScore = post.relatedScore + 1
              }
            }
          })
        }
      });
      this.relatedPosts = this.posts.sort((a,b)=>a.relatedScore - b.relatedScore).reverse().slice(0,5)
    }
  },
  watch: {
   currentPost: function () {
     if (this.posts.length > 0){
      this.pushToRelated();
     }
    },
  }
};
</script>

RelatedCard.vue

<template>
    <div class="related-card">
      <div>
        <img v-if="post._embedded['wp:featuredmedia'][0].media_details.sizes.medium_large !== undefined" :src="postImageML" alt="" />
        <img v-else :src="postImage" alt="">
      </div>
      <div>
        <h2 v-html="post.title.rendered"></h2>
        <p v-html="post.excerpt.rendered"></p>
      </div>
    </div>
</template>

<script>
export default {
  props: {
    post: Object,
  },
  computed:{
    postImageML(){
      return this.post._embedded['wp:featuredmedia'][0].media_details.sizes.medium_large.source_url
    },
    postImage(){
      return this.post._embedded['wp:featuredmedia'][0].media_details.sizes.full.source_url
    }
  },
};
</script>

My Router Config

const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
  },
  {
    path: "/list",
    name: "List",
    component: List,
  },
  { path: "/database", name: "Database", component: Database },
  {path:"/post/:id",name:"Post",component:Post}
];

const router = new VueRouter({
  routes,
});

export default router;

What I have tried:

I have tried using $router.go(). This worked in updating the page. However, after rerendering, my watchers were not working properly. Plus I was losing the ability for a user to go back to the previous post.

I also tried using component keys on the wrapper element, but I had no luck.

Any pointers on why this would be happening and what I can do to fix it would be great.

Upvotes: 2

Views: 1367

Answers (2)

Dan
Dan

Reputation: 63119

When you enter a route whose component is currently rendered, by default the component is reused, and for that reason created is not called. You could:

Use a :key

Using a key means the component will not be reused if the key doesn't match. Change your router-view to:

<router-view :key="$route.fullPath" />

Each separate param will change the full path of the router and give a unique key.

-OR-

Use the updated hook

Unlike created, this is called whenever the param changes. But it's not called on the first load like created, so you'd need to use both hooks. (NOTE: Things other than a param change may also trigger the updated hook, so you'd need to be careful not to do any expensive operations in it.)

created() {
  // Do whatever when the component loads
},
updated() {
  // Do whatever when the component updates
}

Upvotes: 4

Mikael Dalholm
Mikael Dalholm

Reputation: 131

i have not read all of your code, but try add the history mode to the router.

const router = new VueRouter({
  routes,
  mode: 'history', // Add this
});

Upvotes: 0

Related Questions