0

I've been looking for a way to get a json file once in a component and use it on the same component and other components like how you do with global variables.

I've looked at this (it will set the variable after i've used it in the template, so it will show a unassigned variable error in the console) but it dosen't work and i've also looked at vue3 docs but didn't find anything that works.

so i didn't find anyway but to send a request in every component.

showHome.vue:

<script>
import axios from 'axios';
export default {
  created(){
    axios.get("http://api.mjbn.ir/post")
  .then((response) => {
    this.getposts = response.data;
    });
  },
  data: function () {
    return {
      postsearch: "",
      post: true,
      product: true,
      getposts: this.getposts,
    };
  },
  methods: {
    showReq(input0, input1) {
      this.post = input0;
      this.product = input1;
    },
    btnActive(input0) {
      if ((input0 == "post") & (this.post == true) & (this.product == false)) {
        return true;
      } else if ((input0 == "product") & (this.product == true) & (this.post == false)) {
        return true;
      } else if ((input0 == "all") & (this.post == true) & (this.product == true)){
        return true;
      } else {
        return false;
      }
    },
    showRes(input0) {
      if ((input0 == "post") & (this.post == true)) {
        return true;
      } else if ((input0 == "product") & (this.product == true)) {
        return true;
      } else if ((input0 == "all") & (this.post == true) & (this.product == true)){
        return true;
      } else {
        return false;
      }
    },
    postCount(){
      const posts = this.getposts
      let count = 0;
      if (this.post == true & this.product == true){
        return this.getposts.length;
      } else if (this.post == true & this.product == false){
        for (let index = 0; index < posts.length; index++) {
          const element = posts[index];
          if (element.type == 'post') {
            count++;            
          }
        }
        return count;
      } else if (this.post == false & this.product == true){
        for (let index = 0; index < posts.length; index++) {
          const element = posts[index];
          if (element.type == 'product') {
            count++;            
          }        
        }
        return count;
      }
      return "...";
    },
  },
};
</script>
<template>
        <div class="col-12 mt-5">
          <div class="row">
            <div v-for="getpost in getposts" v-show="showRes(getpost.type)" :key="getpost.id" class="col-4">
              <router-link :to="{ name: 'post', params: { id: getpost.id } }">
                <div class="col-6 mx-auto align-self-center">
                  <img
                    :src="getpost.img"
                    :alt="getpost.title"
                    class="img-fluid img-thumbnail"
                  />
                  <h5 class="text-center my-3">{{ getpost.title }}</h5>
                </div>
              </router-link>
            </div>
          </div>
        </div>
</template>

showPosts.vue:

<template>
  <!-- Post -->
  <div v-for="getpost in getposts" v-show="getpost.type == link" :key="getpost.id" class="col-8 my-3 mx-auto blog-post">
    <router-link
      :to="{ name: link, params: { id: getpost.id } }"
      style="color: #f8f8f2"
    >
      <div class="col-2 float-start">
        <img
          :src="getpost.img"
          :alt="getpost.title"
          class="img-fluid img-thumbnail"
        />
      </div>

      <div class="col-10 float-end">
        <div class="col-10 ms-4 me-4">
          <h2>{{ getpost.title }}</h2>

          <figure class="figure figure-caption">{{ getpost.date }}</figure>
        </div>

        <div class="col-10 ms-4 me-4">
          <p>{{ getpost.summerry }}</p>
        </div>
      </div>
    </router-link>
  </div>
</template>
<script>
import axios from 'axios';
export default {
  created() {
    axios.get('http://api.mjbn.ir/post')
    .then(response => { this.getposts =  response.data})
  },
  data: function () {
    return {
      getposts: this.getposts,
      link: "post",
    };
  },
};
</script>

main.js:

import "./assets/css/bootstrap.rtl.min.css";
import "./assets/css/main.css";
import { createApp } from "vue";
import { createWebHashHistory, createRouter } from "vue-router";
import showAbout from "./components/showAbout.vue";
import showBlog from "./components/showBlog.vue";
import showHome from "./components/showHome.vue";
import showLoading from "./components/showLoading.vue";
import showPage from "./components/showPage.vue";
import showHeader from "./components/showHeader.vue";
import showPost from "./components/showPost.vue";
import showPosts from "./components/showPosts.vue";
import showContact from "./components/showContact.vue";

// Routes
const routes = [
  {
    path: "/",
    component: showHeader,
    children: [
      { path: "", component: showHome,},
      { path: "/contact", component: showContact },
      { path: "/about", component: showAbout },
    ],
  },
  {
    path: "/blog",
    component: showBlog,
    children: [
      { path: "", component: showPosts },
      { path: "/blog/:id", name: "post", component: showPost },
    ],
  },
  { path: "/loading", component: showLoading },
];

// Router
const router = createRouter({
  history: createWebHashHistory(),
  routes: routes,
});

// App
const app = createApp(showPage);
app.use(router);
app.mount("#app");
MJBN
  • 16
  • 1
  • 7
  • Load it in your main app component, then pass it down to any child that needs it. https://v3.vuejs.org/guide/component-props.html#passing-an-array –  Jan 10 '22 at 18:02
  • Or put it in your Vuex store. – connexo Jan 10 '22 at 18:05
  • This is what global state is for, commonly Vuex. – Estus Flask Jan 10 '22 at 18:09
  • @ChrisG then i should get the file in the root component and pass it to every child component, if i have a large json file in the future that will increase the load time – MJBN Jan 10 '22 at 18:22
  • @EstusFlask i didn't know about vuex but i will try it, i think it'll work – MJBN Jan 10 '22 at 18:26
  • Passing it down will not increase the load time, also you're still only loading it once. But yeah, vuex is probably the best solution. –  Jan 10 '22 at 18:45
  • @ChrisG passing it down will not increase the load time, but downloading a large file in the root component before the other components loaded will increase the load time – MJBN Jan 10 '22 at 19:14

1 Answers1

0

thanks to connexo and estus flask in the comments. i've come to know that there is something called vuex that will do the work for you. here is the syntax.

main.js:

import { createApp } from "vue";
import { createStore } from "vuex";
import showPage from "./components/showPage.vue";

// Store
const store = createStore({
  state() {
    return {
      getjson: null,
    };
  },
  mutations: {
    getfile(state) {
      axios
        .get("https://jsonplaceholder.typicode.com/todos/1")
        .then((response) => {
          if (state.getjson == null) {
            state.getjson = response.data;
          }
        });
    },
  },
});

// App
const app = createApp(showPage);
app.use(store);
app.mount("#app");

In the component:

<template>
<!-- run setposts before using getjson -->
  {{this.setposts()}}
  {{this.$store.state.getjson}}
</template>
<script>
export default {
  methods:{
    setposts(){
      this.$store.commit("getfile");
    }
  }
};
</script>
MJBN
  • 16
  • 1
  • 7