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

Examining the contents of an array in JavaScript

I am currently conducting API testing. My objective is to verify the presence of a specific name within the API response. The data from the API response is structured in an array format. Despite my intention to check for the existence of the name "activ ...

Angular is throwing a RangeError due to exceeding the maximum call stack size

Encountering a stackOverflow error in my Angular app. (see updates at the end) The main issue lies within my component structure, which consists of two components: the equipment component with equipment information and the socket component displaying conn ...

Alerting Users Before Navigating Away from an Angular Page

I am looking to implement a feature in my app that will display a warning message when attempting to close the tab, exit the page, or reload it. However, I am facing an issue where the warning message is displayed but the page still exits before I can resp ...

Choose a numeric value and then adjust it to display with exactly two decimal places

My goal is to create a code that achieves the following tasks: Add an ID to every nth child Round the number in each nth child to 2 decimal places Prefix the numbers with a pound sign (£) Loop through until all the nth children in a table are processed ...

Hold on until the page is reloaded: React

My current setup includes a React Component that contains a button. When this button is clicked, a sidePane is opened. What I want to achieve is refreshing the page first, waiting until it's completely refreshed, and then opening the sidepane. Below i ...

When attempting to pass data to another page by clicking on a row, the result is that the data appears to be empty

I have been using the MUI-Datatable component, which is able to navigate to the next page. However, when I try to view the data on the History page, nothing appears. How can I resolve this issue? Data transfer to another page: Even though I can see the d ...

Issue: nodebuffer is incompatible with this platform

Currently, I am attempting to utilize the Shpjs package in order to import a Shape file onto a Leaflet map. According to the Shpjs documentation: shpjs Below is the code snippet I am working with: const [geoData, setGeoData] = useState(null); //stat ...

Identical manipulator distinct infusion

I am looking to create multiple controllers that share the same logic, with only differences in injections. One way to achieve this is by creating controllers using a common function like so: var controllerFunc = function($scope, service) { $scope.se ...

Click Action on CanJS Table

I am currently developing a canJS application and have been able to successfully handle the click event for an HTML table using the code below. 'table td click':function(el,event){ console.log('clicked ',el.text()); } ...

I am experiencing an issue where the button I place inside a material-ui table is unresponsive to clicks

Here is the structure of my table: <TableContainer component={Paper} style={{height: "40vh", width: "90vh"}}> <Table size="small" sx={{ minWidth: 200 }}> <TableHea ...

Encountered an error while running npm run dev on a NextJS application due to an

Upon running the npm run dev command, the next app is displaying an error message: $→mmoLD;%g?wŷ↓▬ovH0a5*ؒl͛Siy☺rO7%L]%∟hk ^ SyntaxError: Invalid or unexpected token at wrapSafe (internal/modules/cjs/loader.js:988:16) at Module._comp ...

Routes inoperative as intended

When using a standard expressroute for this login, I have noticed that even if the req.body.password is incorrect, I am still getting redirected to '/login'. router.post('/student/login', (req, res) => { if (req.body.password === ...

Exciting Update: Next.js V13 revalidate not triggering post router.push

Currently using Next.js version 13 for app routing, I've encountered an issue with the revalidate feature not triggering after a router.push call. Within my project, users have the ability to create blog posts on the /blog/create page. Once a post is ...

What specific blur algorithm is utilized by the Flash platform within their blur filter implementation?

I'm in the process of translating AS3 code to JavaScript, and I've come across an AS3 application that utilizes Flash's built-in Blur Filter Could someone provide insight into the blurring algorithm used by this filter or suggest ways to re ...

Tips for managing the onloadedmetadata event

If a video file cannot be played by the browser due to format or codec issues, I want to notify the user about it. When the browser is unable to play a video (because of unsupported format or codec), the onloadedmetadata event does not occur. I have some ...

Incorporating Blank Class into HTML Tag with Modernizr

Currently, I am experimenting with Modernizr for the first time and facing some challenges in adding a class to the HTML tag as per the documentation. To check compatibility for the CSS Object Fit property, I used Modernizr's build feature to create ...

Issues with functionality of React/NextJS audio player buttons arise following implementation of a state

I am currently customizing an Audio Player component in a NextJs application using the ReactAudioPlayer package. However, the standard Import Next/Audio and using just <Audio> without props did not yield the expected results. The player functions as ...

Is it possible to use an onclick function to input JavaScript values into a password entry box seamlessly?

Is there a way to input password values continuously using a JavaScript onclick function into a password field? I have two images, one 'Blue' and one 'Red', that trigger an onclick function with the following values: Blue= w3! Red= T4 ...

After using promise.all, I successfully obtained an array of links. Now, how do I calculate the total number of links in the array?

function verifyAndTallyURLs(linksArray) { let validations = linksArray.map((link) =>{ return fetch(link) .then((response) => { return { webpageURL: response.url, status: response.status, ...

Encountering an issue while executing grunt-contrib-imagemin

Encountering a permissions issue while attempting to execute the grunt-contrib-imagemin script. The installation of grunt-contrib-imagemin was done as follows: npm install --save-dev grunt-contrib-imagemin Node and npm are both installed in my local user ...