Basic Umbraco 6.1.1 SurfaceController Questions
Asked Answered
G

2

6

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.

Guillemot answered 8/7, 2013 at 17:31 Comment(0)
G
3

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? :)

Guillemot answered 17/7, 2013 at 5:27 Comment(1)
I think this answer has a lot of problems. Here are some links that explain how to add forms to macros: our.umbraco.org/documentation/reference/Templating/Mvc/forms ... and more specifically towards the end of this page: proworks.com/blog/2013/02/22/…Foreshadow
M
1

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.

Magnetize answered 9/7, 2013 at 12:18 Comment(4)
Thanks for your help. When is it appropriate to use Html.BeginUmbracoForm(...)? Should I use @Html.RenderPartial() instead?Guillemot
You could use Html.BeginUmbracoForm in the case you have described in your question, you just have to understand why you would want to. There are several permutations of what can be used, it's just a matter of understanding what each one will result in and what the limitations are of each. I would seriously suggest reading the documentation as they give and example of each method.Magnetize
Ok, re-reading the documentation helped. I'm able to get their example code to work, when I embed the Razor code inside of a template. However, I'd ultimately like to wrap the form inside of a macro, so it can eventually be dropped into the content section of my page. Is that possible? I tried creating a Partial View Macro file, adapting the code from that documentation example:Guillemot
@Html.Partial("~/Views/Partials/BlogCommentForm.cshtml", new CommentViewModel()). When I do that, the form renders, but the postback does nothing.Guillemot

© 2022 - 2024 — McMap. All rights reserved.