1

I'm calling data with Nuxt async fetch() like this:

export default {
....
  async fetch() {
    let childrenUrl = process.env.VUE_APP_MGNL_API_PAGES + this.projectPage + "/@nodes";
    await this.$http.$get(childrenUrl).then(childResult => {
      this.projectsPageChildren = childResult;
    })
  },

  fetchOnServer: false,
...
}

projectsPageChildren returns an array with objects, each containing a property "servicesMain" which contains an URL path, see screenshot below. enter image description here

I need to access the data of the servicesMain URL path and I'm assuming that to get it, I need to make another fetch call with the "servicesMain" URL.

So what I'm trying is this: I loop through the projectsPageChildren with v-for and on each child I call a function "getMainService" to which I pass the servicesMain URL.

    <div class="card" v-if="projectsPageChildren" v-for="project in projectsPageChildren">
      <div class="title">{{ getMainService(project.servicesMain) }}</div>
      <div class="title">{{ project.title }}</div>
      <Btn :to="project['@path']">More</Btn>
    </div>

The method "getMainService" is placed within VUE's "methods" hook and makes another asynchronous call with the URL that it receives as an argument.

  methods: {
async getMainService(servicePath) {
    let url = process.env.VUE_APP_MGNL_API_PAGES + servicePath;
    await fetch(url)
      .then(result => {
        result.json().then((data) => {
          console.log(data);
          console.log(data.title);
          return data.title;
        });
      })
      .catch(error => console.log(error));
},

},

The two console log statements in the function show the data that I need the function to return.

enter image description here

However, all I see in the browser is "[object Promise]". enter image description here

To summarise: I'm using Nuxt's fetch() hook to get my data which returns an array. Each object in the array contains an URL which points to more data.

How do set up this second fetch call properly? What am I missing here?

I read the docs on Nuxt data fetching and Javascript Promises and Responses, but none seemed to address my problem exactly.

skQ
  • 11
  • 5
  • I'm not sure how vue works, but I think this async call should use `await`: `{{ getMainService(project.servicesMain) }}` – GrafiCode Mar 30 '22 at 10:43
  • Please do not post code images but rather actual text. – kissu Mar 30 '22 at 10:44
  • 1
    Why are you using both `http` and `fetch`? Pick one. Same goes for `async/await` and `.then`, pick one. Rather than return data.title, feel free to assign it to a variable like `this.projectTitle = data.title` rather, and be sure that this is populated when called in the template (otherwise, you can always `v-if="projectTitle"` on your HTML tag). Envs in Nuxt should rather be used [like this](https://stackoverflow.com/a/67705541/8816585) and you should probably want to keep `fetchOnServer` as `true`. Also, if you want to debug more efficiently, I highly recommend using the Vue devtools. – kissu Mar 30 '22 at 10:54
  • @GrafiCode not sure what you do mean here. – kissu Mar 30 '22 at 10:54
  • @kissu method `getMainService()` is async, so when OP calls it inside the v-for loop, shoud await the returned data, as in something like this `{{ await getMainService(project.servicesMain) }}`, I think that's the reason why the page displays `[object Promise]` – GrafiCode Mar 30 '22 at 11:06
  • @GrafiCode this is not valid Vue template code tho. You cannot do async computations into a sync template, it will just error out. – kissu Mar 30 '22 at 11:11
  • @kissu, that's true. Do you think it can be handled like this? https://stackoverflow.com/a/49746754/5334486 – GrafiCode Mar 30 '22 at 11:15
  • Thanks for the input! @kissu Assigning the result to this.projectTitle works, but displays only one result. However, in the v-for loop each object has a different "servicesMain" path and different value, so I'm not sure how this could work? – skQ Mar 30 '22 at 11:17
  • @GrafiCode this is basically my solution posted above (without the spinner, not really needed IMO). @OP: if it works with 1 element, you can create an array, fill it with all the elements and `v-for` on them once they are done fetching. Check [this answer](https://stackoverflow.com/a/40140562/8816585), you can ignore the Typescript part of course. – kissu Mar 30 '22 at 11:23

1 Answers1

0

I ended up soliving it like this:

In my original code I as calling the method "getMainService()" in the Vue template section, which didn't work. Now I'm making a second request in the async fetch() method and call the method from there. In the forEach loop I'm basically rewriting the Objects' property to what the method returns.

This is the new code:

  async fetch() {
let thisPageUrl = process.env.VUE_APP_MGNL_API_PAGES + this.projectPage;
await this.$http.$get(thisPageUrl).then(thisPageResult => {
  this.projectsPageData = thisPageResult;
})

let childrenUrl = process.env.VUE_APP_MGNL_API_PAGES + this.projectPage + "/@nodes";
await this.$http.$get(childrenUrl).then(projectPages => {
  this.projectsPageChildren = projectPages;
  this.projectsPageChildren.forEach(projectPage => {
    this.getMainService(projectPage.extras[0].serviceMain).then(res => {
      projectPage.extras[0].serviceMain = res;
    });
  })

})

},

fetchOnServer: false,

The method getMainService() makes a call to a path and returns a string value:

  methods: {
 getMainService(servicePath) {
  let url = process.env.VUE_APP_MGNL_API_PAGES + servicePath;
  return this.$http.$get(url).then(serviceMain => {
    return serviceMain.title;
  })
},

},

The template bit looks like this:

      <div>
    <div class="card" v-if="projectsPageChildren" v-for="(project, index) in projectsPageChildren">
      <div class="column_title">{{ project.serviceMain }}</div>
      <div class="title">{{ project.title }}</div>
      <Btn :to="project['@path']">More</Btn>
    </div>
  </div>

Maybe not the prettiest solution, but it works. Thanks to @kissu and @GrafiCode, your comments nudged me in the right direction.

skQ
  • 11
  • 5