Struggling to concatenate array dynamically in Vue using ajax request

I am working on a Vue instance that fetches objects from a REST endpoint and showcases them on a web page. Most parts of the functionality work smoothly like filtering, however, there is an issue when attempting to add new objects by requesting a new "page" of results from the service. Unlike other operations, adding new results involves appending them to the existing set rather than replacing it entirely. The challenge arises as the service only provides the requested "page" of results. Here's the specific code snippet causing the issue:

// External server-side process handles these variables not within Vue context
let searchTags = ["tag1", "tag2", "etc"];
let productsBaseSearchTag = "a/b/c";

Vue.mixin({
    methods: {
        doSearchStuff: function(response, data) {
            this.searchResponse = response;
            this.resultCount = response.total; // jQuery used for consistent results display due to issues
            jQuery(".search-page-sort-results .num").text(this.resultCount);
            if (this.currentPage > 1) {
                this.searchResults = this.searchResults.concat(data.hits);
            } else {
                this.searchResults = data.hits;
            }
            this.facetCount = data.facets.length;
        }
    }
});

new Vue({
    el: '#v-search-page-results',
    data: {
        searchResponse: {},
        searchResults: [],
        facetHeaders: searchTags,
        returnedFacetHeaders: undefined,
        currentPage: 1,
        hitsPerPage: 12,
        searchTerm: "",
        statusMessage: "",
        sortProperty: "",
        displayedFilters: {},
        predicateList: [],
        facetCount: 0,
        resultCount: 0,
        showLoading: true
    },
    created: function() {
        this.predicateList = searchTags;
        this.getSearchResults(false);
    },
    computed: {
        pdpPaths: function() {
            return this.searchResults.map(function(item) {
                let catalogPath = item.path;
                return decodeURIComponent(pdpPath) + catalogPath.replace(decodeURIComponent(catalogRoot), "").replace(/\//g, ".");
            });
        },
        summaries: function() {
            return this.searchResults.map(function(item) {
                let summary = item.properties.summary;
                if (summary.length >= 120) {
                    summary = summary.substring(0, 120);
                    summary = summary.substring(0, summary.lastIndexOf(" ")) + "...";
                }
                return summary;
            });
        },
        assetAbsoluteURLs: function() {
            return this.searchResults.map(function(item) {
                let escapedUrl = item.path.replace(/\s/g, "%20");
                return location.origin + escapedUrl;
            });
        },
        canClearFilters: function() {
            return this.predicateList !== searchTags;
        },
        moreResults: function() {
            if (this.searchResponse) {
                let resultCount = this.resultCount;
                let totalLoadedResults = this.hitsPerPage * this.currentPage;
                if (totalLoadedResults < resultCount) {
                    return true;
                }
            }
            return false;
        }
    },
    methods: {
        loadMoreResults: function() {
            this.currentPage += 1;
            this.getSearchResults();
        },
        clearSearchTerm: function() {
            this.searchTerm = "";
            this.submitSearchTerm();
        },
        getSearchFilters: function() {
            if (this.predicate...

Many complexities are addressed in the code section above regarding array operations. Furthermore, here's the corresponding HTML markup showcasing the array iteration using v-for:

<div id="v-search-page-results" class="search-page-container _clearfix">
    <div class="search-page-wrapper">
        <div class="search-page-facets-wrapper">
            <div class="search-page-sort-results">
                <span v-cloak class="num">{{ resultCount }}</span> results
            </div>

        </div>

        <div class="search-page-container">

            <!-- facet stuff here -->

            <div class="search-page-results-container">
                <div class="search-page-results-wrapper">

                    <div v-for="(result, index) in searchResults" class="search-page-results-item" v-bind:key="result.id">
                        <div class="search-page-image-container">
                            <img v-cloak :alt="result.title" :src="result.properties.thumbnailPath" class="search-page-image">
                        </div>
                        <div class="search-page-results-content">
                            <a v-cloak :href="pdpPaths[index] + '.html'" class="title" title="">{{ result.properties.productTitle }}</a>
                            <div v-cloak class="description" v-html="summaries[index]"></div>
                        </div>
                    </div>

                </div>

                <div class="search-button-top-nav">
                    <div v-show="moreResults" class="button-wrapper load-more-container load-more-wrapper">
                        <div class="button-wrapper-2">
                            <div class="button-container">
                                <a @click="loadMoreResults" class="btn -primary load-more">Load More</a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Lastly, shown below is an example of the data we aim to iterate through:

"hits": [
    {
      "id": 1,
      "title": "product1",
      "path": "/path/to/product1",
      "properties": {
        "thumbnailPath": "/products/images/product1.jpg",
        "productTitle": "Product 1",
        "summary": "<p>This is product 1.</p>\r\n"
      }
    },
    {
      "id": 2,
      "title": "product2",
      "path": "/path/to/product2",
      "properties": {
        "thumbnailPath": "/products/images/product2.jpg",
        "productTitle": "Product 2",
        "summary": "<p>This is product 2.</p>\r\n"
      }
    }
]

The attempts made include utilizing Vue.set, iterating over response objects while pushing one object at a time into the array, leveraging the spread operator, among others. The array does receive the new elements successfully, but Vue fails to reflect these additional results. Overwriting current objects within the array with new ones displays correctly, implying that the DOM updates but stops showing beyond a certain number of items. Despite trying several approaches, the desired outcome remains elusive.

Answer №1

Avoid combining jQuery with Vue as it may cause loss of reactivity by directly manipulating the DOM or encountering other negative effects.

new Vue({
  el: '#app',
  data: {
    searchResults: [],
  },
  methods: {
    async getNewPost(next) {
      this.searchResults.push(await this.getSearchResult(next))
    },
    getSearchResult(next) {
      return fetch(`https://jsonplaceholder.typicode.com/posts/${next}`)
        .then(response => response.json())
        .then(json => {
          return json
        })
    }
  },
  async mounted() {
    this.searchResults = [await this.getSearchResult(this.searchResults.length + 1)]

  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <button @click="getNewPost(searchResults.length + 1)">Get new post</button>
  <div v-for="(result, index) in searchResults" class="search-page-results-item" v-bind:key="result.id">
    <div class="search-page-results-content">
      <h3>{{index + 1}}. {{result.title}}</h3>
      <div v-cloak class="description">{{result.body}}</div>
    </div>
  </div>
</div>

The above snippet fetches data from a simulated JSON API and retrieves the next item upon button click.

In the getNewPost() method, items are not added directly to the searchResults data property, but instead a temporary variable is created before updating the entire array.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The React Fabric TextField feature switches to a read-only mode once the value property is included

I've been grappling with how to manage value changes in React Fabric TextFields. Each time I set the value property, the component goes into read-only mode. When utilizing the defaultValue property, everything functions correctly, but I require this i ...

Live Search: Find Your Answers with Ajax

I've come across this issue multiple times, but haven't found a solution that fits my specific requirements. I've encountered several URLs with links like example.com/ajax/search?query=Thing I'm currently working on a header and using ...

efficiently populating a 2-dimensional numpy array using python conventions

I'm currently working on populating a 2D numpy array, but I have concerns about scalability with larger array sizes. x=np.array([2,3,4]) y=np.array([1,3,9,13]) mat=np.zeros((x.size,y.size)) for i in range(nx): for j in range(ny): if x[i] > y[j ...

AngularJS is encountering an issue with the callback function, resulting in an error

Currently, I am utilizing the $timeout service in Angular to decrease a variable from 100 to 1 in increments of 1/10 seconds. Although I understand that using the $interval service would be a simpler solution, for this particular scenario, I am focused on ...

When using angular $resource.save for savings, the view is forced to redraw and reflow because of the collection watcher

One of the challenges I'm facing involves loading and storing a model using $resource in AngularJS. This particular model is an aggregate with nested collections, which are displayed in an HTML view using ng-repeat. The structure of the model looks l ...

Prevent memory leakage by utilizing Angular's $interval feature in countdown processes

I have a controller set up to handle a countdown feature: var addzero; addzero = function(number) { if (number < 10) { return '0' + number; } return number; }; angular.module('theapp').controller('TematicCountdownCo ...

Retrieve documents from MongoDB that were created within the last week and return a count of 0 for any days in which no documents were created

I need to extract documents from the last 7 days stored in my Mongo Database. I have successfully retrieved data in the desired format, where specific dates and the number of tickets created on those dates are returned: { "datesUsed": { ...

When opting for "Not now" in Firefox, the error callback in getUserMedia is not activated

I am currently working on a script to detect when the user either allows or denies the use of a microphone using the getUserMedia API. UPDATE: To better illustrate the issue I am facing, I have created a fiddle: http://jsfiddle.net/4rgRY/ navigator.getUs ...

Get your hands on a PDF containing server node and vue.js

I am facing an issue with creating a secure download link for a PDF file on the server. When clicking on the link, the file is not being downloaded properly. Ensuring that the PDF link remains hidden from the client but still allows for downloading direct ...

Calculating the frequency of a variable within a nested object in an Angular application

After assigning data fetched from an API to a variable called todayData, I noticed that there is a nested object named meals within it, which contains a property called name. My goal is to determine the frequency of occurrences in the name property within ...

Trigger a drop-down list in React when typing a specific character, like {{ or @, in an input field

Is there a way in React.js to display a list or dropdown when a user types a certain character like '@' or '{{ }}' in the input text area? The user should be able to select an option from this list and have it inserted into the text are ...

"Commander.js does not process query strings when used in conjunction with node

I developed a CLI tool using commander.js which has been released on npm. This command-line interface utilizes node-fetch to fetch data from an external API. However, I have received reports from some users stating that the query string in the fetch URL is ...

NodeJs Classes TypeError: Unable to access 'name' property as it is undefined

I am currently developing a useful API using Node.js. In order to organize my code effectively, I have created a UserController class where I plan to include all the necessary methods. One thing I am struggling with is how to utilize a variable that I set ...

Navigating the dynamic components in Vue using dynamic routing

I'm currently developing an application that helps users manage maintenance tasks. I have successfully created a component to display all the data stored in an array of objects. However, I am facing a challenge in redirecting users to different pages ...

The presence of an unfamiliar custom element, specifically <v-btn>, was detected following the installation of V

I can't figure out why my code isn't functioning properly. I have created a file at src/plugins/vuetify.ts with the following content: import Vue from "vue"; import Vuetify from "vuetify/lib"; Vue.use(Vuetify); const vuetify ...

Leveraging this jQuery code across multiple div elements

As a newcomer to jQuery, I am currently experimenting with a test script. My goal is to create an effect where when an image is clicked, a div slides down displaying more information similar to the new google images effect. The issue with the current scri ...

The selectors in NgRx store are failing to retrieve data from the main global store

As I delve into the world of ngrx, I find myself struggling to fully understand and implement it effectively within my application. Recently, I integrated ngrx version 8.3 into my project in hopes of organizing my state management efficiently. My goal is ...

Is the for loop programmed to stop at the first match?

I've been working on filtering a txt file using nodejs. Here's my code snippet: const fs = require('fs') let list = fs.readFileSync('./newmR.txt', 'utf-8').split('\r\n') console.log(list.length) ...

Obtain file paths from a folder using JavaScript

Currently, I am in the process of developing an npm package that validates imported images. Can anyone provide some insights on how to instruct javascript to iterate through a specific directory and store the file paths in an array? Furthermore, my aim is ...

Tips for replacing v-on:click in Vue to record data:

Exploring options for incorporating logging to collect usage data for a Vue-based web application. Hoping to find a solution that doesn't involve manually adding a 'log' statement to every 'on click' callback. Interested in learn ...