Executing a Knockout.js destructive loop in a foreach fashion

Here is the HTML code with the data-bind elements:

div data-bind="foreach: clientRequests" id="test2">
           <div class="list-group" >
               <a href="#" class="list-group-item active"><b data-bind="text: client"></b></a>
               <a href="#" class="list-group-item"><b>Priority: </b><b data-bind="text: client_priority"></b></a> 
               <a href="#" class="list-group-item"><b>Title: </b><b data-bind="text: title"></b></a>
               <a href="#" class="list-group-item"><b>Description: </b><b data-bind="text: description"></b></a> 
               <a href="#" class="list-group-item"><b>Product Area: </b><b data-bind="text: product_area"></b></a>
               <a href="#" class="list-group-item"><b>Target Date: </b><b data-bind="text: target_date"></b></a>
               <a href="#" class="list-group-item"><b>Ticket URL: </b><b data-bind="text: ticket_url"></b></a>
           </div>
        </div>

This is how I am passing an array called requestsArray to the data-bind loop:

ko.cleanNode(document.getElementById('test2'));

        ko.applyBindings({
            clientRequests: requestsArray
        }, document.getElementById('test2'));

Through different AJAX calls, various requestArrays are returned. After the initial page load, an AJAX call fetches one instance of the requestArray which might contain 10 items. The foreach loop works as expected, and all 10 items are displayed on the page. However, in a second AJAX call, the array may only have 5 items. This causes each item to be repeated twice, resulting in a total of 10 items being displayed on the page.

The issue arises from the fact that even though

ko.cleanNode(document.getElementById('test2'))
is invoked before:

ko.applyBindings({
                clientRequests: requestsArray
            }, document.getElementById('test2'))

with each new array, the number of HTML elements created by each iteration of foreach continues to increase. In Vue.js, passing a new array for data-binding and looping is destructive and does not retain any elements from the previous iteration over the array.

Using ko.cleanNode does not resolve this scenario, and while there is an example in the documentation that demonstrates what seems to be the correct procedure, it only removes one HTML element at a time using a button and self.array.remove(this). Adapting this to completely clear out all HTML elements created from a foreach iteration is not straightforward.

Answer №1

There is no need to manually re-apply bindings when you have a view model with an observable array. Knockout handles the data updates automatically for you. Typically, using cleanNode may not be necessary if there are simpler alternatives available.

Consider trying something like this:

// Apply bindings _once_, viewmodel instance does not change
// in between requests
ko.applyBindings(new ViewModel());


function ViewModel() {
  // Because the array is observable, knockout will
  // monitor for changes and update the UI
  this.requests = ko.observableArray([]);
  
  // The view model has the request method
  // the .done callback writes the results to the observable
  // requests array
  this.doRequest = function() {
    mockupAjaxGetter().done(this.requests);
  }.bind(this);
  
  // Do an initial request
  this.doRequest();
};



// Mockup code, just to produce some random numbers on a timeout
function mockupAjaxGetter() {
  var randomResults = [];
  for (var i = 0; i < Math.random() * 20; i += 1) {
     randomResults.push(Math.random()); 
  }
  var cb;
  var applyCb = function() {
    if (cb) cb(randomResults); 
  }
  
  setTimeout(applyCb, 500);
  
  return {
    done: function(fn) { cb = fn; }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<ul data-bind="foreach: requests">
  <li data-bind="text: $data"></li>
</ul>
<button data-bind="click: doRequest">New request</button>

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

Troubleshooting issue: Angular Typescript object array filter functionality malfunctioning

I am currently attempting to filter an array of objects based on a specific value. Interestingly, out of the console.log outputs provided below, only the first one is yielding the expected result: console.log('log1: ', sf); console.log('log ...

Filling an array in the programming language C

I've been encountering a recurring issue with arrays within my program, and I'm struggling to pinpoint the root cause. It seems like something is awry in my understanding of array theory. There appears to be some mysterious force adding unfamili ...

Click the submit button to display a div element without having to refresh the page

Is it possible to display a spinner for a couple of seconds before the page reloads upon submitting a form? <form class="ready" action="https://link.com" method="post"> <input name="test" type="submit" class="click" value="order"/> </form&g ...

What is the extent of a variable within a jQuery function?

Similar Question: Understanding Asynchronous Behavior in Ajax Question: Why does my variable "temp" remain as 0 after the AJAX request? function calculate7() { var temp = 0; $.ajax({ type: "POST", ...

You cannot call this expression. The type 'String' does not have any call signatures. Error ts(2349)

Here is the User class I am working with: class User { private _email: string; public get email(): string { return this._email; } public set email(value: string) { this._email = value; } ...

save choice in antd select in react js

In the process of developing a ReactJS project, I am utilizing the antd select component to display a list of companies. Upon selecting a company name, the users registered under that company will be shown. The attached video showcases the functionality fo ...

What is the best way to send a response with multiple parts in ExpressJS?

My application showcases a collection of images along with their respective titles and descriptions. As the app communicates with the node server via a get request, I am seeking guidance on how to have the server respond with both the images and their as ...

Guide on preventing selection with beforeSelectionChange when using the select All checkbox in ng-grid

When the select All checkbox in the header is clicked, the beforeSelectionChange function is called with a rowItem array. Unfortunately, there doesn't seem to be an option to disallow selection. I need to disable the checkbox for certain rows based on ...

Manipulating geometry properties in three.js with dat.GUI for dynamic changes

I created a spherical shape using the following function let createBall = () => { let geoBall = new THREE.SphereGeometry(5, 32, 16); let mat = new THREE.MeshPhongMaterial({ color: "red", transparent: true }); ball = new THREE.Mesh(geoBa ...

Efficient search operations in a 2D matrix in C++

Currently, my code utilizes a 2D array and the process of searching for a specific entry is proving to be time-consuming. I am seeking recommendations on optimizations that can be implemented to reduce the search time within this 2D array. Any suggestion ...

Utilizing JavaScript as the front-end client for a web application connected to the backend of

I am facing an interesting scenario with a coworker who has suggested using JavaScript in a Web client application (specifically EPiServer CMS) to manage all the documents in the backend (SharePoint Online). However, I am unable to figure out how to acce ...

Is there a way to insert values into dynamic arrays of arrays and remove them in C++?

Kindly note that I am limited to using arrays and cannot utilize classes or vectors. Here is what I have managed to do so far: int** arrays = new int*[10]; arrays[0] = new int[99]; arrays[1] = new int[47]; I am unsure, but I believe it may be possible ...

Is it possible to integrate the screenfull JavaScript library into the Next.js framework?

Attempting to utilize Dynamic Importing in Nextjs for incorporating the screenfull library has proven unsuccessful. import dynamic from "next/dynamic" import screenfull from 'screenfull'; const Screenfull = dynamic(()=>{return import ...

Can you tell me the appropriate type for handling file input events?

Using Vue, I have a simple file input with a change listener that triggers the function below <script setup lang="ts"> function handleSelectedFiles(event: Event) { const fileInputElement = event.target as HTMLInputElement; if (!fileInp ...

How can I efficiently create a suffix using this JavaScript code?

Take note that the code displayed below showcases the array in the console, rather than in the snippet output var names = ["maria", "mary", "marks", "michael"]; function add_suffix(names) { var suffixes = []; for (var i = 0; i < names.length; i+ ...

Validating groups of fields using Angular fieldsets

AngularJS validation is working well with ng-required. However, I am interested in checking if all the form elements within my fieldset are valid. <form> <fieldset> <legend> Part one <img src="/co ...

Ways to maintain hover functionality when the submenu is visible

My website features a simple table that displays devices and their characteristics. A condensed version of the table can be found in the link below. import "./styles.css"; import { SubMenu } from "./SubMenu"; const subMenuSlice = <S ...

I am currently facing an issue with retrieving the class value that is being generated by PHP code

I am currently facing an issue with jQuery and PHP. Whenever I attempt to target the click event on the class ".id_annonce" in the dynamically generated PHP code, it doesn't retrieve the exact value of what I clicked. Instead, it always gives me a fi ...

Django inline formset posing challenges with deletion of forms

I am using an inline formset named WorkExperienceFormset to generate forms by clicking a button. However, I am facing an issue where I am unable to delete the forms when I click the button. forms.py: WorkExperienceFormset = inlineformset_factory(Employee, ...

Filtering an array dynamically by utilizing an array of conditions

Can jQuery-QueryBuilder be used to filter an array? This amazing plugin generates a unique array of conditions: condition:"AND" rules: { field:"name" id:"name" input:"select" operator:"equal" type:"string" value:"Albert" } I have ...