Umbraco MVC(4.11.1) Surface controller using an AJAX form
Hello :). I have a website using Umbraco MVC (V: 4.11.1). At the top of all the pages we a login form with a username. The actual surface controller is working and if i use UmbracoBeginForm() everything works fine and the page reloads.
However we do not want the page to full reload, just part of the page, so decided to use an Ajax form. However when the post is made an error is thrown that the view Login cannot be found.
How are you hooking up the Ajax parts? As long as you submit as a post to the surface controller action including the hidden var that the surface controller uses for "context" you should be able to post via Ajax fine (you may want to make sure your action returns a Json result instead of a standard view result though at the end)
If you could post some code it might help us point you in the right direction.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MySite.Models;
namespace MySite.Controllers
{
public class FormSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
[HttpPost]
public JsonResult Contact(FormModel model)
{
if (!ModelState.IsValid)
{
return Json(new { success = false });
}
return Json(new { success = true });
}
}
}
Models\FormModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MySite.Models
{
public class FormModel
{
[Required]
public string FirstName { get; set; }
}
}
function feedback(result) {
if (result.success) {
console.log('ok');
} else {
var error = "Error";
if (result.error) {
error = result.error;
}
console.log(error);
}
}
So when I do something like this in a standard ASP.NET MVC 4 project with jquery validation, Ajax.BeginForm generates HTML that looks like this (Browser inspector shows like this):
When I click the "submit" button an ajax post request is sent, and my "feedback" method is fired to get the result (the controller returns a JsonResult). The form works.
Umbraco generates HTML that looks like this:
<form onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: 'POST', onSuccess: Function.createDelegate(this, feedback) });" onclick="Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));" method="post" action="/umbraco/Surface/FormSurface/Contact">
In this form generated by umbraco, when I click on "submit" the form is fully posted and the browser shows the contents of "/umbraco/Surface/FormSurface/Contact" ({"success":true}) instead of firing just an ajax request like in a stanrd ASP.NET MVC4 project and handle the result via feedback method. Can you help?
@Matt, what is the "hidden var that the surface controller uses for "context"" ? Can you provide an example? Maybe my example does a full post because I don't include that var, but as I don't see any documented example I find it hard to guess how to proceed... Thanks for letting me know...
Yes it's the same call, but in umbraco, the generated HTML is unluckily like I posted above.
I posted my code, it doesn't work as expected. There must be somewhere a bug, in my code, or in umbraco.
Can someone help and share some working code for a simple ajax form?
What I'm requesting should be a piece of cake for who has done it already:
A surface controller with JsonResult
A view with a form created via Ajax.BeginForm and an input field as example
A javascript function called e.g. "feedback" that will capture the Json response, and on success just console.log("it works"); or alert("it works")
Expected result: clicking on submit will fire an ajax request and the console will display "it works" (or an alert)
I really do not know what to do, if I don't get this working I must move on, forget about "Ajax.BeginForm" and do everything manually, but then I wonder what kind of MVC I can use in umbraco if it doesn't work... to achieve the scenario described above, using an MVC 4 template from visual studio 2012 I need just a few minutes and it works. If you want I share a zip file containing a solution.
Yea that post looks an ok implimentation. That will work. Should not have all that logic in your controller though. Abstract is and have the controller called a method returning an enum result you can switch on :). Charlie.
SOLVED. THANK YOU. The blog post you found helped me to solve my issue.
To sum up, to fix the code I shared in my previous posts:
I had to move the form inside another partial view, as explained in the umbraco partial views documentation in order to use my strongly typed model (FormModel) and have all the nice client validation given automatically by jquery validation + unobtrusive.
I forgot (shame on me) to insert the jquery-validate, jquery-validate-unobtrusive and jquery.unobtrusive-ajax javascript files (I noticed that before, but somehow something didn't work)
I had to add 2 keys in my web.config file to allow client validation
Note, in the turorial dawoe mentioned, the AjaxOptions are too many for my needs & taste. My "feedback" function takes the resulting JSON result and handles success = true or success = false and takes -if existing- extra information such as a message (for success) or error for failure (these of course have to be added in the Controller) also I didn't use the UpdateTargetId as I don't want to update a div in my page, I do it manually via feedback function.
Umbraco MVC(4.11.1) Surface controller using an AJAX form
Hello :). I have a website using Umbraco MVC (V: 4.11.1). At the top of all the pages we a login form with a username. The actual surface controller is working and if i use UmbracoBeginForm() everything works fine and the page reloads.
However we do not want the page to full reload, just part of the page, so decided to use an Ajax form. However when the post is made an error is thrown that the view Login cannot be found.
Has anyone got any ideas? Thanks. Charlie.
Actually it would have been cool to see an answer here... I'm looking exactly for the same thing...
I have such a form:
@{ var ajaxOptions = new AjaxOptions
{
OnSuccess = "feedback",
HttpMethod = "POST"
}; }
@using(Ajax.BeginForm("Contact", "FormSurface", ajaxOptions))
{
<label for="FirstName">FirstName</label>
<input name="FirstName" />
<input type="submit"/>
}
when I click submit, the page does a full post... I was expecting an ajax call to be done and my function "feedback" to be called...
...any ideas/help is appreciated. THX
Hey guys,
How are you hooking up the Ajax parts? As long as you submit as a post to the surface controller action including the hidden var that the surface controller uses for "context" you should be able to post via Ajax fine (you may want to make sure your action returns a Json result instead of a standard view result though at the end)
If you could post some code it might help us point you in the right direction.
Matt
I personaly use JQuery with asynchronous form postbacks for this purpose. I then return a JSON result which works fine.
Wow this seems like so long ago, ended up using the implemtation you mention above Andreas :). Ajax with some jquery that gets the JSON result :)
Hi there, here some code so you see what I have.
Controllers\FormSurfaceController.cs
Models\FormModel.cs
Views\Shared\_Layout.cshtml
Views\Form.cshtml
/Scripts/common.js
So when I do something like this in a standard ASP.NET MVC 4 project with jquery validation, Ajax.BeginForm generates HTML that looks like this (Browser inspector shows like this):
When I click the "submit" button an ajax post request is sent, and my "feedback" method is fired to get the result (the controller returns a JsonResult). The form works.
Umbraco generates HTML that looks like this:
In this form generated by umbraco, when I click on "submit" the form is fully posted and the browser shows the contents of "/umbraco/Surface/FormSurface/Contact" ({"success":true}) instead of firing just an ajax request like in a stanrd ASP.NET MVC4 project and handle the result via feedback method. Can you help?
@Matt, what is the "hidden var that the surface controller uses for "context"" ? Can you provide an example? Maybe my example does a full post because I don't include that var, but as I don't see any documented example I find it hard to guess how to proceed... Thanks for letting me know...
The form is missing an ID, that could be a problem. Also it does not define the data-ajax attributes required. Is this the same @Ajax.BeginForm call?
Yes it's the same call, but in umbraco, the generated HTML is unluckily like I posted above.
I posted my code, it doesn't work as expected. There must be somewhere a bug, in my code, or in umbraco.
Can someone help and share some working code for a simple ajax form?
What I'm requesting should be a piece of cake for who has done it already:
I really do not know what to do, if I don't get this working I must move on, forget about "Ajax.BeginForm" and do everything manually, but then I wonder what kind of MVC I can use in umbraco if it doesn't work... to achieve the scenario described above, using an MVC 4 template from visual studio 2012 I need just a few minutes and it works. If you want I share a zip file containing a solution.
I haven't done it with a Ajax.BeginForm but I've done it with my own jQuery ajax calls.
I create a surface controller with 2 actions. One to render the form and one to handle the post.
In my ajax call I just called the action to handle the post and return JSON.
There was one catch. And that is how surface controller actions are routed.
See the documentation page here : http://our.umbraco.org/documentation/Reference/Mvc/surface-controllers
Especially the part about Routing for locally declared controllers
Ok I can also create my own ajax calls, but this is what I wanted to avoid...
I would like to use those cool things that come with MVC such as:
Haven't tried that yet but just found this blog post about it : http://www.systenics.com/blog/creating-an-ajax-enabled-contact-form-in-umbraco-6-with-aspnet-mvc-4-and-twitter-bootstrap/?tag=Umbraco+6
Maybe you can find a solution there ?
Dave
Yea that post looks an ok implimentation. That will work. Should not have all that logic in your controller though. Abstract is and have the controller called a method returning an enum result you can switch on :). Charlie.
Hi Dawoe,
SOLVED. THANK YOU. The blog post you found helped me to solve my issue.
To sum up, to fix the code I shared in my previous posts:
I couldn't seem to get the routing right using Ajax.BeginForm the form url for the action it generates is:
/umbraco/RenderMvc/SendMail?Length=7
instead of /umbraco/surface/Contact/SendMail if I try and use the out of the box functionality in v7.2
anyone got any hints short of hardcoding the form open tag to something like:
<form action="/umbraco/surface/Contact/SendMail" class="form quick-contact" data-ajax="true" data-ajax-failure="ShowError()" data-ajax-loading="#contact-load" data-ajax-method="POST" data-ajax-mode="replace" data-ajax-success="ShowSuccess()" data-ajax-update="#target" id="form0" method="post" role="form" novalidate="novalidate">
is working on a reply...