【问题标题】:Vue JS fire a method based on another method's output unique IDVue JS 根据另一个方法的输出唯一 ID 触发一个方法
【发布时间】:2018-04-22 01:33:00
【问题描述】:

我正在尝试呈现笔记列表,并且在该列表中我想根据存储在笔记表中的 user_id 包含笔记的用户名。我有类似的东西,但目前它正在记录一个错误,指出 Cannot read property 'user_id' of undefined,我明白了原因。

我的问题是,在 Vue 中如何执行这样的操作?

模板:

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

脚本:

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);
   });
}

更新:

我修改了我的代码,使其看起来像下面的示例,我得到了更好的结果,但还不是 100%。使用此代码,它在第一次呈现视图时工作,如果我在此组件之外导航然后返回,它会失败......如果我刷新页面,同样的事情。

我得到的错误是:[Vue warn]: Error in render: "TypeError: Cannot read property 'user_name' of undefined"

注意 console.log... 它每次都按预期返回对象,但正如我提到的,如果刷新页面或导航过去然后返回此组件,我会得到错误和正确的日志。

模板:

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

脚本:

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);
              });
          }

      });
   },
}

【问题讨论】:

  • this 未绑定在您的 .then 回调中。你能用箭头函数代替function函数吗?
  • @RoyJ 哪个回调?两个都?我尝试将两个回调都更改为箭头函数,但行为仍然相同,当我刷新页面时它会中断并收到错误消息,但 console.log 显示正确的数据。
  • 你最里面的回调没有使用this,所以没关系。第一个回调使用this,它是未绑定的,所以它不会正确设置notes。导航是否会清除this.notes?导航返回调用created 钩子吗?
  • 进行了更改,但仍然没有骰子。导航或刷新确实会触发创建的钩子并按应有的方式记录this.notes。我注意到的另一个有趣的事情是,如果我将模板 {{ note.user.user_name }} 更改为 {{ note.user.user_email }} 它会中断,它会刷新页面并正确显示,但是一旦我离开并返回相同的问题。如果我再把它改回{{ note.user.user_name }},一切都会好起来的。
  • 另外,如果我注释掉 for 循环和模板中对用户的任何引用,即:{{ note.user.user_name }},这一切都像魅力一样。

标签: api methods vue.js


【解决方案1】:

您似乎正在尝试显示每个笔记关联用户的用户名,而用户名来自与笔记不同的数据源/端点。

一种方法:

  1. 获取笔记
  2. 根据每条笔记的用户ID获取用户信息
  3. 将两个数据集加入到您的视图正在迭代的 notes 数组中,从而在数组中的每个 note 对象上公开一个 user 属性。

示例代码:

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

您的视图模板如下所示:

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

demo w/axios


更新根据您与我共享的代码,看起来我的原始演示代码(使用axios)可能会误导您进入错误。 axios 库在 data 字段中返回 HTTP 响应,但您使用的 vue-resource 库在 body 字段中返回 HTTP 响应。尝试复制我的演示代码而不更新以使用正确的字段会导致您看到的 null 错误。

当我评论 axios 在这里没有区别时,我指的是上面示例代码中显示的逻辑,这将适用于任一库,因为字段名称是在 fetchNotes()fetchUsers() 中抽象的.

这是更新后的演示:demo w/vue-resource

具体来说,您应该按照此 sn-p 中的指示更新您的代码:

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`
},

【讨论】:

  • 我尝试实施您的解决方案,但我得到一个:notes.map is not a function error message in the const userIds。知道为什么吗?此外,我使用的是 Vue 资源而不是 Axios ......以防万一这对实际的 http 请求有任何影响。
  • 托尼,我已经更新了我最初的答案,你能快速浏览一下更新,让我知道你的想法。
  • axios 在这里没有什么不同。在您的新实现中,您在完全解析用户信息之前分配notes,因此您的模板绑定将出错,因为每个注释的.user 将是undefined。您应该将中间笔记数据缓存在一个临时变量中(不在notes 中),解析用户数据,然后在用户 ID 上连接两个数据集。只有这样才能将连接数据的最终结果分配给notes
  • 你的意思是这行`this.notes = response.body;?至于外部变量,您的意思是像data() { return { temp: [] } }内的空数组吗?
  • 是的,我的意思是那一行。 “临时变量”是指一个本地变量(在您的代码中以fetchNotes() 声明)。有关示例,请参见答案中的 codepen 演示。 :)
【解决方案2】:

托尼, 感谢您所有的帮助和努力,伙计!最终,在 Vue 论坛中某人的帮助下,这对我有用。此外,我想学习如何在 fetchNotes 方法中添加除了用户之外的其他 http 请求 - 在此示例中还有图像请求。这对我有用。

模板:

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

脚本:

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

【讨论】:

    猜你喜欢
    • 2018-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 2020-04-05
    • 1970-01-01
    相关资源
    最近更新 更多