Unveiling the Power of KnockoutJS: Displaying HTML Content and Populating

I am trying to achieve a unique effect using KnockoutJS. Let's consider a basic model:

var Item = function () {
    var self = this;
    self.title = ko.observable("");
};

In addition, I have a ViewModel:

var ItemList = function () {
var self = this;
self.list = ko.observableArray();
}
Now the interesting part begins. In this ViewModel, I receive several blocks of HTML markup. The quantity is unknown. For each block, I need to display the HTML markup immediately:

var blocks = await getBlocks();
$.each(blocks, function (index, value) {
    //At this point (as planned), the blocks should be displayed 
  //together with a rotating loading animation.
    self.list.push(new Item());
});

Following that (still in the ViewModel), I need to retrieve data to fill these blocks:

$.each(self.list(), async function (index, value) {
    var data = await getData("some-url");
   //At this point, the blocks should be filled with data, 
  //and the spinning loading animation should disappear.
    self.list().push(data.results[0].title);
});
And finally, all together:

 var Item = function () {
    var self = this;
    self.title = ko.observable("");
};

var ItemList = function () {
    var self = this;
    self.list = ko.observableArray();
    var blocks = await getBlocks();
    $.each(blocks, function (index, value) {
        self.list.push(new Item());
    });

    $.each(self.list(), async function (index, value) {
        var data = await getData("some-url");
        self.list().push(data.results[0].title);
    });
};
ko.applyBindings(new ItemList());
The HTML for all this complexity appears very straightforward:

<div data-bind="foreach: list">
    <span data-bind="text: title"></span>
</div>
This particular approach does not yield the expected results. I am unsure how to achieve this desired outcome with KnockoutJS. Is it even achievable?

Answer №1

This snippet of code contains an error that needs fixing:

self.list().push(data.results[0].title);

The correct version should be:

value.title(data.results[0].title);

Answer №2

Let's explore an example scenario where:

  • We have a single call that informs us about the total number of items to be rendered
  • Each item requires a separate call to fetch the necessary data for rendering its UI

In this setup, each individual item takes charge of loading its own data. This approach simplifies the process of assigning received data to the respective list item, regardless of the order in which it arrives.

The sequence of events during the UI rendering process is as follows:

  1. The initial call to retrieve data for populating the list triggers a loading state with a general message displayed
  2. A placeholder list item is created for each item being fetched. These items initiate their data retrieval process but remain in a loading state until completion
  3. As the individual data retrievals finish one by one, the list elements update with their specific content

const { getProductIdsAsync, getProductAsync } = apiMethods();

function Item(id) {
  this.name = ko.observable(null);
  this.loading = ko.pureComputed(() => !this.name());
  
  getProductAsync(id).then(this.name);
};

Item.fromId = id => new Item(id);

function List() {
  this.items = ko.observableArray([]);
  this.loading = ko.pureComputed(() => !this.items().length);
  
  getProductIdsAsync()
    .then(ids => ids.map(Item.fromId))
    .then(this.items);
}

ko.applyBindings({ list: new List() });
  

// Mocking of some async API, not relevant to question:
function apiMethods() {
  const productCatalogDB = {
    1: "Apples",
    2: "Oranges",
    3: "Bananas"
  };

  const delayed = (f, minT, maxT) => 
    (...args) => 
      new Promise(res => {
        setTimeout(
          () => res(f(...args)),
          minT + Math.random() * (maxT - minT)
        )
      });

  return {
    getProductIdsAsync: delayed(
      () => Object.keys(productCatalogDB), 500, 1200),
    getProductAsync: delayed(
      id => productCatalogDB[id], 500, 1500)
  };
}
.loading {
  opacity: .6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<p data-bind="visible: list.loading">
  Loading catalog ids...
</p>

<ul data-bind="foreach: list.items">
  <li data-bind="css: { loading: loading }, text: name() || 'Loading...'">
    
  </li>
</ul>

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

Using Javascript to select a radio button in a form depending on the value entered in a text box

I have a form that interacts with a Google Sheet to insert and retrieve data. For instance, the form contains two radio buttons: <input id="Rdio_1" name="RdioSelect" type="radio" class="FirstCheck" value="1" onchange="RadioValInsert ()"/> < ...

Is there a way to emulate synchronous behavior in JavaScript?

var routeSearch = new MyGlobal.findRoutes({ originPlaceId: search.placeInputIds.originPlaceId, destinationPlaceId: search.placeInputIds.destinationPlaceId, directionsService: search.directionsService, directionsDisplay: sear ...

Is there a way to execute a callback function once the page has finished loading through AJAX in

I'm in need of a way to attach new events and execute certain functions on a webpage that loads dynamically. Unfortunately, the resources I've found so far are outdated or lack necessary details (even the jqm docs). My current setup involves jQue ...

Select a user at random from the reactions in the message

Is there a way to select a user at random from message reactions on Discord? Despite going through all the documentation, I'm still unsure about how to do this. ...

Getting rid of the Horizontal Scroll Bar

Having trouble with a persistent horizontal scrollbar in the "section3__container" container despite attempts to adjust size and overflow settings. Need assistance in removing this unwanted feature. <html lang="en"> <head> <m ...

browsing through a timeline created using HTML and CSS

I am currently working on a web project that involves creating a timeline with rows of information, similar to a Gantt chart. Here are the key features I need: The ability for users to scroll horizontally through time. Vertical scrolling capability to na ...

The JQuery function fails to execute following a successful Ajax request

I recently ran into an issue with my Ajax call. Here's the code snippet in question: $("#start-upload-btn").click(function(){ $.ajax({ type: "post", url: "", data: { newProjectName: $('#project-name') ...

Ways to showcase the object on the console

How can I display the object function in the console? When I try, nothing is displayed. Can you please help me figure out what went wrong? I know I must have made a mistake somewhere, as this is my first question on Stack Overflow. import React, ...

Using `href="#"` may not function as expected when it is generated by a PHP AJAX function

I am facing an issue with loading html content into a div after the page has loaded using an ajax call. The setup involves a php function fetching data from the database and echoing it as html code to be placed inside the specified div. Here is my current ...

Plot the components of an array and calculate the instances that JavaScript executes

I have an array containing information about PDF files stored in a buffer. Let's imagine this array holds ten PDF files structured like this: [{ correlative: "G-22-1-06", content: <Buffer 25 50 44 46 2d 31 2e 34 0a 25 d3 eb e9 e1 0a ...

What causes the closure variable to be reset after iterating over JSON data using $.each method?

Take a look at this scenario: var elements = []; $.getJSON(data_url, function(result) { $.each(result, function(key, value) { elements.push(parser.read(value.data)); // at this point, "elements" contains items }); }); dataLayer.addElements( ...

VueJS: using dynamic class names within the style attribute

Within my VueJS application, I have implemented Materializecss modals within single page components. Each modal requires a unique dynamic ID due to the application's requirements. The code snippet below showcases this: <template> <div :i ...

The operation failed because the property 'dasherize' is inaccessible on an undefined object

While attempting to execute the following command: ng generate component <component-name> An error occurred saying: Error: Cannot read property 'dasherize' of undefined Cannot read property 'dasherize' of undefined The confi ...

Generate and delete dynamic iFrames through variable manipulation

I'm currently developing a landing page specifically for our pilots to conveniently access weather information before taking off. However, due to the limitations posed by our computer security measures, I can only utilize iframes to obtain the necessa ...

How can we convert a group of HTML elements sharing a common attribute into an array containing their respective values?

Consider the following HTML structure: <span class="L5" letters="a"></span> <span class="L5" letters="b"></span> <span class="L5" letters="c"></span> <span class="L5" letters="d"></span> <span class="L5" ...

Unsuccessful Invocation of Servlet by Ajax Function

I have a situation where I am trying to trigger an Ajax javascript function from my jsp file, with the intention of loading a servlet for further processing. The issue I am facing is that even though I am able to pass values from the jsp to the ajax functi ...

Fixing the Material UI upgrade error: "Make sure you have the right loader for this file type."

As a beginner in React, Webpack, Babel, and web development, I have been tasked by my company to upgrade the material-ui version for a dropdown search component. The current version used in the project is "1.0.0-beta.43", and I decided to start by upgradin ...

Obtain a string in JSON format upon clicking in Angular 2

I am working on extracting the title from a json response using a click event. Currently, I can retrieve all the titles when the button is clicked, but I am looking for a way to obtain a specific title based on the button or a href that the user has clicke ...

Implementing automatic selection mode in Kendo MVC grid

Seeking to modify the SelectionMode of a Kendo MVC Grid, I aim to switch from single to multiple using Javascript or JQuery upon checkbox selection, and revert back when the checkbox is unchecked. Is this feasible? Additionally, I am successfully binding a ...

Sending JSON data using AJAX in PHP is a common task that many developers

Upon clicking the delete button, the confirmDelete function is called and it posts the parameters as JSON. The response comes back from the server page and enters the success method, but with a blank string value instead of null. I am unable to identify th ...