There are many questions on sharepoint.stackexchange.com related to redirecting the user to a specific page after form submission. Most answers include A) code that adds a custom PreSaveAction-function which in turn does a window.location = “…” or executes WebForm_DoPostBackWithOptions function with a custom target destination or B) they rely on providing a customized link to the form itself with a modified Source parameter in the query string.
Option A fails at the default form validation and option B is complicated to maintain.
Let’s have a look what happens when a form is submitted. The Save button has this in it’s onclick-attribute:
if (!PreSaveItem()) return false; if (SPClientForms.ClientFormManager.SubmitClientForm('WPQ1')) return false; WebForm_DoPostBackWithOptions( new WebForm_PostBackOptions( "*long save button ID*", "", true, "", "", false, true ) )
First, PreSaveAction is executed. This function allows you to write custom validation rules or execute any kind of code before a form is submitted. After that SPClientForms.ClientFormManager.SubmitClientForm is executed, this function validates the form and submits it if the validation is successful. WebForm_DoPostBackWithOptions, a function that allows you to specify your own redirect destination, is actually never reached.
What we know so far is that SPClientForms.ClientFormManager.SubmitClientForm validates the form but you can’t specify your own redirect destination. With WebForm_DoPostBackWithOptions you can specify your own redirect destination but the default form validation is not executed.
Now you could start writing your own validations and put it into PreSaveAction which can be quite cumbersome if you have a complex form. Or, you somehow trick SPClientForms.ClientFormManager.SubmitClientForm into redirecting to a different URL. Let’s have a look into SPClientForms.ClientFormManager.SubmitClientForm to check out how the redirect-destination is determined:
(The corresponding code resides in clientforms.js, the code below is the debug-version and unimportant parts are omitted)
var _ctx = window[qualifier + "FormCtx"]; var redirectInfo = _ctx.RedirectInfo; var url = redirectInfo != null ? redirectInfo.redirectUrl : ''; var source = GetUrlKeyValue("Source"); source = source == null || source == '' ? GetUrlKeyValue("NextPage") : source; source = source == null || source == '' ? GetUrlKeyValue("NextUsing") : source; url = source != null && source != '' ? source : url; STSNavigate(url); //on-premises SharePoint 2013 Nav.navigate(url); //SharePoint Online
What is says is that if no Source query string parameter is present then navigate to the URL given in _ctx.RedirectInfo.redirectUrl. The Source parameter may or may not be present but if it present it takes precedence. We don’t want to change this parameter, though, because that would mean that we either have to update the URL programmatically when the form is loaded or that we have to change every link pointing to the form.
But what we can do is changing what STSNavigate/Nav.navigate does.
We don’t really care what those functions do internally, eventually their main purpose is to navigate to the given URL. I have written three different functions that do the job. Choose the one that suits you best:
function changeRedirect(options) { for(var i = 0, buttons = document.querySelectorAll(options.selector); i < buttons.length; i++){ buttons[i].setAttribute( "onclick", "Nav.navigate = STSNavigate = function(){"+ " window.location = '" + options.redirectTo + "'"+ "};"+ buttons[i].getAttribute("onclick") ) } } document.addEventListener("DOMContentLoaded", function(event) { changeRedirect({ selector: "input[value=Save]", redirectTo: "https://google.com" }) changeRedirect({ selector: "input[value=Cancel]", redirectTo: "https://bing.com" }) })
function changeRedirect(options) { for (var i = 0, buttons = document.querySelectorAll(options.selector); i < buttons.length; i++) { var newOnClick = function(originalOnClick) { return function(){ Nav.navigate = STSNavigate = function() { window.location = options.redirectTo } originalOnClick() } } buttons[i].onclick = newOnClick(buttons[i].onclick) } } document.addEventListener("DOMContentLoaded", function(event) { changeRedirect({ selector: "input[value=Save]", redirectTo: "https://google.com" }) changeRedirect({ selector: "input[value=Cancel]", redirectTo: "https://bing.com" }) })
NodeList.prototype.changeRedirect = function(redirectTo){ for (var i = 0; i < this.length; i++) { var newOnClick = function(originalOnClick) { return function(){ Nav.navigate = STSNavigate = function() { window.location = redirectTo } originalOnClick() } } this.onclick = newOnClick(this.onclick) } } document.addEventListener("DOMContentLoaded", function(event) { document.querySelectorAll("input[value=Save]").changeRedirect("https://google.com") document.querySelectorAll("input[value=Cancel]").changeRedirect("https://bing.com") })
All three functions change STSNavigate/Nav.navigate depending on which button has been clicked and on default forms this works for the Save/Cancel-buttons below the form as well as the buttons in the ribbon.
Happy SharePointing!
This is a pretty neat strategy for coercing a redirect without having to use the "source" param in the URL. I have noticed, however, that this still doesn't work (neither does "source") if you've added an attachment to the list form – instead it always redirects to the list page. Have you encountered this? Any thought on how to handle?
Hi Rob,
That’s interesting. Haven’t noticed that before, but you are right, I can reproduce that behavior. I will do some digging. Thank you!
I straight up overwrote the STSNavigate function in my script with a simple alert for the URL and it doesn't even seem to hit STSNavigate after adding attachments. Maybe something in the attachment process is hijacking the "Save" button… Anyway, I feel a little better that I'm not the only one seeing this. ;-)
Hi Rob,
Did u happen to get a solution or any lead as to where to look. I am also facing the same issue. If an attachment is involved then the navigation won't work.
Thank you,
Neha
Thanks for sharing – helped with an issue I was having with client side rendering.
Hi, I've tried this part on Sharepoint Online.
But it does not redirect me.
Can you please help me to achieve this?
I have an Approve button the I want to redirect the Approve to another page instead of Task List page.
Thanks in advance
This is great,
the only one that worked for me was the middle one, with a js file referenced from a script editor web part. (sharePoint online)
This also fixed an issue in one of my custom forms where the multi line text fields would not save their data when creating a new item.
Hope more people will use this
Cheers