Short : How to make a default SharePoint NewForm.aspx add an item and stay on the input page instead of returning to the list view AllItems?
long :
I am asked to allow SharePoint users to enter many new items to a SharePoint list without having to return to AllItems each time they save.
This requirement applies to many lists so I don't want to develop specific code for every possible content type.
I though I could write a short js file and use it whenever the the user wants to save and continue.
So far I tried to add the "Save and continue" behavior in a Content Editor Web Part (CEWP).
My first approach was to change the Source= parameter with no success (either cancel returned also to the new source or the source was ignored when set in preSaveAction().
Then I tried to set the form action in preSaveAction :
<script type="text/javascript">
JSRequest.EnsureSetup();
var src = JSRequest.QueryString["Source"];
var exit = JSRequest.QueryString["exit"];
var isDialog = JSRequest.QueryString["IsDlg"];
var dlgParam = "";
if (isDialog)
dlgParam = "&IsDlg="+isDialog;
//If exit is defined its keeping default source parameter
if (exit) {
document.forms.aspnetForm.action= location.pathname+"?Source="+exit+dlgParam;
}
function PreSaveAction(){
//before saving the original source is saved in exit
exit=JSRequest.QueryString["Source"];
src=escapeProperly(window.location.protocol + '//' + window.location.host + _spPageContextInfo.serverRequestPath);
document.forms.aspnetForm.action=location.pathname+"?Source="+src+"&exit="+exit+dlgParam;
return true;
The action is updated as expected but the user is still redirected to AllItems.aspx when a new item is saved.
Another attempt was to add a specific button reusing the SharePoint javascript action used in the ribbon and page buttons
<script type="text/javascript">
function adressePage() {
return window.location.protocol + '//' + window.location.host + _spPageContextInfo.serverRequestPath;
}
function saveContinue() {
document.getElementById("cmdSaveContinue").disabled=true;
if (!PreSaveItem()) return false;
if (SPClientForms.ClientFormManager.SubmitClientForm("WPQ2")) {
SP.UI.Notify.addNotification("Saving ...", false);
window.location = adressePage();
} else {
WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("cmdSaveContinue", "", true, "", adressePage(), false, true));
}
document.getElementById("cmdSaveContinue").disabled=false;
}
</script>
<input id="cmdSaveContinue" onclick="javascript:return saveContinue();" type="button" value="Enregistrer et continuer" style="top: -5.5em; position: relative;"/>
This way, form validation is processed and the item is saved.
If error messages are returned, the form stays on NewItem but the error messages are lost after the window.location=... is executed.
When everything works well, the item is saved and the user is on a new empty NewForm.aspx.
But SharePoint SPClientForms.ClientFormManager.SubmitClientForm("WPQ2") is executed asynchronously and sometimes (not always) the redirection to
AllItems occurs after the end of my redirection.
I am stuck at this point and fear to be forced to edit each and every NewForm page in SPDesigner whenever a list is added...
Infos : SharePoint server 2013 on premise, SPDesigner possible
You can do this through InfoPath, which you should be able to use if you have SP on prem and SPDesigner access. If you go to InfoPath and customize the form, you can go to Data > Submit Options > (advanced >>) > After Submit > New Form.
You can either google 'InfoPath Save and New' or go to the Microsoft site and check out this walkthrough. Their walkthrough suggests using two buttons, one of which opens a new form and the other which closes the form.
Create a custom NewForm.aspx and add a new button and mention {} in redirect.
<input type="button" class="contact-button" value="Submit and Create New Request" name="btnSaven" onclick="javascript: {ddwrt:GenFireServerEvent('__commit;__redirect={}')}" />
add script editor web part to a view
<input type="button" value="Add items in continuity" onclick="openNewItemDialog()"/>
<script>
function openNewItemDialog() {
var options = {
url: 'http://sp/sites/dev/Lists/<yourList>/NewForm.aspx',
dialogReturnValueCallback: function(result, returnValue) {
if(result== SP.UI.DialogResult.OK)
{
openNewItemDialog()
}
}
}
SP.UI.ModalDialog.showModalDialog(options);
}
Related
I have a form which contains many drop-down and numeric slide-bar.
I am using post method to pass the selected variables to another page. Where I am getting the variables in the next page by $_POST() method.
And I am updating the variables passed into the database, after updation giving javascript pop-up as "you have saved successfully".
So my problem is when I click on browser back button, the values are getting updated in the database again and again. How can I prevent this by disabling browser back button.
You can have your post method open up a new tab so that there is no back navigation to go to:
<!DOCTYPE HTML>
<html>
<body>
<form action="www.google.com" method="post" target="_blank">
<input type="submit">
</form>
</body>
</html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$('#theSubmit').on('click', function () {
setTimeout(function(){
window.close();
}, 500);
})
</script>
The target generates the new window
And if you would like to close the old window add the two scripts that close the previous tab 500ms after the new tab is opened.
Instead of disabling the back button, you could redirect the user if he gets back to the page using sessions.
page1.php
session_start();
if (isset($_SESSION['block'])) {
header('Location: page2.php');
}
page2.php
session_start();
$_SESSION['block'] = true;
Another option:
This is how you could set values of all your input fields back, if the user clicks back:
page1.html
var block = localStorage.getItem("block");
window.addEventListener("beforeunload", function() {
if (block === 1) {
const block = true;
}
});
if (block) {
const inputs = document.getElementsByTagName('input');
for (input of inputs) {
input.value = '';
}
}
page2.html
localStorage.setItem("block", 1);
In this case, if you don't want your values get updated in your database, use:
if (!empty($_POST['my_value']) { // Add to database })
Don't disable the back button, fix the problem that the data is saved multiple times instead. You could use pass the users to a separate page with message "you have successfully...".
Then if the user tries to go back you look at $_SERVER['HTTP_REFERER'] if that is "successful.php" then don't save the data.
Disabling back buttons is a big reason for me to block a page so that I can't visit it again.
I truly hate when they do that or add several pages that you have to click back to get out of a page.
Whenever you post your data then you should check your post data that this is empty or not
<?php
if(isset($_POST) && !empty($_POST) ){
//your code for update
//Then after run update query and success message ,do empty the post
$_POST=array(); // empty the post
}
?>
I'm working on a group project for a class, and we have a webpage that is split into different tabs, so it is only one webpage, but appears to be different pages using Jquery so the page doesn't have to reload when switching between tabs. The problem I am having is that one of the tabs has a form to get information from the user, then after the user clicks the submit button, the info is sent to the database using php, causing the page to reload. Then depending on if the information was successfully sent to the database, there will be either "success" or "invalid" appended to the end of the URL. If the user submits this form, we want them to automatically come back to this tab on the reload, and I have tried doing this by using a script like this:
<script>
document.getElementById("baseTab").click();
window.onload = function() {
var theurl = document.location.href;
if (theurl.includes("success") || theurl.includes("invalid") {
document.getElementById("infoTab").click();
}
};
</script>
The baseTab is the tab we want to load whenever someone first loads the webpage, unless they have just submitted the form on the infoTab page. This code structure works on a simple test webpage I run on my computer, but when I try to push it to our project repository, it will only do the "baseTab".click, and not click the "infoTab" button even if theurl includes "success" or "invalid". I tried doing it without the window.onload(), but that doesn't work either. Also, if I do
if (theurl.includes("success") || theurl.includes("invalid") {
document.getElementById("infoTab").click();
}
else {
document.getElementById("baseTab").click();
}
then neither of the buttons get clicked. If their is an easier way to do this or you see where I am going wrong, any help would be appreciated. Thanks!
Before saying that the answers are already on the forum take note that I have already tried them to no avail. Basically the problem is that when I press enter to search it opens the google page in a new tab. How do I get it to open in the current tab?
This is the HTML
<div class="Search">
<img id="pic" src="http://i.imgur.com/fjAZgqe.png" alt="moose"/>
<form class="websearch">
<input autofocus placeholder="Google" type="text" id="GGLSite"> <!--this creates the textbox they can use to search. Note the ID is what the function grabs -->
<input type="button" id="GGLmeme" onclick="DoGGL()" style="display: none;" value="Search GGL"> <!-- this is just the button that calls the function. The value is whats shown on the button -->
</form>
</div>
This is the Javascript
function DoGGL(){
var GGLVar = document.getElementById("GGLSite").value; //this grabs the variable (search terms) from the textbox
var NewURL = "https://www.google.se/?gws_rd=ssl#safe=off&q=" + GGLVar; //this puts the site they typed into the wayback machines URL
var NewTabGGL = window.open(NewURL, "_blank"); //this opens a new tab with the URL.
if (NewTabGGL){ //make sure the browser can allow it
NewTabGGL.focus(); //switches them to the new tab -- done!
}
else{
alert("Popup didnt work");
}
}
$(document).ready(function(){
$('#GGLSite').keypress(function(e){
if(e.keyCode==13)
$('#GGLmeme').click();
});
});
I did some tweaks on your code (read the comments):
Javascript
// Remember capitalized functions are supposed to be used with the new operator, hence, this function must not be capitalized
function doGGL(event){
// Here we prevent the default behavior of the form submit
event.preventDefault();
// Javascript variables must not be capitalized
var gGLVar = document.getElementById("GGLSite").value;
var newURL = "https://www.google.se/?gws_rd=ssl#safe=off&q=" + gGLVar;
// This sentence navigates to desired URL in the same window
window.location.href = newURL;
}
$(document).ready(function(){
// There's no need to catch the enter key because that's the form default behavior. So I'm attaching the submit event to the function defined above
$('.websearch').on('submit', doGGL);
});
This didn't work in jsFiddle so I tried it in a local file called index.html with the same HTML, CSS but replacing the javascript with the latter.
Hope it helps!
If you are trying to just get to the page from this page, window.location = NewURL; would work. I don't see exactly what you're trying to do.
I made an autocomplete for a form input field that allows a user to add tags to a list of them. If the user selects any of the suggestions, I want the page to use add the new tag to a section of tags that already exist without the page reloading.
I want this to happen with 3 scenarios:
The user types in the tag, ignores the autocomplete suggestions and presses enter.
After typing in any part of a query, the user selects one of the autocomplete suggestions with the arrow keys and presses enter.
After typing in any part of a query, the user clicks on one of the autocomplete suggestions with the mouse.
I have been able to make scenario 1 work flawlessly. However, scenarios 1 and 2 make the page reload and still doesn't even add the tag to the list.
Scenarios 1 and 2 are both called by the same function:
$j("#addTag").autocomplete({
serviceUrl:'/ac',
onSelect: function(val, data){
addTag(data);
}
});
And here is the code for addTag():
function addTag(tag){
var url = '/addTag/' + tag;
//Call the server to add the tag/
$j.ajax({
async: true,
type: 'GET',
url: url,
success:function(data){
//Add the tag to the displayed list of already added tags
reloadTagBox(data);
},
dataType: "json"
});
//Hide the messages that have been displayed to the user
hideMessageBox();
}
Scenario 1 code:
function addTagByLookup(e, tag){
if(e && e.keyCode == 13)
{
/*This stops the page from reloading (when the page thinks
the form is submitted I assume).
*/
e.preventDefault();
//If a message is currently being displayed to the user, hide it
if ($j("#messageBox").is(":visible") && $j("#okayButton").is(":visible")){
hideMessageBox();
}
else{
//Give a message to the user that their tag is being loaded
showMessageBox("Adding the tag <strong>"+tag+"</strong> to your station...",'load');
//Check if the tag is valid
setTimeout(function(){
var url = '/checkTag/' + tag;
var isTagValid = checkTag(tag);
//If the tag is not vaid, tell the user.
if (isTagValid == false){
var message = "<strong>"+tag+"</strong>"+
" was not recognized as a valid tag or artist. Try something else.";
//Prompt the user for a different tag
showMessageBox(message, 'okay');
}
//If the tag is valid
else{
addTag(tag);
}
}, 1000);
}
}
}
I know I used the e.preventDefault functionality for a normal form submit in scenario 1, but I can't seem to make it work with the other scenarios and I'm not even sure that is the real problem.
I am using pylons as the MVC and using this tutorial for the autocomplete.
So in case anyone wants to know, my problem was had an easy solution that I should have never had in the first place.
My input tag was embedded in a form which submitted every time the input tag was activated.
I had stopped this problem in scenario 1 by preventing the default event from occurring when the user pressed enter. But since I didn't have access to this event in the jQuery event .autocomplete(), I couldn't prevent it.
I have a form which allows to view data in a page or download it in csv according to the submit button pressed.
Since it's a long database query I want to avoid the user to submit more than once (you know how heavy is users' index finger on left mouse button...) to avoid database overload and also to make user more relaxed...
I wrote this little jQuery code to substitute submit button(s) with a Processing, please wait and the classic animated spinning gif
$(document).ready(function(){
//preload wait img
var $waitImg = $('<img />').attr('src', '/img/wait.gif')
$('.wait').click(function(){
$(':submit').hide();
$(this).after($('<span>Processing, please wait...</span>').prepend($waitImg));
});
});
All works but has some drawbacks:
when user sees results and then press the browser's back button he will get again the Processing, please wait sentence and no submit buttons (what if he just wants to edit something and make a new query)
after user is prompted to download the CSV file he keeps on being told to wait...
Solutions could be to detect someway user is back or download stared or another way to tell him work is in progress.
The easier, the better.
When user sees results and then press the browser's back button he will get again the Processing, please wait sentence and no submit buttons (what if he just wants to edit something and make a new query)
The browser is caching the page. You could try resetting the values/removing the loading image in $(document).ready() which should fire when the user presses the back button using the onunload trick: Is there a cross-browser onload event when clicking the back button?
after user is prompted to download the CSV file he keeps on being told to wait...
It won't be possible to detect this without the help of the server. The easiest thing to do would be to "ping" the server via ajax and the server will tell the client if the download was initiated/sent to the user. This can be done by repeatability calling the server every i.e. 3 seconds to see if the download was initiated and if so, reset/hide the loading image and text.
You could use jQuery deferred to help make this easy and of a nice syntax.
jQuery
function downloadStarted()
{
var $def = $.Deferred();
var check = function() {
$.get('/ajax/check-download-status', function(response) {
if (response.started)
{
$def.resolve();
}
else
{
//Check again in 3 seconds
setTimeout(check, 3000);
}
}, 'json');
};
check();
return $def.promise();
}
Usage:
var success = function() { /* reset/hide loading image */ }
$.when(downloadStarted()).then(success);
PHP/Server side
On the server side ajax/check-download-status will look like so:
session_start();
$json['started'] = 0;
if ($_SESSION['download_started']) $json['started'] = 1;
return json_encode($json);
And obviously when your csv file is sent to the client, set $_SESSION['download_started'] to 1.
Found this:
Detecting the File Download Dialog In the Browser
and this is my code based on it:
html
<form ...>
<fieldset>
...
<div>
<input class="wait" id="submit" name="submit" type="submit" value="View" />
<input class="wait" id="submit" name="submit" type="submit" value="Download as CSV" />
</div>
</fieldset>
</form>
javascript
$(document).ready(function(){
var cookieCheckTimer;
var cookieName = 'download_token';
var $wait = $('.wait');
var $waitMsg = $('<span>Processing, please wait...</span>').prepend(
$('<img />').attr('src', '/img/wait.gif').css({
'vertical-align': 'middle',
'margin-right': '1em'
}));
//add hidden field to forms with .wait submit
$wait.parent().each(function(){
$(this).append($('<input />').attr({
'type': 'hidden',
'name': cookieName,
'id': cookieName
}));
});
$wait.click(function(){
var token = new Date().getTime();
//set token value
$('#' + cookieName).val(token);
//hide submit buttons
$(':submit').hide();
//append wait msg
$(this).after($waitMsg);
cookieCheckTimer = window.setInterval(function () {
if ($.cookie(cookieName) == token){
//clear timer
window.clearInterval(cookieCheckTimer);
//clear cookie value
$.cookie(cookieName, null);
//detach wait msg
$waitMsg.detach();
//show again submit buttons
$(':submit').show();
}
}, 1000);
});
});
Server side if a download_token key is found in request parameters a cookie with its name and value is set.
Here's my python (pylons) code for a controller's __before__ :
python
cookieName = 'download_token'
#set file download coockie if asked
if cookieName in request.params:
response.set_cookie(cookieName,
#str: see http://groups.google.com/group/pylons-discuss/browse_thread/thread/7d42f3b28bc6f447
str(request.params.get(self._downloadTokenName)),
expires=datetime.now() + timedelta(minutes=15))
I set cookie expire time to 15 minutes to not fill up client cookies, you choose an appropriate duration based on time needed by task.
This also will work with browser back button issue as when going back the cookie will be found and buttons restored.