1

I have a newsletter subscription form in a website I'm creating (it's part of the layout) and I'm using Html.Action() in my layout.cshtml file to call my Subscribe() action method. The method has 'two' versions: one for get and other for post requests.

Problem:

  • the Subscribe() POST action method gets called whenever any other form is submitted - I don't want that: it should only be called when someone clicks on the 'subscribe' button (then there's an ajax call to update the page without reloading)
  • For instance, in my contacts page, when I submit the form, the Subscribe() post method also gets called

I'm not sure why this happens but I believe it is because there's a post request and hence my Subscribe() POST method gets called automatically instead of the Subscribe() GET one.I tried using Html.Partial for this instead but it doesn't work because I have to pass a model to the partial view through the layout.cshtml file

_layout.cshtml:

// more code
 @Html.Action("Subscribe", "Newsletter", new { area = "" })
// mode code

NewsletterController:

public ActionResult Subscribe()    {
        NewsletterSubscribeVM model = new NewsletterSubscribeVM();
        return PartialView("NewsletterSubscription", model);
    }

/// always gets called, even when it shouldn't     
        [HttpPost, ValidateAntiForgeryToken]
        public ActionResult Subscribe(NewsletterSubscribeVM subscriber) {
            string message;
            if (!ModelState.IsValid) {
                message = "Ops! Something went wrong.";
                return Json(message, JsonRequestBehavior.AllowGet);
            }
            Newsletter sub = new Newsletter { Email = subscriber.SubscriberEmail };
            this._service.Add(sub);
            message = "Thank you for subscribing!";
            return Json(message, JsonRequestBehavior.AllowGet);
        }
    }

NewsletterSubscription.chtml

@model Web.ViewModels.NewsletterSubscribeVM

@using (Html.BeginForm("Subscribe", "Newsletter", new { area = "" }, FormMethod.Post, new { id = "newsletter-form", @class = "col-xs-12" })) {
    @Html.AntiForgeryToken()

    @Html.Label("Subcribe!", new { id = "newsletter-msg", @class = "col-xs-12 no-padding" })
    @Html.TextBoxFor(m => m.SubscriberEmail, new { placeholder = "Email", @class = "col-xs-7", id = "newsletter-box" })
    <button id="newsletter-btn" class="col-xs-1">
        <i class="fa fa-arrow-right absolute-both-centered" aria-hidden="true"></i>    </button>
}

Javascript:

$('#newsletter-btn').click(function (e) {
            var form = $('#newsletter-form');
            e.preventDefault();

            // if the user has inserted at least one character and the 'thank you' msg isn't showing yet:
            if ($('#newsletter-box').val().length != 0 && $('#subscription-status-msg').length == 0) {
                $.ajax({
                    method: "POST",
                    url: "/newsletter/subscribe",
                    data: form.serialize(),
                    dataType: "json",
                    success: function(data) {
                        $('<div id="subscription-status-msg" class="col-xs-12 no-padding">' + data + '</div>').appendTo($("#newsletter-form")).hide().fadeIn(500);
                    }
                })
            }
    })

Thanks in advance!

Acla
  • 141
  • 3
  • 12
  • Shwo us the view part. How you bind the button to this action. – CodeNotFound Apr 30 '17 at 18:36
  • It seems that you are not using a submit button but a simple button. I suppose you use javascript to reach you action method. What is the JS part? – CodeNotFound Apr 30 '17 at 18:48
  • Does the submit button make a difference? Yes, I'm using js to call the action method - added that part too – Acla Apr 30 '17 at 19:00
  • Your JS code seems to be correct. Yes submit will make a difference but it will reload the whole page. The actual code should work. Make sure there is no another handler for your button into your JS. – CodeNotFound Apr 30 '17 at 19:02
  • Nope..that code is the only one that handles the button. I actually tested the js file (added some alerts()) to make sure that the action wasn't being called from the js file. I believe it's being called just because I'm using Html.Action() which gets called automatically on page load. This situation does seem odd to me because it's such a common one..you use login and newsletter forms in your layout file all the time and I'm guessing people use Html.Action in those cases too so I don't get how they solve this problem. – Acla Apr 30 '17 at 19:07
  • the `Html.Action` does not call the Subscribe with POST method but the Suscribe action that has GET Method. If that is the issue you have then it is normal. The Get via `Html.Action` method only render the partial view. – CodeNotFound Apr 30 '17 at 19:10
  • Really? What if the page is being loaded because there was a POST request. Wouldn't it get called then? Because there's a POST version of the method..not just a GET one. I don't have issues when the GET version gets called because, like you said, it just renders the view; I have a problem because the POST one fires when it shouldn't and then an exception is thrown – Acla Apr 30 '17 at 19:14
  • 1
    Maybe you should remove the Html.BeginForm in your view. it is useless because you use Javascript to post the form. Check if that change may help – CodeNotFound Apr 30 '17 at 19:27
  • 1
    Ok, so after some digging around, I found a solution! I changed the name of the POST method so that, no matter the request type, Html.Action always calls the GET version. More details here: http://stackoverflow.com/questions/19299627/html-renderaction-uses-post-instead-of-get Thank you for your help :) – Acla Apr 30 '17 at 19:53

0 Answers0