Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic Umbraco 6.1.1 SurfaceController Questions

I've searched all the available tutorials I can find, and I'm still having trouble with Umbraco Surface Controllers. I've created a bare-bones Surface Controller example which sorta works, but has some issues. Here's my code so far, questions to follow:

ContactformModel1.cs:

public class ContactFormModel1
{

    public string Email { get; set; }
    public string Name { get; set; }
    public string HoneyPot { get; set; }

    public string Title { get; set; }
    public string Last { get; set; }
    public string First { get; set; }
    public string Addr { get; set; }
    public string Phone { get; set; }
    public string Time { get; set; }
    public string Comment { get; set; }
}

ContactSurfaceController.cs:

public class ContactSurfaceController : Umbraco.Web.Mvc.SurfaceController
{

    public ActionResult Index()
    {
        return Content("this is some test content...");
    }

    [HttpGet]
    [ActionName("ContactForm")]
    public ActionResult ContactFormGet(ContactFormModel1 model)
    {
        return PartialView("~/Views/ContactSurface/Contact1.cshtml", model);
    }

    [HttpPost]
    [ActionName("ContactForm")]
    public ActionResult ContactFormPost(ContactFormModel1 model)
    {
        // Return the form, just append some exclamation points to the email address
        model.Email += "!!!!";
        return ContactFormGet(model);
    }


    public ActionResult SayOK(ContactFormModel1 model)
    {
        return Content("OK");
    }

}

Contact.cshtml:

@model ContactFormModel1

 @using (Html.BeginUmbracoForm<ContactSurfaceController>("ContactForm"))
 {
     @Html.EditorFor(x => Model)
     <input type="submit" />
 }

ContactMacroPartial.cshtml:

@inherits Umbraco.Web.Macros.PartialViewMacroPage

@Html.Action("ContactForm", "ContactSurface")

My Questions:

  1. I'm pretty sure that return ContactFormGet(model) is wrong in the ContactFormPost method, but everything else I've tried throws an error.

    When I try return RedirectToCurrentUmbracoPage(), I get Cannot find the Umbraco route definition in the route values, the request must be made in the context of an Umbraco request.

    When I try return CurrentUmbracoPage(), I get Can only use UmbracoPageResult in the context of an Http POST when using a SurfaceController form.

  2. The routing appears to work correctly (when I put a breakpoint inside ContactFormPost, the debugger stops there). But when the form comes back, I get the exact values I submitted. I don't see the !!! appended to the email address. (Note, this bit of code is just for debugging, it's not meant to do anything useful).

  3. How do I call the "SayOK" method in the controller? When I change the BeginUmbracoForm method to point to SayOK, I still get stuck in the ContactFormPost method.

I'm sure I'm missing something incredibly stupid, but I can't figure this out for the life of me.

like image 835
misterspaceman Avatar asked Jul 08 '13 17:07

misterspaceman


2 Answers

I wanted to take a moment to say how I resolved this. After playing around some more, I realized that I didn't really state my problem clearly. Basically, all I'm trying to do is embed an MVC form inside a Partial View Macro, so that it could be used in the content of a page (not embedded in the template).

I could get this solution to work, but I really didn't like how much logic the author put inside the View file. So I adapted his solution this way:

Partial View Macro (cshtml) file:

@inherits Umbraco.Web.Macros.PartialViewMacroPage
@using Intrepiware.Models
@{
    bool isPostback = !String.IsNullOrEmpty(Request.Form["submit-button"]);
    if(isPostback)
    {
        @Html.Action("CreateComment", "ContactSurface", Request.Form)   
    }
    else
    {
        @Html.Partial("~/Views/Partials/ContactForm.cshtml", new ContactFormModel())
    }

}

Form Partial View (cshtml) file:

@using Intrepiware.Models
@using Intrepiware.Controllers
@model ContactFormModel

<p>
    <span style="color: red;">@TempData["Errors"]</span>
</p>
<p>
    @TempData["Success"]
</p>
<div id="cp_contact_form">

@using(Html.BeginUmbracoForm("CreateComment", "BlogPostSurface"))
{
    @* Form code goes here *@
}

ContactSurfaceController.cs file:

public class ContactSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult ubCreateComment(ContactFormModel model)
    {
        if (processComment(model) == false)
            return CurrentUmbracoPage();
        else
            return RedirectToCurrentUmbracoPage();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult CreateComment(ContactFormModel model)
    {
        if(processComment(model) == true)
        {
            TempData["Success"] = "Thank you for your interest. We will be in contact with you shortly.";
            ModelState.Clear();
        }
        return PartialView("~/Views/Partials/ContactForm.cshtml");
    }

    private bool processComment(ContactFormModel model)
    {
            // Handle the model validation and processing; return true if success
    }

}

The controller is designed so that the form can be embedded either in the template or a Partial View Macro. If it's embedded in a template, the form should post to ubCreateComment; if it's in a macro, post to CreateComment.

I'm almost positive there's a better/more correct way of doing this, but I ran out of time to work on the project. If someone has a better solution, please post it!

One final question/note: You'll notice that the partial view macro posts Request.Form to the ContactSurfaceController.CreateComment, and MVC magically serializes it for me. That's safe, yeah? If so, doesn't MVC rock? :)

like image 77
misterspaceman Avatar answered Nov 15 '22 11:11

misterspaceman


You are using a ChildAction because you are specifying @Html.Action("ContactForm", "ContactSurface") and because of this, in your View you need to:

  • Use Html.BeginForm(...) and not 'Html.BeginUmbracoForm(...)'
  • Allow the form to post back to the same path and not to the action

If you do this, then the form will post back to itself as expected.

See the documentation here for further help.

Edit:

Just saw the final part to your question. If you intend SayOK to be your 'thank you' message, I would just call it from your HttpPost action instead of returning the initial view.

like image 45
Digbyswift Avatar answered Nov 15 '22 10:11

Digbyswift