How to return a single string to a div in my current page from HTTP POST in ASP.NET MVC 5?

1.6k views Asked by At

I'm trying to post a message after a contact form, indicating to the user that their message has been sent after they click the submit button. I don't want to redirect to a different page or to return a different view inside my HTTP Post action method. How do I do something like that in ASP.NET MVC framework?

Below is my code sample:

@*contactus.cshtml*@
            @model MySite.Models.ContactModel
            @using (Html.BeginForm())
            {
                <div class="col-md-6">
                    <div class="form-group">
                        @Html.TextBoxFor(model => model.Name})
                        <p>@Html.ValidationMessageFor(model => model.Name)</p>
                    </div>
                    <div class="form-group">
                        @Html.TextBoxFor(model => model.Email)
                        <p>@Html.ValidationMessageFor(model => model.Email)</p>
                    </div>
                    <div class="form-group">
                        @Html.TextAreaFor(model => model.Message)
                        <p>@Html.ValidationMessageFor(model => model.Message)</p>
                    </div>

                    <div class="col-lg-12">
                        <button type="submit">Send Message</button>
                    </div>
                </div>
            }

@*ContactModel.cs*@
public class ContactModel
{
    [Required(ErrorMessage = "* Please enter your name.")]
    [StringLength(100, MinimumLength=3, ErrorMessage="* Please enter your full name.")]
    public string Name { get; set; }

    [Required]
    [EmailAddress(ErrorMessage="* Not a valid email address.")]
    public string Email { get; set; }

    [Required]
    public string Message { get; set; }
}

I only have a contact us form right now on my home/index page, and I don't want to redirect it to any other pages. I would like to display a message right below the Send Message button, but I'm not sure how to go about it using the action method below:

@*HomeController.cs*@
    public ActionResult Index(ContactModel model)
    {
        if (ModelState.IsValid)
        {
            // this is my helper library, for brevity, I'm not copying it.
            EmailHelper emailService = new EmailHelper(); 
            bool success = emailService.SendEmail(model.Name, model.Email, model.Message);
            return Content(success ? "success" : "no...something went wrong :(");
        } else {
            return View(model);
        }
    }

Right now this controller will return the string inside Content which replaces my entire page, and I would like the string to be returned below my contact form. Also, I have two sections on the same html page with Contact Form as the second one, when I return View(model), it automatically redirects to the first section, which isn't ideal... How do I tell the controller to only redirect it to the second section after the POST method? In addition, I feel like it would be more efficient if it didn't return the whole page... so is there a way to only return a Message string to the div?

2

There are 2 answers

8
wicker95 On BEST ANSWER

You can place a hidden div on the page which will contain the message.

Then when your form has been submitted, capture the click event for your button, and use that to display the hidden message.

Let me know if you need a code example. Posting your form would help us answer you more specifically.

9
IamzombieGrrArgh On

To only show the success message if the form is successfully sent, I would recommend setting a value in the ViewBag in the POST action of the controller and then returning that same page if you want to still have the same page showing. On the View itself, you could then place an If statement to test if the ViewBag variable contains a value and if so, display the message.

Controller:

[HttpPost]
public ActionResult YourAction(YourModel m)
{
    //Do stuff to send the contact form
    ...
    if(error)
    {
        ViewBag.Message = "There was a problem sending the form.";
    }
    else
    {
        ViewBag.Message = "The form was sent successfully!";
    }
    return View(m);
}

View:

@if(ViewBag.Message != null)
{
    <div>@ViewBag.Message</div>
}

This lets you check if the form was posted successfully on the server before telling the user the result and will only display a message if ViewBag.Message has been set. Note that you can have as many ViewBag variables as you want and can name them whatever you want... just remember which one you use in which place.

EDIT:

Following the comments, this could also be done using an AJAX call. I'll use the jQuery .post() method for simplicity sake.

In Script:

<script>
    $(document).on('click', "#buttonId", function() {
        var nameText = $("#IdOfNameField").val();
        var emailText = $("#IdOfEmailField").val();
        var messageText = $("#IdOfMessageField").val();
        $.post('@Url.Content("~/Controller/AJAXPostContactForm")',//the url to post to
            {name: nameText, email: emailText, message: messageText }, //these are values to be sent to the action
            function(){ //this is the success function
                $("#successMessage").val("Form posted successfully.");
            }
        )
        .fail(function() {//failure function
            alert("Something went wrong.");
        });
    }
</script>

Controller:

public void AJAXPostContactForm(string name, string email, string message)
{
    try
    {
        //do stuff with the information passed into the action
    }
    catch(exception e)
    {
        //Handle errors. If error thrown, Ajax should hit fail block in script
    }
    finally
    {
        //do any cleanup actions
    }
}

View:

<div id="successMessage"></div>

I have not tested this code but it should theoretically work. On a specific button click, it will get the values from the form fields, post those values to a specialized ActionResult in the controller, and then return a message about what happened.