@gistol

Как во Vue.js добавить данные в существующий массив?

Приветствую.
Прошу помощи знающим Vue.js

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

Основная проблема, что не могу объединить 2 массива.
Пробовал this.articles.concat(response.data.payload) и через Push.

Но каждый раз выдает ошибку TypeError: this.articles.push is not a function. (In 'this.articles.push({ message: 'Baz' })', 'this.articles.push' is undefined) или TypeError: this.articles.concat is not a function. (In 'this.articles.concat(test)', 'this.articles.concat' is undefined)

Использую код:
<template>
    <div class="main__inner useful_inner">
               <section class="section section_1 tittle__section">
            <div class="grid">
                <div class="section__wrapper">
                    <div class="tittle-box">
                        <h1>{{documentContent.title}}</h1>
                       </div>
                    <div class="tag-box">
                        <button @click="addTag('all')" class="tag-box_item active" data-tag="all">
                            <span class="tag-name">всё</span>
                            <span class="tag-count">{{countedTags.all}}</span>
                        </button>
                        <button @click="addTag('radio')" class="tag-box_item" data-tag="radio">
                            <img src="/static/img/tag_radio.svg" class="tag-img" alt="">
                            <span class="tag-name">радиоэфир</span>
                            <span class="tag-count">{{countedTags.radio}}</span>
                        </button>
                        <button @click="addTag('article')" class="tag-box_item" data-tag="article">
                            <img src="/static/img/tag_article.svg" class="tag-img" alt="">
                            <span class="tag-name">статья</span>
                            <span class="tag-count">{{countedTags.article}}</span>
                        </button>
                      </div>
                </div>
            </div>
        </section>
        <!--<router-view-->
           <section class="section section_2">
            <div class="grid">
                <div class="section__wrapper">
                    <div class="articles-box">
                        <div v-for="article in articles"
                             v-bind:item="article"
                             v-bind:key="article.oo_id">
                            <a :href="'//useful/articles//' + article.oo_id" class="articles-box__item" :data-tag="article.tags.category">
                                <svg class="articles-box__item_svg" width="63" height="249" viewBox="0 0 63 249"
                                     fill="none"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <rect x="0.76001" y="-3.28906" width="34.7626" height="291" fill="#ADCFF7"/>
                                    <path d="M43.2469 -7.25961V-88.5448H35.0311V314.94H43.2469V173.697V123.377C43.2469 111.987 43.7479 102.088 51.7647 90.4762C61.7856 75.961 62.2866 65.3165 62.2866 57.575C62.2866 49.8336 60.2824 37.2537 51.7647 26.6092C44.9504 18.0936 43.2469 3.50254 43.2469 -7.25961Z"
                                          fill="#ADCFF7"/>
                                </svg>
                                <div class="articles-box__item_inner">
                                    <div class="articles-box__item_tag">
                                        <img :src="article.tags.iconWhite" :alt="article.name" class="item__tag_img">
                                        <span class="item__tag_text">{{ article.tags.name }}</span>
                                    </div>
                                    <div class="item__inner_info">
                                        <div class="info__top-box">
                                            <span class="info__title">id={{ article.oo_id }};name={{ article.name }} </span>
                                            <span class="info__descript">{{ article.description }}</span>
                                        </div>
                                        <div class="info__bottom-box">
                                            <div class="info__bottom-box_date">{{ article.date }}</div>
                                            <div class="info__bottom-box_watched">
                                                <img src="/static/img/wacthed_eye.svg" alt=""><span>{{ article.views }}</span>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="item__inner_img">
                                        <img :src="article.previewImage" :alt="article.name">
                                    </div>
                                </div>
                            </a>

                            <button @click.prevent="loadMore">Load more</button>
                            <a href="#" class="orange__link show_more">
                                <span>Показать ещё</span>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>
</template>

<script>
    import axios from 'axios'
    import FosJsRouting from './FosJsRouting';

    export default {
        name: 'app',

        data() {
            let categoryValue = document.getElementById('category').value;
            console.log('categoryValue =' + categoryValue);
            let documentId = document.getElementById('documentId').value;
            console.log('documentId =' + documentId);
            return {
                userIsAuthorized: false,
                category: categoryValue,
                documentId: documentId,
                tags: ['all'],
                articles: [],
                documentContent: [],
                countedTags: [],
                page: 1,
      
            }
        },
        created() {
            this.getDocument();
            this.getCountedTags();
            this.getArticles();
        },
        methods: {
            loadMore: function() {
                this.page = this.page + 1;
                var vm = this;
                axios.get(FosJsRouting.generate('getArticleList', {category: this.category, tags: this.tags, page: this.page})).then(response => {
                     // only 10 will be visible at any time
                    if (response.data.status === 0) {
// Merges both arrays
                       vm.articles = vm.articles.concat(response.data.payload);
                       
                    }
                    else {
                        console.log(response.data.message);
                    }
                });
            },
            addTag: function (value) {
                let allIndexTag = this.tags.indexOf('all');
                if (value === 'all') {
                    this.tags = ['all'];
                } else if (this.tags.includes(value)) {
                    if (allIndexTag !== -1) {
                        this.tags.splice(allIndexTag, 1);
                    }
                    this.tags = this.tags.filter(function (e) {
                        return e !== value
                    });
                    if (this.tags.length === 0) {
                        this.tags = ['all'];
                    }
                } else {
                    if (allIndexTag !== -1) {
                        this.tags.splice(allIndexTag, 1);
                    }
                    this.tags.push(value);
                }

                console.log(this.tags);
                this.getArticles();
                console.log(this.tags);
            },
            getArticles: function () {
                axios.get(FosJsRouting.generate('getArticleList', {category: this.category, tags: this.tags}))
                    .then((response) => {
                        if (response.data.status === 0) {
                            console.log(response.data.payload);
                            this.articles = response.data.payload;
                        }
                        else {
                            console.log(response.data.message);
                        }
                    });
            },
            getDocument: function () {
                axios.get(FosJsRouting.generate('getDocumentContent', {id: this.documentId}))
                    .then((response) => {
                        if (response.data.status === 0) {
                            console.log(response.data.payload);
                            this.documentContent = response.data.payload;
                        }
                        else {
                            console.log(response.data.message);
                        }
                    });
             },
            getCountedTags: function () {
                axios.get(FosJsRouting.generate('getCountedTags', {category: this.category}))
                    .then((response) => {
                        if (response.data.status === 0) {
                            console.log(response.data.payload);
                            this.countedTags = response.data.payload;
                        }
                        else {
                            console.log(response.data.message);
                        }
                    });
                // this.$router.push({name: 'articleList'});
            }
        }
    }
</script>
  • Вопрос задан
  • 1024 просмотра
Решения вопроса 2
0xD34F
@0xD34F Куратор тега Vue.js
А откуда вы взяли, что у вас там массив? Вы сообщение об ошибке вообще читали? Если "this.articles.push is not a function", значит this.articles - это не массив, у массивов метод push есть. Изначально да - массив, но когда вы в created вызываете getArticles, производится перезапись свойства. Неплохо было бы разобраться, что на самом деле возвращает запрос на получение статей - уж не объект ли?

UPD. Вынесено из комментариев:

Да, не массив, а объект. Я просто и так и так пробовал. Смог добавить таким способом.
this.articles = Object.assign(this.articles, response.data.payload);

Но значение добавилось не так как нужно.

Присваивание бессмысленное - Object.assign модифицирует первый аргумент, а не создаёт новый объект.

Кроме того, vue не отслеживает установку значений по индексу.

Сам способ добавления данных в массив сомнительный - что если имена свойств пришедшего объекта не образуют корректного набора индексов? Типа, начинаются не с нуля, есть пропуски... А если какие-то из имён свойств вообще не могут быть использованы в качестве индекса массива? - само свойство создано будет, но v-for (как и методы - forEach, map, ...) не будет его обрабатывать. Доставайте из объекта массив значений и уже его элементы добавляйте в articles:

this.articles.push(...Object.values(response.data.payload));

Это если именно "добавить в существующий". Но, поскольку изначально он пустой, в getArticles можно просто заменить один массив другим:

this.articles = Object.values(response.data.payload);

А вообще - какого чёрта? Ждёте массив, а приходит объект... Или исправьте бекенд, чтобы приходил массив, или не ждите массива - замените дефолтное значение articles на пустой объект, а в getArticles по получении данных просто выполняйте присваивание: this.articles = response.data.payload. А там, где пытаетесь concat выполнить, создавайте новый объект, в который будут копироваться свойства существующего и результат запроса:

this.articles = { ...this.articles, ...response.data.payload };
// или
this.articles = Object.assign({}, this.articles, response.data.payload);
Ответ написан
@gistol Автор вопроса
Даа, 2 дня сидел. Плохо не знать JS.
В общем всё просто и на поверхности:

this.articles = {...this.articles, ...response.data.payload};
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы