0

I'm trying to combine all the pieces I need into one external client side rendering file so I only need to maintain one file for my list.

When we create a new item in the list there are some csr things I want to do on the NewForm when I render it, and I mostly have the CSR working for that. Upon save, there I have a custom PreSaveAction that creates some other list items and modifies the user input on the page.

When editing an existing item, there are some different things I want to do with the colums and I have the csr doing that correctly. I also want to have a custom PreSaveAction, but this time it needs to just updated the other list items it created on the new form.

Basically I control for New vs Edit in the csr like this

customContext.Templates.Fields = {
    'SpecialColum': { "NewForm": NewFormRender,
                      "EditForm": EditRenderFunction}
}

And that knows which form we're on because that is how it was designed to function.

I see that ctx.BaseViewID is a value of either NewForm or EditForm. But by the time I get to my custom PreSaveAction the ctx is long gone.

How do I pass the context BaseViewID to my PreSaveAction?

2

Presuming that you did not modify the default webpart on the NewForm and EditForm webpages, then you should be able to access a global JS object named WPQ2FormCtx. This object is loaded before the CSR is executed. The CSR is actually using the contents of this object for things like populating the input fields with values on the EditForm webpage, etc.

So, what you need to do inside the PreSaveAction function is the following:

function PreSaveAction() {
    if (WPQ2FormCtx.FormControlMode === 3) {

        // execute code for NewForm page here

    } else if (WPQ2FormCtx.FormControlMode === 2) {

        // execute code for EditForm page here

    }
}

Personally, I suggest you keep your JS files separate because they will be shorter so they will load and execute faster. Also, nobody can guarantee you 100% that the WPQ2FormCtx object will not become WPQ3FormCtx, although it should not if nobody is messing with the web parts.


The way I approached something similar in the past was to create a variable on my global object (I always use only one global variable which is an object and to which I attach functions and other objects) and then set this variable inside the function used for the CSR of the first field in the form.

For example, I would do this:

// My global object.
var myGlobalObject = {...};

// CSR functions here.
myGlobalObject.NewFormRender = function NewFormRender(ctx) {
    myGlobalObject.baseViewID = ctx.BaseViewID;

    // more code here...
};

// more code here...

function PreSaveAction() {
    if (myGlobalObject.baseViewID === 'NewForm') {

        // execute code for NewForm page here...

    } else if (myGlobalObject.baseViewID === 'EditForm') {

        // execute code for EditForm page here...

    }
}

Note that the NewFormRender function above is the one you used for your SpecialColum field. You only need to do this in one of your custom rendering functions.

  • I like your second approach, but that means I would need to add that setting at the beginning of each of my custom render functions, right? – Rothrock Apr 27 '17 at 20:06
  • Nope, not each of your custom render functions. Just one of them because the ctx.BaseViewID variable will give you the same value, so it is redundant to do the same thing in all your render functions. Test it and you will see what I mean. :) – Mihail Popa Apr 27 '17 at 20:17
  • note that var myGlobalObject is not going into the global scope if this is declared inside a (CSR) function ... window.myGlobalObject = window.myGlobalObject || {} is the proper assignment.. also note that MDS can play tricks on you, since it does some garbage collection, and will destroy your objects if you are not properly declaring CSR initialisations (use the boiler plate code the Cisar Chrome Extension gives you) – Danny '365CSI' Engelman Apr 27 '17 at 20:27
  • @Danny'365CSI'Engelman Fair points. I hope the readers are aware of the assumptions that I have made there: 1) the above code goes into a JS file as it is, namely the myGlobalObject variable is not declared inside any function; 2) people using MDS can look up articles on how to overcome it when applying their own CSR customisations. – Mihail Popa Apr 27 '17 at 20:41
0

You could try changing the Scope for the PreSaveAction with

function PreSaveAction(){
   var baseviewId=this;

}.bind(ctx.BaseViewId);

But easier might be to just whack it in the global scope
people who say the global scope is evil, don't understand JavaScript

window.MYBaseViewID = ctx.BaseViewID;
  • Where would I put that line of code to add it to the global scope? – Rothrock Apr 27 '17 at 20:03
  • Anywhere when ctx is available. Note that is the same concept as Mihail global object, he just wraps it in an extra container, handy when you have more to store, not required for a single variable.. global scope is global scope. – Danny '365CSI' Engelman Apr 27 '17 at 20:21
  • Yeah that is the problem. ctx isn't available everywhere. And there doesn't seem to be a place in the execution of the csr that always happens AND has ctx defined. Other than to make sure to add it to any and every custom render functions. – Rothrock Apr 27 '17 at 21:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.