Error with Form Routing after any change to data in the list

I’ve been writing some code to do some custom form set routing. When opening an item in a list, the routing code looks up another list using the PnPjs library, and routes to a form set based on some values there.

if (item) {
  
  // Get current meeting ID from the lookup field (Lookup fields provide the value and the id of the linked item)
  let { CommitteeMeetingId, CommitteeId } = await item.get();
  
  // Get committee this item is assigned to
  const committee = await pnp.sp.web.lists.getByTitle('BA-Committees').items.getById(CommitteeId)();
  
  // ... some logic on whether to show the formset or not. 

The problem i’m having is that any change to any item in any of my related lists (not the list itself, just adding or editing an item), will cause the very next load of the form to throw several errors in the console, then a 404 on my list, and the default form set loads in fullscreen mode (while all of these forms are set to dialog mode) . Error below.

Now, the odd thing is… all I have to do is close the form and re-open it and everything is back to normal. All the logic and form sets will work just fine until somebody edits a list item again.

I don't understand the 404 one minute and then it works fine the next. Some kind of weird caching thing? I'm pulling my hair out with this and it works fantastic as long as nobody puts in any data! :squinting_face_with_tongue:

Hello @Dana_Pellerin ,

I am unsure if this approach helps you, try to use this:

  const committee = await pnp.sp.web.lists.getById('GUID-OF-The-List').items.getById(CommitteeId)();

  • I have experienced so many errors regarding to “getByTitle” even though it is working approach and documented in the documentation from PnP community.

Give it a try.

And do not pull your hair out of your head, whenever you go further with your knowledge in this area (IT or Javascript), you would be bald very soon :smiley: :smiley: :smiley:

Stepan

Thanks for the reply. I ended up ditching the Form Set idea altogether and just modifying the forms directly. More JS, but it works a lot more reliably. :slightly_smiling_face:

Can you share the output? :slight_smile:

Thank you

Stepan

So I'm doing several lookups and checking user permissions before hiding or showing certain parts of the form. My original idea was to do this in the Form Routing code and route the user to a restricted form based on these conditions. But the problem seems to be with the way the form routing works.. perhaps it's how SharePoint loads or maybe it's caching... I don't know. So finally I rewrote the code directly in the form itself, to wait for certain fields to load, then do some other lookups from other Lists to get some users and dates, and then hide or show the fields on the form based on those dates and the user. It's working very reliably now.

It ended up looking like this (sorry if it's messy with all my debug stuff, I need to clean it up now that it's working).


window.fd = fd;
window.sp = sp;
window.pnp = pnp;

console.log("##### Plumsail script loaded");



fd.spRendered(function () {
    fd.control("StatusText").hidden = true;
    fd.control("CautionIcon").hidden = true;
    
    console.log("##### Plumsail ssendered loaded");
    let CommitteeId = null;
    let CommitteeMeetingId = null;

    // Helper to check if both IDs are ready and then run logic
    async function tryRunLogic() {
        if (CommitteeId && CommitteeMeetingId) {
            console.log("##### CommitteeId: ${CommitteeId}, CommitteeMeetingId: ${CommitteeMeetingId}");
            await runFormLogic(CommitteeId, CommitteeMeetingId);
        }
    }

    // Listen for Committee field changes
    fd.field('Committee').$on('ready', function () {
        
        const val = fd.field('Committee').value;
        CommitteeId = val && val.Id ? val.Id : null;
        console.log("##### Committee Changed - " + CommitteeId);
        tryRunLogic();
    });

    // Listen for CommitteeMeeting field changes
    fd.field('CommitteeMeeting').$on('ready', function () {
        const val = fd.field('CommitteeMeeting').value;
        CommitteeMeetingId = val && val.Id ? val.Id : null;
        console.log("##### CommitteeMeeting Changed - " + CommitteeMeetingId);
        tryRunLogic();
    });

    // If values are already loaded (Edit form), set them immediately
    if (fd.field('Committee').value && fd.field('Committee').value.Id) {
        CommitteeId = fd.field('Committee').value.Id;
    }
    if (fd.field('CommitteeMeeting').value && fd.field('CommitteeMeeting').value.Id) {
        CommitteeMeetingId = fd.field('CommitteeMeeting').value.Id;
    }
    tryRunLogic();

    // Main logic function
    async function runFormLogic(CommitteeId, CommitteeMeetingId) {
        try {
            let userMessage;
            let isEA = false;
            const today = new Date();                               // Fetch current date
            const committee = await pnp.sp.web.lists                // Fetch committee item
                .getByTitle('Committees')
                .items.getById(CommitteeId)
                .get();
            const committeeMeeting = await pnp.sp.web.lists         // Fetch committee meeting
                .getByTitle('Committee Meetings')
                .items.filter('ID eq ' + CommitteeMeetingId)
                .get();
            const blackoutWindows = await pnp.sp.web.lists          // Fetch blackout windows
                .getByTitle('Blackout Windows')
                .items.filter('MeetingId eq ' + CommitteeMeetingId)
                .get();
            const user = await sp.web.currentUser();                // Fetch current user
            const eaUser = await pnp.sp.web.siteUsers               // Fetch EA
                .getById(committee.SupportingEAId)
                .get();

            // Check if current user is EA
            if (committee.SupportingEAId === user.Id) {
                isEA = true;
            }
            
            // Check meeting window
            if (today < new Date(committeeMeeting[0].OpenDate) || today > new Date(committeeMeeting[0].CloseDate)) {
                if(isEA){
                    setMessage('The date is currently outside of the meeting submission window and edits are blocked. Overriding for EA access.');
                } else {
                    disableFields();
                    setMessage('The date is currently outside of the meeting submission window and edits are blocked.<br>Contact ' + eaUser.Title + ' for assistance.');
                }
                return;
            }
            
            // Check blackout windows
            for (const blackoutWindow of blackoutWindows) {
                if (today > new Date(blackoutWindow.StartDate) && today < new Date(blackoutWindow.EndDate)) {
                    if(isEA){
                        setMessage('This item is currently locked due to a scheduled ' + blackoutWindow.Title + ' blackout period. Overriding for EA access.');
                    } else {
                        disableFields();
                        setMessage('This item is currently locked due to a scheduled ' + blackoutWindow.Title + ' blackout period.<br>Contact ' + eaUser.Title + ' for assistance.');
                    }
                    return;
                }
            }
        } catch (err) {
            throw Error("Error in Plumsail form logic:", err);
        }
    }
    
    function disableFields(){
        const fields = ["Title", "Committee", "CommitteeMeeting", "Attachments"];
        for (const field of fields){
            fd.field(field).disabled = true;
        }
        fd.toolbar.buttons[0].visible = false; // Usually the first button is Save
    }
    
    function setMessage(m){
        fd.control("StatusText").html = m;
        fd.control("StatusText").hidden = false;
        fd.control("CautionIcon").hidden = false;
    }
});











1 Like

Hello @Dana_Pellerin ,

very nice :slight_smile:

Yeap, sometimes it’s a challenge to do correct routing and then stakeholders come and change the assignment. Recently it happened to me, so I had to rewrite the code too from Forms Routing to only “JS-based” logic.

Thank you for sharing

Stepan