And when I made a feeble attempt to use an Ajaxform instead, it didnt work. So is it possible to use an AjaxCall for this? I'm sure there must be a way to make an ajaxcall so you don't have to make a postback. Could someone please explain how? =)
becuase if i do not then i get errors something about missing page, the BeginUmbracoForm puts in some hidden fields route values think it uses those to give you a page? The other issue i had was in my surfacecontroller i was using dictionary items and they would be blank as it would lose the thread culture so i had to do
protectedvoidSetCultureForAjax(){//we lose culture and dictionary wont get labels therefore set it on the threadstringcode=_umbracoService.GetCultureCode();//Get the culture info of the language codeCultureInfoculture=CultureInfo.CreateSpecificCulture(code);Thread.CurrentThread.CurrentCulture=culture;Thread.CurrentThread.CurrentUICulture=culture;}
also from what i can remember none of my models with ajax calls were inheriting from rendermodel
I never got it to work, and I didnt have time to keep trying, but if I remember correctly it had to do with some code that was compiled into the Umbraco Forms DLL's.
Sorry, I never got it to work atleast, and the same for Jesper it seems.
Too bad that it was real easy to do with Countour :(
Although I do not get the same error, but rather the exception when hitting the submit button: http://prntscr.com/8zbjsg.
Previously I have tried to implement the 'Ajax.BeginForm' method, but the website was reporting 404 to the action method: /umbraco/Surface/UmbracoForms/HandleForm.
That creates an encrypted value containing route information, then outputs that as a hidden input field, "ufprt". That is used on postback to locate the action method and controller (rather than the typical MVC technique of using the URL to do that locating). If you use BeingForm rather than BeginUmbracoForm, you will be missing that value, so I imagine you'd have to add it back yourself.
If you generate that in your form, and pass it along in your AJAX request, you may have better luck.
Could you post the code that you are using and clarify what you mean by "not working"? When you say "not working", that could mean a number of things:
A request isn't being sent to the server.
The server isn't responding to the request.
The server is responding to the request in a way you aren't expecting.
The server seems to be responding as you expect, but when you update the page based on the response you are seeing something different than what you'd expect to see.
Any number of other possible ways things can go wrong.
More info will be needed before we can give specific advise on what may be going wrong in your scenario.
all the jquery scripts and the umbracoForms scripts are loaded in master page.
i change the @using (Html.BeginUmbracoForm<Umbraco.Forms.Web.Controllers.UmbracoFormsController>("HandleForm"))
to @using (Ajax.BeginForm("UmbracoForms", "HandleForm", new { area = "Surface" }, new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "Success()",
OnFailure = "Failure()",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "contour_form_" + Model.FormName.Replace(" ", "")
}, new { enctype = "multipart/form-data", role = "form" }))
inside the form object i enter the extra hidden field you mention as follows var _encryptedString = EncryptedRoute.GetEncryptedRoute("UmbracoForms", "HandleForm", "Surface", null);
<input type="hidden" name="ufprt" value="@_encryptedString" />
i create the EncryptedRoute.GetEncrytedRoute public static funtion copied from the UmbracoHelper.CreateEncryptedRouteString because this function in UmbracoHelper is internal and not available from razor syntax.
So everything was ok, when i press the submit button i am getting failure from the ajax post.
You should continue to use Html.BeginUmbracoForm (i.e., do not use Ajax.BeginForm). That will atuomatically add the ufprt hidden field for you (I only explained how it was doing it to help others understand what was going on). I repeat, you do not need to generate the ufprt field for yourself.
Once you have the form rendered, I'd use jQuery to intercept the submit event for the form and create an AJAX request using $.ajax (also cancelling the initial full postback). When you do the $.ajax, be sure to include the hidden ufprt field in the request (along with the rest of the form fields).
I'm not sure what Umbraco Forms will give you as a result. My guess is it will give you the entire markup for the page, but you'll just have to try it out to see. It may be clever enough to detect an AJAX submission and return some sort of partial result.
Nicholas that was great idea.
I follow what you said and now everything it works fine. So as you said i am using the Html.BeginUmbracoForm but i change it a bit like
Html.BeginUmbracoForm<Umbraco.Forms.Web.Controllers.UmbracoFormsController>("HandleForm", null, new { id= Model.FormId }, FormMethod.Post)
in order to give an id. I am doing that because in the jquery script i have to be sure that i will intercept the submition only for this form.
Then i wrote the following script:
<script type="text/javascript">
$(document).ready(function () {
//Intercept Submit button in order to make ajax call instead of a postback
$('#@Model.FormId').preventDoubleSubmission();
})
// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function () {
$(this).on('submit', function (e) {
e.preventDefault();
var $form = $(this);
if ($form.data('submitted') === true) {
// Previously submitted - don't submit again
} else {
if ($form.valid()) {
// Mark it so that the next submit can be ignored
$form.data('submitted', true);
// Make ajax call form submission
$.ajax({
url: $form.attr('action'),
type: 'POST',
cache: false,
data: $form.serialize(),
success: function (result) {
console.log(result);
//ToDo: Add code to replace html inside the div that holds the form with a Success message.
}
});
}
}
});
// Keep chainability
return this;
};
I am using your technique and at first glance all appears to be working great, form entries are saved etc. so have been using in a live environment.
However, requirements have since changed and now I have had to add a workflow to my ajax enabled form.. But.. on debugging, it would appear that my workflow is not being hit when the form is submitted via ajax. Should I be doing something special to get it being called? The workflow isn't the issue as it's being called by other forms submitted in the usual way.
Any thoughts would be appreciated, unfortunately this is a change that needs to go live today, never figured it would be an issue when I said it should be fine to go live :-/
Not sure how relevent this is since this is an old topic, but I've sold it this way. I created a controller which inherited from the UmbracoFormsController and a ActionResult to handle the ajax calls:
public class UmbracoFormsAjaxController : UmbracoFormsController
{
private IPublishedContent _basePage;
protected override IPublishedContent CurrentPage {
get
{
return _basePage;
}
}
[HttpPost, ValidateInput(false), ValidateFormsAntiForgeryToken, ValidateCaptcha]
public ActionResult HandleFormAjax(FormViewModel model, bool captchaIsValid, int currentPageId)
{
// Set base page
var helper = new UmbracoHelper(UmbracoContext.Current);
_basePage = helper.TypedContent(currentPageId);
// Handle form
HandleForm(model, captchaIsValid);
// Return rendered view only
return RenderForm(model.FormId, model.RecordId, model.Theme, true);
}
}
The HandleForm method handles the validation and record creation, and the RenderForm the rendering of your UmbracoForms form.
The reason I overloaded CurrentPage is because in an AJAX call, which usually is to a different url than the current page url, Umbraco can't find the actual current page, so I set it in my overloaded HandleForm method using a hidden field in my form. I also added a hidden field for the theme, since by default it's not added to the form and it's null.
So basically my form looks like:
@using (Ajax.BeginForm("HandleFormAjax", "UmbracoFormsAjax", new AjaxOptions
{
InsertionMode = InsertionMode.ReplaceWith,
UpdateTargetId = "umbraco_form_" + Model.FormClientId,
AllowCache = false
}))
{
@* Standard form meta data *@
@Html.AntiForgeryToken()
@Html.HiddenFor(x => Model.FormId)
@Html.HiddenFor(x => Model.FormName)
@Html.HiddenFor(x => Model.RecordId)
@Html.HiddenFor(x => Model.PreviousClicked)
if (TempData.ContainsKey("parent"))
{
<input type="hidden" name="currentPageId" value="@(((RenderModel)TempData["parent"]).Content.Id)" />
TempData.Remove("parent");
}
<input type="hidden" name="Theme" value="landingspage" />
@* These 2 cannot use the htmlhelper *@
<input type="hidden" name="FormStep" value="@Model.FormStep" />
<input type="hidden" name="RecordState" value="@Model.RecordState" />
@* Render the form html *@
@Html.Partial(formThemedView)
}
This way I'm actually using an AJAX postback the way it's supposed to work
Jeroen, thanks for posting code that works for you. Question for you regarding this example, how is "parent" set into the TempData? I'm having an issue where the form just redirects to a returned partial view of the form upon submit - and I think it's because the parent / currentPageId vars aren't getting set.
So, at this point my form does render on the page and the field validation works and the form submits via AJAX to my HandleFormAjax() action. However, inside that action at the line HandleForm(model); I get the following error:
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=Umbraco.Forms.Core
StackTrace:
at Umbraco.Forms.Core.Services.WorkflowService.GetPageElements()
at Umbraco.Forms.Core.Services.WorkflowService.ExecuteWorkflows(List`1 workflows, RecordEventArgs e)
at Umbraco.Forms.Core.Services.WorkflowService.ExecuteWorkflows(Record record, Form form, FormState state, Boolean editMode)
at Umbraco.Forms.Core.Services.RecordService.Submit(Record record, Form form)
at Umbraco.Forms.Web.Controllers.UmbracoFormsController.SubmitForm(Form form, FormViewModel model, Dictionary`2 state, ControllerContext context)
at Umbraco.Forms.Web.Controllers.UmbracoFormsController.GoForward(Form form, FormViewModel model, Dictionary`2 state)
at Umbraco.Forms.Web.Controllers.UmbracoFormsController.HandleForm(FormViewModel model)
at myProject.Controllers.UmbracoFormsAjaxController.HandleFormAjax(FormViewModel model, Int32 currentPageId) in C:\temp_source\projectfolder\mySolution\myProject\Controllers\UmbracoFormsAjaxController.cs:line 73
Something is blowing up inside of WorkflowService.GetPageElements() and I'm guessing that "Page" refers to the current Umbraco page. And, of course, since this process was kicked off by an AJAX call there is no current Umbraco page (as far as the process is aware).
In UmbracoFormsAjaxController we're setting the CurrentPage property when the form makes the AJAX call but apparently that's not enough?? I have looked around at the other properties available to me and I don't see anything further I can do.
I'm hoping that someone else might have an idea?
BTW; just to re-iterate. The whole reason I'm doing this is so that Umbraco Forms will work on pages that are being Output Cached. Yes, I build all my widgets on my pages so that render time is at a minimum, but Output Caching still greatly improves the responsiveness of the site and so I'm loath to just turn it off.
It seems to me that Umbraco Forms should support Output Caching via using AJAX forms out-of-the-box ... but I guess that's just me.
Does anyone have an ideas where I can go from here?
Umbraco Forms and Ajax
Hi there!
When I used Contour, I managed to change the form to use an ajaxform, instead of an html form.
But heres the issue. With the new Umbraco Forms the code looks like this:
@using (Html.BeginUmbracoForm<Umbraco.Forms.Web.Controllers.UmbracoFormsController>("HandleForm"))
And when I made a feeble attempt to use an Ajaxform instead, it didnt work. So is it possible to use an AjaxCall for this? I'm sure there must be a way to make an ajaxcall so you don't have to make a postback. Could someone please explain how? =)
Cheers,
Mats
Would like to know this too.
best
Jesper
Did you add jquery ajax libs I have done this and it works
yes sir :)
Ive added:
<scriptsrc="/js/jquery.js"></script>
<scriptsrc="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.13.1/jquery.validate.min.js"></script>
<scriptsrc="http://ajax.aspnetcdn.com/ajax/mvc/5.1/jquery.validate.unobtrusive.min.js"></script>
@Umbraco.RenderMacro("umbracoforms.RenderScripts")
but form is submittet with full reload. But if thats all it takes then it might be something else that interferes.
Best
Jesper
@ismail .. and you did no change to the form rendering? So it still using this? :
@using (Html.BeginUmbracoForm<Umbraco.Forms.Web.Controllers.UmbracoFormsController>("HandleForm"))
Jesper,
Ah yes my bad, so I had todo
becuase if i do not then i get errors something about missing page, the BeginUmbracoForm puts in some hidden fields route values think it uses those to give you a page? The other issue i had was in my surfacecontroller i was using dictionary items and they would be blank as it would lose the thread culture so i had to do
also from what i can remember none of my models with ajax calls were inheriting from rendermodel
Regards
Ismail
Hi Ismail,
Thanks a bunch. I'll give it a go.
best
Jesper
It didnt seem to work for me. I might be doing something wrong but I have no time.
I'll wait for an official ajax support for Umbraco Forms and do my custom ones until then .. https://gist.github.com/jesperordrup/8cae76e368f65b7a1346
best
Jesper
Anyone sorted this already?
1) I added references to the scripts
2) I changed the Form.cshtml from
to
But no luck. When the form is submitted, the button gets disabled and nothing happens... When I review the HTML, I see the correct URL is rendered:
I never got it to work, and I didnt have time to keep trying, but if I remember correctly it had to do with some code that was compiled into the Umbraco Forms DLL's. Sorry, I never got it to work atleast, and the same for Jesper it seems.
Too bad that it was real easy to do with Countour :(
I didnt get it to work . Time didnt allow me to work much with it so I went with rolling my own.
Crossing fingers for future Contour version supporting Ajax and some docs that shows it.
/Jesper
Time is always the issue, same here.
I got close, but in the AJAX call the UmbracoContext was lost, and that is needed inside the controller. Think it is the same as MatsStam experienced.
I got even closer this week by posting to the page's url using an Ajax request (see also Tom's post in this thread https://our.umbraco.org/forum/developers/api-questions/48945-Current-Page-doesnt-exist-in-SurfaceController-With-Ajax-Form- ). But the response was about to render the form again which caused some issues, and I had to alter the Form.cshtml that much that I left it for what it was. Also because of not knowing the side effects of posting back to the same page.
At that point, I ran out of time and decided to go the old-fashioned-postback-way.
Has anyone managed to get close to solving this issue?
I have added the same changes to custom 'Form.cshtml' file as marcelh mentioned:
Form tag:
and I get the correct form tag rendered:
Script references:
Although I do not get the same error, but rather the exception when hitting the submit button: http://prntscr.com/8zbjsg.
Previously I have tried to implement the 'Ajax.BeginForm' method, but the website was reporting 404 to the action method: /umbraco/Surface/UmbracoForms/HandleForm.
I have also posted the question on StackOverflow.
I haven't tried to get AJAX working with Umbraco Forms (yet), but reading through this thread I haven't seen anybody try to inject the "ufprt" hidden field that Umbraco injects when you call BeginUmbracoForm(): https://github.com/umbraco/Umbraco-CMS/blob/775e63148d9c9e0ba4ffad3b697f6f2e2ca9f28b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs#L351
The two key lines in that file are these:
That creates an encrypted value containing route information, then outputs that as a hidden input field, "ufprt". That is used on postback to locate the action method and controller (rather than the typical MVC technique of using the URL to do that locating). If you use BeingForm rather than BeginUmbracoForm, you will be missing that value, so I imagine you'd have to add it back yourself.
If you generate that in your form, and pass it along in your AJAX request, you may have better luck.
Hi,
I have done all the above, i follow your comments for the extra hidden field but still not working.
Any solution?
Could you post the code that you are using and clarify what you mean by "not working"? When you say "not working", that could mean a number of things:
More info will be needed before we can give specific advise on what may be going wrong in your scenario.
@using (Html.BeginUmbracoForm<Umbraco.Forms.Web.Controllers.UmbracoFormsController>("HandleForm"))
to@using (Ajax.BeginForm("UmbracoForms", "HandleForm", new { area = "Surface" }, new AjaxOptions { HttpMethod = "POST", OnSuccess = "Success()", OnFailure = "Failure()", InsertionMode = InsertionMode.Replace, UpdateTargetId = "contour_form_" + Model.FormName.Replace(" ", "") }, new { enctype = "multipart/form-data", role = "form" }))
var _encryptedString = EncryptedRoute.GetEncryptedRoute("UmbracoForms", "HandleForm", "Surface", null); <input type="hidden" name="ufprt" value="@_encryptedString" />
So everything was ok, when i press the submit button i am getting failure from the ajax post.
You should continue to use
Html.BeginUmbracoForm
(i.e., do not useAjax.BeginForm
). That will atuomatically add theufprt
hidden field for you (I only explained how it was doing it to help others understand what was going on). I repeat, you do not need to generate theufprt
field for yourself.Once you have the form rendered, I'd use jQuery to intercept the
submit
event for the form and create an AJAX request using$.ajax
(also cancelling the initial full postback). When you do the$.ajax
, be sure to include the hiddenufprt
field in the request (along with the rest of the form fields).I'm not sure what Umbraco Forms will give you as a result. My guess is it will give you the entire markup for the page, but you'll just have to try it out to see. It may be clever enough to detect an AJAX submission and return some sort of partial result.
Nicholas that was great idea. I follow what you said and now everything it works fine. So as you said i am using the
Html.BeginUmbracoForm
but i change it a bit likein order to give an id. I am doing that because in the jquery script i have to be sure that i will intercept the submition only for this form.
Then i wrote the following script:
Thank you for the idea.
Hi Thomas,
Does this actually work?
When I try this approach I get a "request must be made in the context of an Umbraco request" error.
Thanks
Steve
Yes it does. I am already using it in live environment.
Hi Thomas,
I am using your technique and at first glance all appears to be working great, form entries are saved etc. so have been using in a live environment.
However, requirements have since changed and now I have had to add a workflow to my ajax enabled form.. But.. on debugging, it would appear that my workflow is not being hit when the form is submitted via ajax. Should I be doing something special to get it being called? The workflow isn't the issue as it's being called by other forms submitted in the usual way.
Any thoughts would be appreciated, unfortunately this is a change that needs to go live today, never figured it would be an issue when I said it should be fine to go live :-/
Cheers..
Mark
Hi Mark,
Have you found a solution for using workflows and Ajax posting?
In version 4.2.1 it worked great but after I updated to 4.3.2 it stopped working. It just doesn't hit the workflow
Thanks Thomas,
I got it working this morning. Turns out I was posting to the wrong URL.
Thanks
Steve
Any idea why the method Thomas recommends would break form conditions?
Not sure how relevent this is since this is an old topic, but I've sold it this way. I created a controller which inherited from the UmbracoFormsController and a ActionResult to handle the ajax calls:
The HandleForm method handles the validation and record creation, and the RenderForm the rendering of your UmbracoForms form.
The reason I overloaded CurrentPage is because in an AJAX call, which usually is to a different url than the current page url, Umbraco can't find the actual current page, so I set it in my overloaded HandleForm method using a hidden field in my form. I also added a hidden field for the theme, since by default it's not added to the form and it's null.
So basically my form looks like:
This way I'm actually using an AJAX postback the way it's supposed to work
Jeroen, thanks for posting code that works for you. Question for you regarding this example, how is "parent" set into the TempData? I'm having an issue where the form just redirects to a returned partial view of the form upon submit - and I think it's because the parent / currentPageId vars aren't getting set.
I'm trying this in Umbraco 8 and I am getting an error that I don't know how to resolve. First, my code:
My controller:
Here's my customer Render.cshtml in my theme directory:
Then, my partial that calls the RenderMacro helper:
So, at this point my form does render on the page and the field validation works and the form submits via AJAX to my HandleFormAjax() action. However, inside that action at the line HandleForm(model); I get the following error:
Something is blowing up inside of WorkflowService.GetPageElements() and I'm guessing that "Page" refers to the current Umbraco page. And, of course, since this process was kicked off by an AJAX call there is no current Umbraco page (as far as the process is aware).
In UmbracoFormsAjaxController we're setting the CurrentPage property when the form makes the AJAX call but apparently that's not enough?? I have looked around at the other properties available to me and I don't see anything further I can do.
I'm hoping that someone else might have an idea?
BTW; just to re-iterate. The whole reason I'm doing this is so that Umbraco Forms will work on pages that are being Output Cached. Yes, I build all my widgets on my pages so that render time is at a minimum, but Output Caching still greatly improves the responsiveness of the site and so I'm loath to just turn it off.
It seems to me that Umbraco Forms should support Output Caching via using AJAX forms out-of-the-box ... but I guess that's just me.
Does anyone have an ideas where I can go from here?
Thanks!
Hi Chester Campbell did you get any further ran into similar problems myself with umbraco froms
No, I'm afraid not.
is working on a reply...