Custom Code JavaScript Doesn't Always Run Successfully

Hello,

I have the following custom code inside the header of my Softr app, but it doesn’t always run successfully when logged in.

<!-- Append Logged In User Record ID to Kite Flyer Profile URL in User Profile Menu -->
<script>
	window.onload = function () {
		if (window['logged_in_user']) {
			const ProfileURLWithRecordID = window['logged_in_user']['Profile URL'];
			const ProfileURLsWithoutRecordID = document.querySelectorAll('a[href^="https://www.kitebag.app/kite-flyer-profile?recordid="]');
			ProfileURLsWithoutRecordID.forEach(function (link) {
				link.href = ProfileURLWithRecordID;
			});
		}
	}
</script>

The code waits until everything on the page is loaded, then finds instances of a specific URL, and appends a RecordID to it. This is done to take users to their user profile instead of a random profile.

I’ve debugged the code in Google Chrome Developer Tools and with ChatGPT, it looks like I’m doing every right - I even switched from waiting for DOMContent to load to window.onload to delay the script from running too early (this worked better, but not prefectly).

I suspect that this is still an issue of timing, and the script is running and attempting to edit HTML elements not yet present on the page.

Any help would be greatly appreciated. :slightly_smiling_face:

Here’s an updated script that waits for:

  • DOMContentLoaded
  • Header block
  • Logged In User
  • Will repeat the code if it doesn’t find the HREF in the header to update
  • Will repeat the code if the code is modified dynamically

I taken about every precaution you can take here to ensure that this JavaScript runs, but more often than not it still doesn’t update the HREF in the header.

Softr says it supports custom code, including JavaScript, but that’s not my experience here. I can’t launch my app without this, and it’s the only thing I’m waiting on to launch.

@artur can you help me out here?

// Function to check if an element with an ID starting with "header-for-" exists
function waitForHeaderForElement() {
    const headerForElement = document.querySelector('[id^="header-for-"]');
    if (headerForElement) {
        // Element found, execute your code here
        if (window['logged_in_user']) {
            const ProfileURLWithRecordID = window['logged_in_user']['Profile URL'];
            const ProfileURLsWithoutRecordID = document.querySelectorAll('a[href^="https://www.kitebag.app/kite-flyer-profile?recordid="]');
            ProfileURLsWithoutRecordID.forEach(function (link) {
                link.href = ProfileURLWithRecordID;
            });
        }
    } else {
        // Element not found, wait and check again
        setTimeout(waitForHeaderForElement, 100); // Adjust the delay as needed
    }
}

// Listen for the DOMContentLoaded event
document.addEventListener('DOMContentLoaded', function () {
    // Start waiting for the element
    waitForHeaderForElement();
});

// Use a mutation observer to check for dynamically added elements
const observer = new MutationObserver(waitForHeaderForElement);
observer.observe(document.body, { childList: true, subtree: true });

Might be worth trying with Softr’s own block-loaded or get-records events as shown here - Event Listener for Dynamic Lists (React Version) - #2 by jstrauss, I’ve generally had more luck with those instead of DOMContentLoaded and onload.

Not sure if and how it works for logged in users, but hopefully a direction to explore :slight_smile:

Hi,

Not sure you’re taken the good logic to do what you want.

Can you try this one, instead, at app level, in the custom code footer (no need for dom content loaded or onload or anything else for now).
Just change ‘ID’ and the urls by what you need. Note that I don’t use a Profile URL field but recordId() in a formula field called ‘ID’

<script>
    if (window['logged_in_user'] && window['logged_in_user']['ID']) {
        const userID = window['logged_in_user']['ID'];
        const currentURL = window.location.href;

        if (currentURL === 'https://test-play.softr.app/url-profile') {
            const newURL = `https://test-play.softr.app/url-profile?recordId=${userID}`;
            history.replaceState(null, '', newURL);
        }
    }
</script>
1 Like

I did some more debugging and discovered that, as suspected, it’s a timing issue. When the script would fire, the header block wasn’t always fully loaded and thus there was no matching link to update.

I tested a version of the script that focused on the block ID, this didn’t work (because it’s a header block?). I then tested DOMContentLoaded. This worked in Google Chrome, but not Safari.

I ultimately ended up going with LOAD as this is one of the last things to load and ensures that all content is on the page before running.

Here’s my working final code:

<!-- Append Logged In User Record ID to Kite Flyer Profile URL in User Profile Menu -->
<script>
	window.addEventListener('load', function () {
		if (window['logged_in_user']) {
			const ProfileURLWithRecordID = window['logged_in_user']['Profile URL'];
			const ProfileURLsWithoutRecordID = document.querySelectorAll('a[href="https://www.kitebag.app/kite-flyer-profile?recordid="]');
			ProfileURLsWithoutRecordID.forEach(function (link) {
				link.href = ProfileURLWithRecordID;
			});
		}
	});
</script>