Кнопки удаленного атрибута MVC3 и множественной отправки

#asp.net-mvc-3

#asp.net-mvc-3

Вопрос:

Я обнаружил то, что кажется ошибкой при использовании MVC 3 с RemoteAttibute и ActionNameSelectorAttribute.

Я внедрил решение для поддержки нескольких кнопок отправки в одном представлении, аналогичное этому сообщению:http://blog.ashmind.com/2010/03/15/multiple-submit-buttons-with-asp-net-mvc-final-solution

Решение работает, однако, когда я ввожу RemoteAttribute в свою модель, ControllerContext.RequestContext.HttpContext.Request больше не содержит ни одной из моих кнопок отправки, что приводит к сбою решения «multi-submit-button».

Кто-нибудь еще сталкивался с подобным сценарием?

Ответ №1:

Я знаю, что это не прямой ответ на ваш вопрос, но я бы предложил альтернативное решение для нескольких кнопок отправки, используя вместо этого клиентский jQuery и markup:

Javascript

 <script type="text/javascript">
    $(document).ready(function () {
        $("input[type=submit][data-action]").click(function (e) {
            var $this = $(this);
            var form = $this.parents("form");
            var action = $this.attr('data-action');
            var controller = $this.attr('data-controller');
            form.attr('action', "/"   controller   "/"   action);
            form.submit();
            e.preventDefault();
        });
    });
</script>
  

HTML

 @using (Html.BeginForm())
{    
    <input type="text" name="name" id="name" />

    <input type="submit" value="Save draft" data-action="SaveDraft" data-controller="Home" />
    <input type="submit" value="Publish" data-action="Publish" data-controller="Home" />
}
  

Это может быть не так элегантно, как кодовое решение, но оно предлагает несколько меньше хлопот, поскольку единственное, что на самом деле меняется, — это атрибут действия формы при нажатии кнопки отправки.

По сути, что это делает, так это то, что всякий раз, когда нажимается кнопка отправки с набором атрибутов data-action, она заменяет атрибут действия родительской формы комбинацией атрибутов data-controller и data-action на нажатой кнопке, а затем запускает событие отправки формы.

Конечно, этот конкретный пример не является универсальным, и он всегда будет создавать URL-адрес / Controller / Action, но это можно легко расширить с помощью дополнительной логики в click-action.

Просто совет 🙂

Комментарии:

1. Спасибо за предложение, но мне нужно поддерживать отключенные браузеры javascript. Я разработал решение, которое вскоре опубликую.

Ответ №2:

я не уверен, что это ошибка в mvc 3, поскольку это не то, что вы ожидали. RemoteAttribute заставляет javascript перехватывать и проверять форму с помощью ajax post. для этого публикация формы, вероятно, отменяется, и когда проверка завершена, событие отправки формы, вероятно, вызывается напрямую, а не с использованием фактически нажатой кнопки. я вижу, где это было бы проблематично в вашем сценарии, но это имеет смысл. мое предложение: либо не используйте RemoteAttribute и не проверяйте вещи самостоятельно, либо не выполняйте несколько действий с формой.

Комментарии:

1. Спасибо за сообщение, Натан. Я слышу, что ты говоришь. Я думаю, мне придется самому «имитировать» RemoteAttribute с помощью ajax. К сожалению, в форме есть несколько кнопок — чего я не могу избежать.

Ответ №3:

Проблема проявляется, когда атрибут RemoteAttribute используется в модели в представлении, где используются кнопки множественной отправки. Независимо от того, какое «многокнопочное» решение вы используете, сообщение больше не содержит никаких входных данных для отправки.

Мне удалось решить проблему с помощью нескольких настроек атрибута ActionMethod selectorattribute и добавления скрытого поля просмотра и некоторого javascript, чтобы помочь соединить элементы.

ViewModel

 public class NomineeViewModel
    {
        [Remote("UserAlreadyRegistered", "Nominee", AdditionalFields="Version", ErrorMessage="This Username is already registered with the agency.")]
        public string UserName { get; set; }

        public int Version {get; set;}
        public string SubmitButtonName{ get; set; }
    }
  

ActionMethod selectorattribute

 public class OnlyIfPostedFromButtonAttribute : ActionMethodSelectorAttribute
    {
        public String SubmitButton { get; set; }
        public String ViewModelSubmitButton { get; set; }

        public override Boolean IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            var buttonName = controllerContext.HttpContext.Request[SubmitButton];
            if (buttonName == null)
            {
                //This is neccessary to support the RemoteAttribute that appears to intercepted the form post
                //and removes the submit button from the Request (normally detected in the code above)
                var viewModelSubmitButton = controllerContext.HttpContext.Request[ViewModelSubmitButton];
                if ((viewModelSubmitButton == null) || (viewModelSubmitButton != SubmitButton))
                    return false;
            }

            // Modify the requested action to the name of the method the attribute is attached to
            controllerContext.RouteData.Values["action"] = methodInfo.Name;
            return true;
        }
    }
  

Вид

 <script type="text/javascript" language="javascript">
    $(function () {
        $("input[type=submit][data-action]").click(function (e) {
            var action = $(this).attr('data-action');
            $("#SubmitButtonName").val(action);
        });
    });
</script>

    <% using (Html.BeginForm())
       {%>
        <p>
            <%= Html.LabelFor(m => m.UserName)%>
            <%= Html.DisplayFor(m => m.UserName)%>
        </p>

        <input type="submit" name="editNominee" value="Edit" data-action="editNominee" />
        <input type="submit" name="sendActivationEmail" value="SendActivationEmail" data-action="sendActivationEmail" />
        <%=Html.HiddenFor(m=>m.SubmitButtonName) %>
<% } %>
  

Контроллер

 [AcceptVerbs(HttpVerbs.Post)]
[ActionName("Details")]
[OnlyIfPostedFromButton(SubmitButton = "editNominee", ViewModelSubmitButton = "SubmitButtonName")]
public ActionResult DetailsEditNominee(NomineeViewModel nom)
{
    return RedirectToAction("Edit", "Nominee", new { id = nom.UserName });
}

[AcceptVerbs(HttpVerbs.Post)]
[ActionName("Details")]
[OnlyIfPostedFromButton(SubmitButton = "sendActivationEmail", ViewModelSubmitButton = "SubmitButtonName")]
public ActionResult DetailsSendActivationEmail(NomineeViewModel nom)
{
    return RedirectToAction("SendActivationEmail", "Nominee", new { id = nom.UserName });
}

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public ActionResult UserAlreadyRegistered(string UserName, int Version)
{
    //Only validate this property for new records (i.e. Version != zero)
    return Version != 0 ? Json(true, JsonRequestBehavior.AllowGet) 
                              : Json(! nomineeService.UserNameAlreadyRegistered(CurrentLogonDetails.TaxAgentId, UserName), JsonRequestBehavior.AllowGet);
}
  

Ответ №4:

Я столкнулся с той же проблемой.

Я также прикрепил событие отправки для подготовки формы перед отправкой. Интересно, что когда я вставляю точку останова в функцию on submit, а затем продолжаю, проблема исчезает.

В итоге я получил Ajax-форму, удалив удаленный атрибут и подтвердив поле с помощью ModelState.