Vue JS fire a method based on another method's output unique ID

半世苍凉 提交于 2019-12-23 04:46:06

问题


I'm trying to render a list of notes and in that list I would like to include the note's user name based on the user_id stored in the note's table. I have something like this, but at the moment it is logging an error stating Cannot read property 'user_id' of undefined, which I get why.

My question is, in Vue how can something like this be executed?

Template:

<div v-for="note in notes">
   <h2>{{note.title}}</h2>
   <em>{{user.name}}</em>
</div>

Scripts:

methods:{
   fetchNotes(id){
      return this.$http.get('http://api/notes/' + id )
      .then(function(response){
         this.notes = response.body;
      });
   },
   fetchUser(id){
      return this.$http.get('http://api/user/' + id )
      .then(function(response){
         this.user = response.body;
      });
   }
},
created: function(){
   this.fetchNotes(this.$route.params.id)
   .then( () => {
      this.fetchUser(this.note.user_id);
   });
}

UPDATE:

I modified my code to look like the below example, and I'm getting better results, but not 100% yet. With this code, it works the first time it renders the view, if I navigate outside this component and then back in, it then fails...same thing if I refresh the page.

The error I am getting is: [Vue warn]: Error in render: "TypeError: Cannot read property 'user_name' of undefined"

Notice the console.log... it the returns the object as expected every time, but as I mentioned if refresh the page or navigate past and then back to this component, I get the error plus the correct log.

Template:

<div v-for="note in notes">
   <h2>{{note.title}}</h2>
   <em>{{note.user.user_name}}</em>
</div>

Scripts:

methods:{
   fetchNotes(id){
      return this.$http.get('http://api/notes/' + id )
      .then(function(response){
         this.notes = response.body;

          for( let i = 0; i < response.body.length; i++ ) {
             let uId = response.body[i].user_id,
                 uNote = this.notes[i];
              this.$http.get('http://api/users/' + uId)
              .then(function(response){
                 uNote.user = response.body;
                 console.log(uNote);
              });
          }

      });
   },
}

回答1:


It looks like you're trying to show the username of each note's associated user, while the username comes from a different data source/endpoint than that of the notes.

One way to do that:

  1. Fetch the notes
  2. Fetch the user info based on each note's user ID
  3. Join the two datasets into the notes array that your view is iterating, exposing a user property on each note object in the array.

Example code:

let _notes;
this.fetchNotes()
    .then(notes => this.fetchUsers(notes))
    .then(notes => _notes = notes)
    .then(users => this.joinUserNotes(users, _notes))
    .then(result => this.notes = result);

Your view template would look like this:

<div v-for="note in notes">
  <h2>{{note.title}}</h2>
  <em>{{note.user.name}}</em>
</div>

demo w/axios


UPDATE Based on the code you shared with me, it looks like my original demo code (which uses axios) might've misled you into a bug. The axios library returns the HTTP response in a data field, but the vue-resource library you use returns the HTTP response in a body field. Attempting to copy my demo code without updating to use the correct field would cause the null errors you were seeing.

When I commented that axios made no difference here, I was referring to the logic shown in the example code above, which would apply to either library, given the field names are abstracted in the fetchNotes() and fetchUsers().

Here's the updated demo: demo w/vue-resource.

Specifically, you should update your code as indicated in this snippet:

fetchInvoices(id) {
  return this.$http.get('http://localhost/php-api/public/api/invoices/' + id)
    // .then(invoices => invoices.data);  // DON'T DO THIS!
    .then(invoices => invoices.body);     // DO THIS: `.data` should be `.body`
},
fetchCustomers(invoices) {
  // ...
  return Promise.all(
      uCustIds.map(id => this.$http.get('http://localhost/php-api/public/api/customers/' + id))
  )
  // .then(customers => customers.map(customer => customer.data));  // DON'T DO THIS!
  .then(customers => customers.map(customer => customer.body));     // DO THIS: `.data` should be `.body`
},



回答2:


Tony, Thank you for all your help and effort dude! Ultimately, with the help from someone in the Vue forum, this worked for me. In addition I wanted to learn how to add additional http requests besides the just the user in the fetchNotes method - in this example also the image request. And this works for me.

Template:

<div v-if="notes.length > 0">
   <div v-if="loaded === true">
    <div v-for="note in notes">
        <h2>{{note.title}}</h2>
        <em>{{note.user.user_name}}</em>
        <img :src="note.image.url" />
      </div>
    </div>
   <div v-else>Something....</div>
</div>
<div v-else>Something....</div>

Script:

name: 'invoices',
data () {
   return {
      invoices: [],
      loaded: false,
   }
},
methods: {
fetchNotes: async function (id){
    try{
        let notes = (await this.$http.get('http://api/notes/' + id )).body
        for (let i = 0; notes.length; i++) {
            notes[i].user = (await this.$http.get('http://api/user/' + notes[i].user_id)).body
            notes[i].image = (await this.$http.get('http://api/image/' + notes[i].image_id)).body
        }
        this.notes = this.notes.concat(notes)
    }catch (error) {

    }finally{
       this.loaded = true;
    }
} 


来源:https://stackoverflow.com/questions/47195367/vue-js-fire-a-method-based-on-another-methods-output-unique-id

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!