1

EDITED -

Best to start this over.

I have a VUE js CLI app - it calls the DB from the APP.vue page and then dispurses the data to the other pages and nav bar -

The nav bar calls a router function:

loadRouter(articles){
          this.$router.push({name: 'Articles', params: {articles: articles}})
      }

However this is now causing 2 issues:

  1. the component does not re-load with new data when a new nav is clicked

  2. I receive an error:

    Error: Avoided redundant navigation to current location: "/articles".

enter image description here

The CODE:

app.vue <<<< this file makes the fetch call then passes that data to the component NAV bar (seen in <Navbar :articleData="articleData"/>)

<template>
  <div id="app">
    <div class="topElements">
      <Navbar :articleData="articleData"/>
      
      <router-view/>
    </div>
      <Footer />
  </div>
</template>

<script>
import Navbar from '@/components/Nav.vue'

import Footer from '@/components/Footer.vue'
export default {
  components: {
    Navbar,
    Footer
  },
  data(){
    return {
      articleData: null,


      //   set up a variable for the local host as this will change later when the enviroment moves online
      enviroment: 'http://localhost:1337/',
    }
  },
  created(){
    fetch(`${this.enviroment}languages`)
    .then(responce => responce.json())
    .then(data => {this.articleData = data})
  }
}
</script>

Navbar.vue << this is where the user selects the language (article) - this is done via a @click event that then calls the callback which $route.push the Article component and props

template>
  <div class="navigationContainer">
      <div class="languageContainer" v-for="item in articleData" :key="item.id">
          <h2 @click="loadRouter(item.articles)">{{ item.title }}</h2>
      </div>
  </div>
</template>

<script>
export default {
  name: 'Navbar',
  props: ['articleData'],
  data(){
      return{

      }
  },
  methods: {
      loadRouter(articles){
          this.$router.push({name: 'Articles', params: {articles: articles}})
      }
  } 
}
</script>

Articles.vue << lastly the articles page displays all the articles here by being passed as a prop the (the initial props does load but then does not re-load when a new nav is clicked and the error i mentioned above is shown)

Articles.vue

<template>
  <div class="articleContainer">
     <p>{{ articles }}</p>  <<< just to display if the props has come through correctly - will be changed later
  </div>
</template>

<script>
export default {
    name: 'Articles',
    props: ['articles'],
    data(){
      return{
        articleData: null,
      }
    },
    watch: {
      articles(){
        this.articleData = this.articles; <<<< trying to update the component when A new $route is detected - I also tried this with $route
        console.log(articleData) <<< checking if it worked.... 
      }
    }
}
</script>

Thats allot to read so I just wanted to say thank you for any help that can be given here.

Warm regards, Wally

p.s.

Ask any questions you might have

EDITED:

article data from: http://localhost:1337/languages

Its an array of OBJS being pulled from the STRAPI API (I've made it public)

[
{
"id": 1,
"title": "JS",
"created_at": "2020-07-10T08:30:33.156Z",
"updated_at": "2020-07-10T08:30:33.156Z",
"articles": [
{
"id": 4,
"title": "hamburger menu",
"description": "This is where I would explain how to make a front end hamburger menu style for the navigation of a web page",
"created_at": "2020-07-10T08:32:11.474Z",
"updated_at": "2020-07-10T08:32:11.474Z"
}
]
},
{
"id": 2,
"title": "HTML",
"created_at": "2020-07-10T08:30:38.437Z",
"updated_at": "2020-07-10T08:30:38.437Z",
"articles": [
{
"id": 4,
"title": "hamburger menu",
"description": "This is where I would explain how to make a front end hamburger menu style for the navigation of a web page",
"created_at": "2020-07-10T08:32:11.474Z",
"updated_at": "2020-07-10T08:32:11.474Z"
},
{
"id": 5,
"title": "WEB STRUCTURE",
"description": null,
"created_at": "2020-07-10T10:08:44.221Z",
"updated_at": "2020-07-10T10:08:44.221Z"
}
]
},
{
"id": 3,
"title": "CSS",
"created_at": "2020-07-10T08:30:43.107Z",
"updated_at": "2020-07-10T08:30:43.107Z",
"articles": [
{
"id": 4,
"title": "hamburger menu",
"description": "This is where I would explain how to make a front end hamburger menu style for the navigation of a web page",
"created_at": "2020-07-10T08:32:11.474Z",
"updated_at": "2020-07-10T08:32:11.474Z"
}
]
},
{
"id": 4,
"title": "VUE",
"created_at": "2020-07-10T10:52:11.390Z",
"updated_at": "2020-07-10T10:52:11.390Z",
"articles": []
},
{
"id": 5,
"title": "NODE JS",
"created_at": "2020-07-10T10:52:23.351Z",
"updated_at": "2020-07-10T10:52:23.351Z",
"articles": []
},
{
"id": 6,
"title": "SASS",
"created_at": "2020-07-10T10:52:31.450Z",
"updated_at": "2020-07-10T10:52:31.450Z",
"articles": []
},
{
"id": 7,
"title": "PHP",
"created_at": "2020-07-12T19:21:48.620Z",
"updated_at": "2020-07-12T19:21:48.620Z",
"articles": []
},
{
"id": 8,
"title": "GIT",
"created_at": "2020-07-12T19:22:02.208Z",
"updated_at": "2020-07-12T19:22:02.208Z",
"articles": []
}
]
Wally
  • 705
  • 1
  • 9
  • 24
  • 1
    You're trying to pass an array through the route and it expects a primitive value. You either need to use [function mode](https://router.vuejs.org/guide/essentials/passing-props.html#function-mode) similar to [this](https://stackoverflow.com/questions/50506470/how-to-pass-an-object-as-props-with-vue-router) or pass just an id and do a lookup somewhere. – Steven B. Jul 29 '20 at 21:21
  • Thank you for the reply - I have altered my work to send a primitive through but it's not very efficient really - initially I have made a fetch requestion which loads all data on the nav bar - which then I wanted to pass via routes to the component, with this method I'm making multiple fetch requests..... which doesn't seem correct (but I'm very possibly wrong here) -- thanks again for the help – Wally Jul 30 '20 at 08:44
  • Hi Steve - thank you for your suggestion - I have followed this and made some changed to the code but now I am receiving errors - I have updated the question if you could re-vist it that would be amazing as I'm really lost here and have been going in circles for a while – Wally Jul 30 '20 at 16:38
  • I don't see the update to the question – Steven B. Jul 30 '20 at 16:48
  • Sorry Steven - I have just added the edit - any help would be great and sorry for the long read..... ask any questions you might have :) – Wally Jul 30 '20 at 16:53
  • Can you add what `articleData` looks like when it comes back from the api – Steven B. Jul 30 '20 at 17:05

2 Answers2

1

Your navbar can just use a normal router-link and bind the article to the params of the route.

Navbar.vue

<template>
  <div class="navigationContainer">
      <div class="languageContainer" v-for="article in articleData" :key="item.id">
          <router-link :to="{name: 'Articles', params: { id: article.id, article: article }}">
            {{ article.title }}
          </router-link>
      </div>
  </div>
</template>
....

You'll need to update your route to use function mode and parse out the article from the route.params to feed into your component as props.

Routes

{
    name: 'Articles',
    path: '/articles/:id', 
    props: (route) => ({
        id: route.params.id,
        article: route.params.article,
    })
}

And finally your article component will receive the id and article as props.

Articles.vue

<template>
  <div class="articleContainer">
     <p>{{ id }}</p>
     <p>{{ article.title }}</p>
     <p>{{ article.description }}</p>
  </div>
</template>

<script>
export default {
    name: 'Articles',
    props: ['id', 'article'],
    created() {
        if (!this.article) {
            // direct url navigation: you need to fetch the article using `this.id`
        }
    }
}
</script>

Simplified Demo

One thing you'll need to consider. If a user directly navigates to the route through the url, the article prop will be null. So you'll need fetch the article in the component's created hook or a router navigation guard.

Steven B.
  • 8,962
  • 3
  • 24
  • 45
  • Awesome thank you for the feedback! I'll implement this shortly to see if it has success :) thank you for all of your effort on this question its really appreciated – Wally Jul 30 '20 at 17:47
  • Hi Steven - Just implemented this (had to take a break from the screen for a little while) - its all working as I had originally had hoped - Thank you again for your help on this issue, it seems I have some more learning to do with Vue.js and how to handle routes. I had originally used router-links instead of $route.push but had not known about the params function (or how to handle it) - this has been a great bit of learning for me! Thanks again for all your help and saving me from more grey hairs :P – Wally Jul 31 '20 at 06:54
0

I might do this a little differently, as follows:

  1. In App.vue, do not fetch the entire set of articleData. Instead, just retrieve the item titles and item ids that the Navbar needs.

  2. Then, in Navbar, just use a router-link to pass through the item.id:

          <router-link :to="{name: 'Articles', params: { itemid: item.id}}">
            {{ article.title }}
          </router-link>```
  1. Then, in your Articles component, fetch the article details within the mounted() lifecycle method, keying off the itemid.

  2. The final step addresses the title of the post, and is necessary to ensure that the Articles mounted lifecycle method fires even when the $route is seemingly unchanged. You do this by changing <router-view> to <router-view :key="$route.fullPath"> in the App.vue file.

<template>
  <div id="app">
    <div class="topElements">
      <Navbar :articleData="articleData"/>
      
      <router-view :key="$route.fullPath" />
    </div>
      <Footer />
  </div>
</template>

While this approach requires two fetches instead of one, you will only be fetching the data required for the user's specific path.

crosen9999
  • 823
  • 7
  • 13
  • This is actually how I would probably do it too but I would just use a `beforeRouteUpdate` in-component guard to fetch the new data rather than putting a key on the `router-view` and causing a complete re-render. – Steven B. Jul 31 '20 at 05:06