refreshing elements when fresh arguments are provided to them (VUE JS)

UPDATED -

Starting fresh is the way to go.

I've got a VUE js CLI app that fetches data from the DB in the APP.vue page and then distributes it across other pages and the navigation bar.

The nav bar triggers a function in the router:

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

But now two issues have arisen:

  1. The component doesn't refresh with new data when a new nav item is clicked

  2. An error message shows up:

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

https://i.sstatic.net/jSs0O.png

The CODE:

app.vue <<<< Here, the fetch call is made and then the fetched data is passed to the NAV bar component (visible 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,


      //   setting up a variable for the local host as it will change later when moving 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 which calls the callback that uses $route.push to navigate to the Article component along with 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 << Finally, the articles page shows all the articles by receiving them as a prop (initial props load but don't reload when a new nav item is clicked, resulting in the aforementioned error)

Articles.vue

<template>
  <div class="articleContainer">
     <p>{{ articles }}</p>  <<< Just to confirm if the props are received correctly - will be updated later
  </div>
</template>

<script>
export default {
    name: 'Articles',
    props: ['articles'],
    data(){
      return{
        articleData: null,
      }
    },
    watch: {
      articles(){
        this.articleData = this.articles; <<<< Attempting to update the component upon detecting a new $route - Also tried using $route
        console.log(articleData) <<< Checking if it worked.... 
      }
    }
}
</script>

This was quite extensive, so I really appreciate any help offered here.

Sincerely, Wally

p.s.

Feel free to ask any questions you may have

UPDATED:

Article data sourced from: http://localhost:1337/languages

It's an array of objects fetched 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": []
}
]

Answer №1

Instead of using a complex navbar setup, you can simply utilize a regular router-link and bind the article to the route parameters.

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>
....

To make this work, update your route configuration to use function mode so that you can extract the article from the route.params and pass it as props to your component.

Routes

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

In your article component, you will then 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) {
            // If user navigates directly to the url, fetch the article using `this.id`
        }
    }
}
</script>

See a Simplified Demo Here

Keep in mind that if a user accesses the route through the URL directly, the article prop will be null. In such cases, you'll need to fetch the article in the component's created hook or a router navigation guard.

Answer №2

If I were to approach this task in a different way, it would look something like this:

  1. Firstly, in the App.vue file, avoid fetching the entire articleData set. Instead, retrieve only the item titles and ids needed by the Navbar component.

  2. Next, utilize a router-link in the Navbar component to pass the item.id:

<router-link :to="{name: 'Articles', params: { itemid: item.id}}">
  {{ article.title }}
</router-link>
  1. Subsequently, within your Articles component, fetch the specific article details using the mounted() lifecycle method, based on the itemid provided.

  2. The crucial final step involves addressing the post title and ensuring that the Articles mounted lifecycle method is triggered even when the $route appears unchanged. This can be achieved by replacing <router-view> with

    <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>

Although this method involves two fetches instead of one, it efficiently retrieves only the necessary data for each user's unique path.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Transferring Date or DateTime from one HTML Input to another HTML Input using Javascript

There are 2 a elements present. Each one triggers a Bootstrap modal window. One of these a elements is used to create a completely new record, and thus it includes the current date/time: <a style="color:#5cb85c" data-CreateDate="@DateTime.Now" data-tog ...

Utilizing AJAX and PHP to create a dynamic like button function

Is there a way to make the like number increase without refreshing the page when the like button is clicked? Here's my current code: <script type="text/javascript> jQuery(document).ready(function ($) { $('body').on( 'cli ...

Tips for transferring data from the Item of a repeater to a JavaScript file through a Button click event for use in Ajax operations

I am working with a repeater that displays data from my repository: <div class="container" id="TourDetail"> <asp:Repeater ID="RptTourDetail" runat="server" DataSourceID="ODSTTitle" ItemType="Tour" EnableViewState="false" OnItemDataBound="Rp ...

Aligning a lowercase "i" element within a container

Is there a more effective way to center the "i" element within this div without using specific pixel margins that adjust based on hover? Below is my code snippet: HTML: <div class="nav-collapse"> <i class="fa fa-bars fa-2x" id="bars"></ ...

Transmitting a JSON array from a client-side using AJAX to a server

I am currently working on sending a JSON array to PHP. I have successfully sent the data but am facing some challenges when it comes to parsing it. Below is the code snippet that I am referring to: JavaScript: var employees = [ { "firstName":"John" , ...

Functionality of the Parameters Object

As I transition from using the params hash in Rails to learning Node/Express, I find myself confused about how it all works. The Express.js documentation provides some insight: 'This property is an array containing properties mapped to the named rout ...

Mixing controllers with the same name in AngularJS from different modules can lead to

Recently, while working on an AngularJS web application with multiple sub-modules, I encountered a situation where two sub-modules had controllers with the same name due to them both having CRUD functionality. Here's a snippet of the code structure: ...

how to make a post request to an API using Next.js

I am attempting to make a request to the Exist API using next.js and the backend is in PHP. I am trying to send a post request (using Axios) with data and retrieve the response. How can I manage this API in my code? I have read that I need to include som ...

What causes Firefox's CPU to spike to 100% when a slideshow begins that adjusts the width and left coordinates of certain divs?

Seeking Advice I'm in need of some help with identifying whether the code I'm working on is causing high CPU usage in Firefox or if it's a bug inherent to the browser itself. The situation is getting frustrating, and I've run out of so ...

Tips for generating PHP tooltips for ImageMapster

Currently, I am in the process of creating a floor map for my organization. This map will help individuals locate specific employees and their respective desks easily before visiting them. To achieve this, I have generated a <map> with numerous < ...

Building a web application using the Nuxt.js framework and Express generator

Seeking help to seamlessly integrate an express app generated with express generator into my nuxt.js application. Came across this https://github.com/nuxt-community/express-template, although it seems to only cover basic express applications. Any recomme ...

After the update to Angular 9, the stopImmediatePropagation function on mat-expansion-panel is no longer functioning as

Issue Description After upgrading to Angular 9, the expected behavior of preventing an expansion panel from opening when editing a field inside was not working. The use of event.stopImmediatePropagation() and event.stopPropagation() did not prevent the exp ...

Updating the AngularJS view following a deletion process

I have a web application developed using AngularJS and Rails that carries out RESTful operations like create, read, and delete. After deleting an item, I need to refresh the page and update the view asynchronously. However, I am facing challenges in imple ...

resizing a big image to perfectly fit the width of the screen with the help of

Is there a way to use AngularJS to automatically adjust the size of a large image to fit the screen on various devices (responsive), similar to how it is done on this website? Are there any Angular directives available for this purpose, or would I need to ...

Retrieve error message from 400 error in AngularJS and WebAPI

Why am I having trouble reading the error message in AngularJS from this code snippet? ModelState.AddModelError("field", "error"); return BadRequest(ModelState); Alternatively, return BadRequest("error message"); return Content(System.Net.HttpStatusCod ...

Issues encountered while converting scss to css with gulp

I've been attempting to convert SCSS to CSS, and here's the code I've been working with. const gulp = require('gulp'); const sass = require('gulp-sass'); gulp.task('sass', function() { return gulp.src(&apos ...

Ensure history.back() does not trigger Confirm Form Resubmission

Within my web application, every form submission is directed to an action folder. Once the process is complete, the user is redirected back to their original location. However, a problem arises when the user performs an action that requires the application ...

Using Parseint in a Vue.js method

For instance, let's say this.last is 5 and this.current is 60. I want the sum of this.last + this.current to be 65, not 605. I attempted using parseInt(this.last + this.current) but it did not work as expected. <button class="plus" @click="plus"&g ...

How can we identify if the user is utilizing a text-input control?

Incorporating keyboard shortcuts into my HTML + GWT application is a goal of mine, but I am hesitant about triggering actions when users are typing in a text area or utilizing the keyboard for select menu operations. I am curious if there exists a method ...

Is the length of a complex match in Angular JS ng-if and ng-repeat greater than a specified value?

In my code, there is an ng-repeat that generates a table based on one loop, and within each row, another cell is populated based on a different loop: <tbody> <tr ng-repeat="r in roles | limitTo: 30"> <td>{{r.name}}</td> ...