Custom code running before views load completely

Is there a way to force views to load in a specific order or wait until everything is loaded to run custom code?

I have several custom functions that pull data from other views on the page, and if it tries to run one before it is completely loaded they do not work.

For example, I get the type of record on a detail page, and below that, I have other related records in a table, I only want to show the same type, so I get the ID from the detail view and then hide the rows without that ID for the type.

This only works about 50% of the time because sometimes the table view loads before the detail view.

While I appreciate the increased performance, it has only worsened this particular problem.

I’ve tried using scene render, only works on hard refresh, and view render does not work because it is random which view finishes loading first; I have tried using custom code to check for the elements, but nothing has been reliable.

I have edited this to include a video
https://cloud.noaviv.com/vpPn3jtt

You can see the records change in the table when I hit refresh 50% of the time.

My code on view render for the details is getting the ID and the field value for the dance style and setting them as variables, then in the table below, it is hiding the ID and any that do not have the same dance style ID.

Any help would be appreciated
Lori

Hi Lori,

The key as you mentioned is to write a function that waits for the views to load. Do you mind showing the code that you’re using to check for elements on the page? It needs to use a loop to be reliable.

Ian

Hi Ian, thanks for your response.

I have a solution I got working but it has some limitations. I noticed the scene always renders last, so I used that as my check here and it does work for the scenario I outlined above. I have pasterd my code below maybe someone has a better idea of how to do the same thing. It only seems to work on an ‘any’ scene call, if I put a specific scene in, it does not work. I also cannot run any view renders within this, they will not work and while I was able to get the ID and thins from the URL on this page, I have pages where I would need this to get multiple IDs so that would not work.

(I know this will work without the checkscene function code but I was trying to get it to be a function I could call and this is my test code that is working.)

var currentScene="";
$(document).on('knack-scene-render.any', function(event, scene, data) {
    currentScene="#kn-"+scene.key;
    function checkScene() {
        Knack.showSpinner();
	    if(currentScene != "") {
	        console.log('check scene done ' + currentScene);
	        /* Run all my Dependant Code here */
	        Knack.hideSpinner();
        } else {
	         window.setTimeout(checkScene, 100); /* this checks the scene every 100 milliseconds*/
	        console.log('recheck scene');
	    }
    }
    checkScene();
});

Hi Lori,

Here’s one (untested) solution. It runs when a specific view is rendered, and waits for another view to load before doing stuff. The code can be improved by waiting for multiple views instead of one, but in the meantime you can just call it multiple times. Note: It uses async/await syntax, which for those who are unfamiliar is basically a simpler alternative to using callbacks (search google for “callback hell”).

$(document).on('knack-view-render.view_1', async function(event, view) {
    const elementOne = await waitForElement('#view_2')
    const elementTwo = await waitForElement('#view_3')
    // ...then do stuff 
})

// This function waits for a specific element to load. 
async function waitForElement(element, retryLimit=5, interval=1000) {
  var tryCount = 0

  while ( document.querySelector(element) === null && tryCount < retryLimit) {
    tryCount++
    await pause(interval)
  }
  return document.querySelector(element)
}

// This is a Promise-based version of setTimeout
function pause(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

You may need to debug and modify to your needs.

2 Likes