Vuejs и запрос: функция вычисляемого свойства не отображает значение GET JSON

У меня есть экземпляр Vue.

// create a root instance
var app = new Vue({
    el: '#app',
    data:
    {
        album: '',
        artist: '',
        link: '',
        genre: '',
        rating: '',
        genres: ["Memphis Rap", "R&B\Soul", "Pop", "Vaporwave", "Alt-Lat"],
        length: 0
    },
    methods: {
        addAlbum: function (event) {
            this.youtubeAlbumList.push({ album: this.album, artist: this.artist, link: this.link, genre: this.genre, rating: this.rating });
            request.post(
                'http://localhost:3000/album',
                { json: { album: this.album, artist: this.artist, link: this.link, genre: this.genre, rating: this.rating } },
                function (error, response, body) {
                    if (!error && response.statusCode == 201) {
                        console.log(body)
                    }
                }
            );
            this.length = this.youtubeAlbumList.length;
            this.album = '';
            this.link = '';
            this.genre = 'Genre';
            this.rating = '';
        }
    },
    computed: {
        albumList:
        {
            get: function () {
                request.get(
                    'http://localhost:3000/album',
                    function (err, res, body) {
                        var info = JSON.parse(body);
                        //.forEach(function(obj) { console.log(obj.id); });
                        return info;
                    }
                )
            }
        }
    }
});

Я пытаюсь заполнить список альбомов, используя метод запроса get. Сервер успешно возвращает код состояния 200. В инструментах разработчика я вижу, что возвращается JSON.

введите описание изображения здесь

Проблема в том, что список (хотя и короткий) не отображается на странице. Для визуализации списка я использовал следующие компоненты:

Vue.component('album-component', {
    template: ` 
    <div class="content">
            <div class="col-sm-6 col-md-4">
                    <div class="thumbnail">
                    <img src="#" alt="#">
                    <div class="caption">
                        <h3>{{x.album}}</h3>
                        <div class="message-body">
                            <h2>Artist:&nbsp{{x.artist}}</h2>
                            <h3>Link:&nbsp<a v-bind:href="x.link">Link</a></h3>
                            <div>Genre:&nbsp{{x.genre}}</div>
                            <div>Rating:&nbsp{{x.rating}}</div>
                        </div>
                        <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p>
                    </div>
                    </div>
                </div>
            </div>`,
    props: ['album'],
    data: function () {
        return {
            x:this.album
        }
    }
});


// register
Vue.component('youtube-album-list-component', {
    template: `<div class="row">
                    <album-component v-for="album in albumList" :album="album"> </album-component>         
            </div>`
    ,
    props: ['albums'],
    data: function () {
        return {
            albumList: this.albums
        }
    }
})

И index.html

 <div id="app">
      <div>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Album</span>
          <input v-model="album" class="form-control" placeholder="Title">
        </div><br>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Artist</span>
          <input type="text" class="form-control" placeholder="Name" v-model="artist">
        </div><br>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Link</span>
          <input type="text" class="form-control" placeholder="Link" v-model="link">
        </div><br>

        <div v-cloak class="input-group input-group-med">
          <select v-model="genre">
          <option v-for="genre in genres" v-bind:values="genre">{{genre}}</option>
        </select>
        </div>
        <br>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Rating</span>
          <input type="text" class="form-control" placeholder="Rating" v-model="rating">
        </div><br>
      </div>
      <button v-on:click="addAlbum" type="button" class="btn btn-danger btn-lg">Left</button>
      <br>
      <br>
      <div>
        <div class="page-header result-header">
          <h1>Album list</h1>
        </div>
      </div>
      <youtube-album-list-component :albums="albumList"></youtube-album-list-component>
    </div>

Я пытаюсь передать вычисленный список альбомов в свой компонент списка альбомов youtube в качестве опоры. Затем используя этот список для создания компонентов альбома. Я пытаюсь понять, почему, хотя в переменной info есть возвращаемый массив, он не отображается. Любые идеи?


person TYMG    schedule 04.01.2017    source источник
comment
свойства, вычисленные или иным образом, не могут быть асинхронными.   -  person Mat J    schedule 04.01.2017
comment
@MathewJibin, как Vuejs обычно обрабатывает рендеринг асинхронных данных? Придется ли мне использовать что-то вроде vue-async-computed для достижения этой цели?   -  person TYMG    schedule 05.01.2017
comment
Вам нужно будет вызвать действие для запроса ресурса async или вы можете сделать это в любых обработчиках событий жизненного цикла компонентов vue, а затем установить свойство поддержки. Если нет дальнейшей обработки, вы можете привязать к этому свойству, иначе вы можете использовать вычисляемое свойство, которое будет автоматически обновляться на основе свойства поддержки.   -  person Mat J    schedule 05.01.2017
comment
@MathewJibin, можете ли вы пояснить «свойство поддержки» в этом контексте? Что-то за пределами экземпляра Vuejs?   -  person TYMG    schedule 05.01.2017
comment
Комментарий стал слишком длинным, поэтому опубликовал ответ. Посмотрим, поможет ли это вам. Наслаждайтесь туром по Vue.   -  person Mat J    schedule 05.01.2017


Ответы (2)


Вы можете перепроектировать что-то вроде этого. В основном у вас будет свойство для хранения вашего списка в свойстве data компонента, вы обновляете его с помощью ajax, затем трансформируете и выставляете с помощью своего вычисляемого свойства.

Vue.component('album-component',{
template:"#album-template",
props: ['album']
});

Vue.component('youtube-album-list-component', {
template:"#youtube-list-template",
props: ['albums',"isLoading"]
});



var app = new Vue({
    el: '#app',
    data:
    {
        album: '',
        artist: '',
        link: '',
        genre: '',
        rating: '',
        genres: ["Memphis Rap", "R&B\Soul", "Pop", "Vaporwave", "Alt-Lat"],
        length: 0,
        albumStore:[],  //This will be your backing store
        limit:2,  
        isBusy:true
    },
    created:function(){
        var me=this;

      //*********REPLACE WITH YOUR AJAX CALL HERE*********

      //moke a ajax request
      setTimeout(function(){
        me.albumStore.push.apply(me.albumStore,[
        {album:"Album 1",artist:"Artist 1",genre:"Pop",rating:4},
        {album:"Album 2",artist:"Artist 1",genre:"Vaporwave",rating:3},
        {album:"Album 3",artist:"Artist 1",genre:"Memphis Rap",rating:5},
        ]);
        me.isBusy=false;
      },3000);
    },
    methods: {
        addAlbum: function (event) { }
    },
    computed: {
        albumList:
        {
            get: function () {
                    //do some for loop or $.map processing here and return the result.
                  var list=[];
                  for(var i=0; i<this.limit && i < this.albumStore.length;i++)
                  {
                    list.push(this.albumStore[i]);
                  }

                  return list;
               }
         }
    }
});

Полная рабочая скрипка находится здесь. Добавлять функционал не делается, можно надстроить поверх этого или адаптировать по своему вкусу.

person Mat J    schedule 05.01.2017
comment
Я думаю, что резервное хранилище чаще называют начальным значением, что проще и понятнее. - person PanJunjie潘俊杰; 05.01.2017
comment
Спасибо. Теперь я понимаю, что вы имеете в виду под «вспомогательным складом». После того, как я разместил свой вопрос, я начал использовать событие жизненного цикла «ранее созданное» для выполнения моего асинхронного вызова. Это тоже сработало, но не так хорошо, как ваш ответ. Последний вопрос: я думаю, что отображение асинхронных данных не является необычной задачей для фреймворка, это я или эта функциональность является слабым местом Vuejs? - person TYMG; 05.01.2017
comment
Извините за путаницу, мой основной стек - это .net с C #, где он называется резервным полем для свойства :). Это не недостаток, но это обычный рекомендуемый способ, свойство со значением по умолчанию, которое обновляется, когда доступно новое значение. Вычисляемые свойства в vue предназначены для преобразований уже доступных данных, а не для операций aync. Для сложных сценариев проверьте Vuex, но если вы новичок, я бы рекомендовал сначала получить прежде чем рассматривать vuex, вы знакомы с принципом работы с vue. - person Mat J; 05.01.2017

вычисляемое свойство не может быть асинхронным, вы не можете вызывать API из него, так как это асинхронно, вы можете написать этот код в методах, и он должен работать:

 methods: {
        albumList:
        {
            get: function () {
                request.get(
                    'http://localhost:3000/album',
                    function (err, res, body) {
                        var info = JSON.parse(body);
                        //.forEach(function(obj) { console.log(obj.id); });
                        return info;
                    }
                )
            }
        }

Если вы непреклонны или у вас есть убедительный пример использования этого только в вычисляемом свойстве, вы можете использовать что-то вроде vue-async-computed, что позволяет иметь вычисляемые свойства в Vue, которые вычисляются асинхронно.

Но я уверен, что использование метода должно быть совершенно нормальным.

person Saurabh    schedule 04.01.2017
comment
Я пробовал это решение, но после того, как albumList все еще передавался в компонент списка, функция get не вызывалась. Но я рассмотрю модуль vue-async-computed. - person TYMG; 05.01.2017
comment
@TYMG какая-то конкретная причина, вы не хотите использовать методы, поскольку это способ vue? - person Saurabh; 05.01.2017
comment
Я пробовал использовать методы, которые предоставляет Vue, но, думаю, использовал их неправильно. Я собираюсь попробовать решение MatthewJbin, поскольку оно не требует внешних библиотек. - person TYMG; 05.01.2017