Prolonged duration load tasks in durandal

Trying to determine the most effective location for running a lengthy load operation with Durandal.

Based on my research, it seems that the recommended approach for data loading is within the ViewModel's activate method, which is typically what I do:

viewModel.activate = function () {
    var loadPromise = myService.loadData();

    return $.when(loadPromise).then(function (loadedData) {
        viewModel.data(data);
    });
};

I understand that failing to return the promise can lead to binding issues, as discussed in this question and answer.

However, executing a time-consuming load operation in the activate method can cause the app to become unresponsive until the operation finishes. For instance, consider the following scenario:

viewModel.activate = function () {
    // All loads return a promise
    var firstLoad = myService.loadFirstData();
    var secondLoad = myService.loadSecondData();
    var thirdLoad = myService.loadThirdDataWhichTakesAges();

    return $.when(firstLoad, secondLoad, thirdLoad).then(function (one, two, three) {
        viewModel.one(one);
        viewModel.two(two);
        viewModel.three(three);
    });
};

In this case, the URL changes to reflect the new page being loaded but the content remains unchanged (leading to the "freeze" effect).

It would be ideal if the URL updated and displayed the new page while waiting for the data to return. Then, the relevant parts of the page could update as the data binds to the view model.

Is there a recommended approach for achieving this in Durandal?

My current workaround involves initiating the load in the activate method and populating the data in the viewAttached method:

var loadPromise;

viewModel.activate = function () {
    // All loads return a promise
    var firstLoad = myService.loadFirstData();
    var secondLoad = myService.loadSecondData();
    var thirdLoad = myService.loadThirdDataWhichTakesAges();

    loadPromise = $.when(firstLoad, secondLoad, thirdLoad);

    // Proceed without returning the promise.
};

viewModel.viewAttached = function () {
    $.when(loadPromise).then(function (one, two, three) {
        viewModel.one(one);
        viewModel.two(two);
        viewModel.three(three);
    });
};

This solution appears to work, but I recall hearing that relying on viewAttached may not be optimal. Additionally, there could be potential race conditions since activation continues.

Any other suggestions?

Answer №1

It is not necessary to return a promise, but if you choose not to do so, make sure to handle it in your knockout bindings to avoid binding to undefined elements. One way to achieve this is by removing the 'return' statement from the activate function and instead adding a property that indicates whether the model is still loading. Here's an example:

viewModel.isLoading = ko.observable(false);
viewModel.activate = function () {
   isLoading(true);
   var loadPromise = myService.loadData();

   $.when(loadPromise).then(function (loadedData) {
      viewModel.data(data);
      isLoading(false);
   });
};

In your view, you can then display a section that appears while the data is still loading and another section for when the loading is complete. For instance:

<div data-bind:"visible: isLoading()">Loading Data....</div>
<div data-bind:"visible: !isLoading()">Insert your regular view with bindings here. The loading process is complete, so the bindings will now work.</div>

Answer №2

What version of Durandal are you currently utilizing? If you're working with Durandal 2.0.0pre, you were previously able to forego returning a promise in the activate function to allow immediate composition of the view without data.

Consider restructuring viewModel.one as a module that returns a constructor function, ensuring each component is responsible for fetching its own data. This way, the first two calls wouldn't have to wait for loadThirdDataWhichTakesAges, particularly useful when one, two, and three are not heavily dependent on each other.

Answer №3

Just recently, I reached out to the Durandal community on their Google Group with a question about the usage of activate and viewAttached in a specific manner. Luckily, Rob Eisenberg himself responded with some valuable insights:

It seems like your approach should work just fine. However, there might be a slight issue with Knockout destroying data bindings on elements if properties are updated while the element is not currently within the document. This potential problem arises due to asynchronous code execution timing. In version 1.x, this could lead to complications if you failed to return a promise from your activate function. While utilizing viewAttached may offer better results, it's worth noting that depending on the complexity of your composition, the view might be attached to its parent but still not fully integrated into the document structure. The depth of composition plays a significant role here. So, keep in mind that deeply composed modules could potentially encounter similar challenges. Fortunately, in Durandal 2.x, the composition process has been revamped to eliminate this issue altogether. Now, returning a promise is no longer mandatory (although still an option). You'll be pleased to hear that Durandal 2.0 is set for release in approximately two weeks.

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

Skipping beforeRouteLeave in VueJS

In my Vue SPA, there is a component where I am using the beforeRouteLeave guard to prevent accidental page exits. However, within this component, I occasionally make an ajax request that, upon successful completion, needs to redirect the user to another lo ...

Leveraging Next.js for "client-side rendering" in React Encapsulations

My dilemma involves a component housing content crucial for SEO optimization. Here is an excerpt from my code: <AnimatedElement className="flex flex-col justify-start items-center gap-4 w-full" duration={500}> <h2 class ...

Store the response data in a global variable or forward it to another function in Node.js using Express JS

I'm currently working on a function that makes a post request to an API (app.post), sending a token and a URL for redirection to webpay. The challenge I'm facing is saving that token in a global variable so that it can be accessed by another func ...

Controlling ever-changing routes using AngularJS

My AngularJS app (Angular v1) has a secure login system in place. Users who are not authenticated can only access the login page, forgotten password page, and cookie policy. I am utilizing ngRoute as shown below: $routeProvider .when('/login ...

Modifying the nginx configuration file for an Angular application: a step-by-step guide

After deploying my Angular application on an nginx server, I encountered a problem. When I accessed http://**.8.100.248:30749, it displayed the default index.html page from the nginx server instead of my actual application located in the html folder under ...

Having trouble converting the JQuery result from the REST request into the correct format

Currently, I am working on making a REST request for an array of objects using JQuery. During the execution of the code within the "success" section, everything works perfectly fine - the objects in the array are converted to the correct type. However, I ...

WebClient executes JavaScript code

On my aspx page, there are JavaScript functions that handle paging. I am currently using the WebBrowser control to run these JavaScript functions by calling WebBrowser1_DocumentCompleted. WebBrowser1.Document.Window.DomWindow.execscript ("somefunction(); ...

Incorporating ZeroClipboard or ZClip (button for copying to clipboard) using JQuery's Ajax functionality

Seeking to implement a 'copy to clipboard' feature triggered by clicking. However, I am facing a challenge as this functionality needs to be integrated with other content loaded using Ajax. Many plugins that achieve the same use Flash to bypass ...

Activate Input by Clicking on Label in Internet Explorer version 8

I am trying to implement a widget in JQuery colorbox that allows users to load files. My approach involves using an input tag with type='file' and styling it with visibility:hidden. Additionally, I have created two labels that are styled like but ...

Strategies for managing a sizable td Input element in a Table that undergoes re-rendering whenever there is a change in state in React

I'm not entirely certain if this is the best practice for rendering a table element in React, but it's what I've been doing consistently. The for loop below will be executed each time a re-render occurs, or when there is a change in input. W ...

JSON data displaying improper date format

After retrieving date from the database, it is in the following format: {5/13/2002 12:00:00 AM} Once this is passed as JSON and bound to a textbox, it appears like this: /Date(1021228200000)/ Is there a way to display the date in the correct format? E ...

Breaking down the jQuery datepicker into individual fields for Day, Month, and Year

Currently, I am using the Contact Form 7 plugin on my Wordpress website, which I believe uses the jQuery datepicker for its date fields (please correct me if I'm mistaken). My query is about splitting the user input box into three separate elements ( ...

On my production server, json_encode functions flawlessly, however, in the development environment, it

I'm stumped on how to solve this issue. Appreciate any help. My json_encode function works perfectly in the development environment, but it's failing on my production server. ...

Creating a dynamic form that efficiently captures user information and automatically redirects to the appropriate web page

Sorry for the unusual question, but it was the best way I could think of asking. I have come across websites with fill-in-the-blank lines where you can input your desired information and then get redirected to another page. For example: "What are you sea ...

What is the best way to create a sleek typewriter effect transition by hovering between tabs?

When hovering over a tab, the content in the main content area's child div should be displayed from a sibling div that holds the content. Initially, the details div style is set to hide the contents but upon hover, it is displayed. The described func ...

Tips for creating a console.log wrapper specifically designed for Angular2 using Typescript

Is there a way to create a custom global logging function in Angular 2 TypeScript project that can be used instead of console.log for services and components? I envision the function looking like this: mylogger.ts function mylogger(msg){ console.log ...

What is the method for transforming latitude and longitude coordinates into a physical address for a website?

I'm working with an API that provides latitude and longitude coordinates, and I need to retrieve the address information (city, area, etc.) based on these values. For example, there is a website like where if we enter the IP address of a location, i ...

The ng-show animation is not functioning as anticipated

I've put together this Plunker, but I'm having issues with the enter and leave animations... The enter animation seems to be delayed, while the leave animation doesn't seem to work at all. Here is the CSS style: div.ng-enter { ...

Make the table in a bootstrap design appear with a border when you hover over a cell using the table

Looking for a solution to make the border work as expected when hovering over each td in a table like this example: https://jsfiddle.net/nmw82od1/ Here is the CSS code: .table1 td:hover { border: 1px solid black; } .table2 td:hover { border: 1px do ...

Firefox consistently reports ajax status as error

One of my ajax requests is causing some confusion. $.ajax({ url: webURL, type: 'post', data: somedata, cache: false, datatype: "json", contentType: "application/json", success: successFunc, ...