MVC 4 @ HTML.HiddenFor не обновляется после обратной передачи [дубликат]

18

У вас возникли проблемы с состоянием представления в серии просмотров страниц. На начальном этапе просмотра страницы в Razor я использую Html.HiddenFor следующим образом:

    @Html.HiddenFor(x => Model.err)
    @Html.HiddenFor(x => Model.errField)
    @Html.HiddenFor(x => Model.errMessage)
    @Html.HiddenFor(x => Model.IsMove)

, который работает нормально. Мои скрытые теги ввода содержат правильные значения. Однако, когда я отправляю форму [HTTPPost] и обновляю модель в своем действии контроллера с помощью.

       model.err = transHelper.err;
       model.errField = transHelper.errField;
       model.errMessage = transHelper.errMessage;
       return View(model);

Скрытые поля, похоже, не обновляются, они содержат исходные значения из исходного представления. Однако, когда я использую эти поля в другом контексте в том же виде бритвы, как это ...

     @*      
        this seems to not update correctly...

    @Html.HiddenFor(x => Model.err)
    @Html.HiddenFor(x => Model.errField)
    @Html.HiddenFor(x => Model.errMessage)
    @Html.HiddenFor(x => Model.IsMove)

        *@
        <input type="hidden" id="err" value="@Model.err" />
        <input type="hidden" id="errField" value="@Model.errField" />
        <input type="hidden" id="errMessage" value="@Model.errMessage" />
        <input type="hidden" id="IsMove" value="@Model.IsMove" />

    </div>

Затем поля ввода обновляются правильно. Я даже создал помощник вида, чтобы помочь отлаживать, и во всех случаях у модели, кажется, есть правильные данные в HtmlHelper<TModel> - я даже вернул модель как return Json(model); , и данные были точными.

На этом этапе я работаю с работой, но кто-нибудь знает, почему @Html.HiddenFor грязно.

Обновление: вот мои действия с контроллером

  [HttpPost]
   public ActionResult Index(HomePageModel model)
   {


       // process transaction
       Transactionr transr = new Transactionr();
       transr.Process(model);

       model.err = transr.err;
       model.errField = transr.errField;
       model.errMessage = transr.errMessage;

       return View(model);
   }

Вот мой взгляд:

        @model App.Models.HomePageModel
    @{
        ViewBag.Title = "Product Categorizer";
    }
    <form id="formData" method="post" action="/Home/Index">
        @Html.AntiForgeryToken()
        <fieldset>
            <div>

            @Html.HiddenFor(model => model.err)
            @Html.HiddenFor(model => model.errField)
            @Html.HiddenFor(model => model.errMessage)
            @Html.HiddenFor(model => model.IsMove)

            <input type="hidden" id="myerr" value="@Model.err" />
            <input type="hidden" id="myerrField" value="@Model.errField" />

            </div>

           <div class="section group">
                <div class="col span_2_of_2">
                     <div class="message" id ="message">
                         @if (Model.err < 0)
                         {
                             <span style="color: purple;">@Model.errMessage (@Model.err) - (@Model.errField)</span>
                         }
                         else if (Model.err > 0)
                         {
                             <span style="color:red;">@Model.errMessage (@Model.err) (@Model.errField)</span>
                         } else {
                            <span>@Model.errMessage (@Model.err) (@Model.errField)</span>
                         }
                         </div>
                     </div>
            </div>

            <div class="section group" id="workspace">
                  @Html.Partial("_WorkspacePartial", Model)
            </div>
              <div class="section group" id="details">
                  @Html.Partial("_DetailPartial", Model)
              </div>


        </fieldset>
        </form>

Вот моя модель:

 public class HomePageModel
 {
    public int FromStore { get; set; }

    //  the "To" part of the copy/move transaction
    public int ToStore { get; set; }

    // a list of the copy/move transaction
    public List<int> Details { get; set; }


    // true is move false is copy
    public bool IsMove { get; set; }

    // current message
    public int err { get; set; }
    public int errField { get; set; }
    public string errMessage { get; set; }
    
задан user799301 18.12.2013 в 13:03
источник

7 ответов

30

Поведение HtmlHelpers по умолчанию (@ Html.HiddenFor и т. д.) должно вести себя точно так, как вы описали.

то есть. любые изменения, которые вы делаете в ViewModel в сообщении, выполняются, любые изменения, которые вы возвращаете из Почты, принимаются в представлении, но при повторном рендеринге с помощью HTMLHELPERS предыдущие значения Post имеют приоритет над измененными значениями ViewModel.

Хотите «исправить» это поведение быстрым и грязным способом, очистите ModelState.Clear () перед возвратом из HttpPost ActionMethod!

    
ответ дан joedotnot 21.04.2014 в 17:40
  • Это очень грязно, потому что все сообщения о проверке также очищаются, поэтому имейте в виду! –  321X 15.06.2016 в 16:40
  • Я думал, что сойду с ума. –  agrath 25.09.2016 в 00:26
  • Я не понимаю. Нет атрибута Required для любых свойств модели. Зачем возвращать представление было получение HiddenFor пустым для свойства ONE? После выполнения ModelState.Clear я получил все правильно! –  Marc Roussel 25.12.2017 в 00:28
5

Как упоминалось joedotnot, это предполагаемое поведение. Другим «быстрым решением» для этого является кодирование html для скрытого поля и обновление только значения из модели, например:

<input type="hidden" id="ErrMessage" name="ErrMessage" value="@Model.ErrMessage">

Используйте те же id и name , что и ваше свойство модели, и обновленное значение будет отображаться после обратной передачи.

    
ответ дан maxscan 25.09.2014 в 11:21
4

Я столкнулся с подобной проблемой в последнее время и закончил тем, что написал новый простой хелперный метод + 2 перегрузки. Я разделяю его здесь, если кто-то все еще ищет какое-то обходное решение, потому что эта «функция» иногда раздражает.

public static class CustomExtensions
{
    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        string text = ExpressionHelper.GetExpressionText(expression);
        string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text);
        ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState;

        if (modelState.ContainsKey(fullName))
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            ValueProviderResult currentValue = modelState[fullName].Value;
            modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture);
        }
    }
}

Затем вы просто используете его как обычно изнутри:

@Html.HiddenFor2(m => m.Id)

Стоит упомянуть, что он также работает с коллекциями.

    
ответ дан Ruslan Georgievskiy 03.10.2014 в 16:49
3

Я думаю, вы должны использовать их вот так:

@Html.HiddenFor(x => x.Err)
@Html.HiddenFor(x => x.ErrField)
@Html.HiddenFor(x => x.ErrMessage)
@Html.HiddenFor(x => x.IsMove)

Не видя свою модель, я предполагаю, что она выглядит примерно так:

public class ErroViewModel
{
  public string Err { get; set; }
  public string ErrField { get; set; }
  public string ErrMessage { get; set; }
  public bool IsMove { get; set; }
}

Если это не должно быть похоже на общедоступные свойства, как указано выше.

Обновление

У вас есть следующее:

public ActionResult Index(HomePageModel model)
{
   var model = new HomePageModel();
   return View(model);
}

Я бы тоже изменил вашу форму:

 <form id="formData" method="post" action="/Home/Index">

Для этого:

@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
  // rest of form
}
    
ответ дан hutchonoid 18.12.2013 в 13:49
  • Моя модель использует общедоступные свойства. Что касается выражения, я пробовал все, включая то, что вы предлагаете, и это, похоже, не влияет. –  user799301 18.12.2013 в 14:25
  • У вас есть ссылка @model в верхней части вашего представления? Можете ли вы обновить вопрос с помощью полных действий, и я могу взглянуть? –  hutchonoid 18.12.2013 в 14:46
  • Чтобы ответить на ваш вопрос, да, у меня есть ссылка @model. Я также обновил вопрос с помощью полного действия, модели и представления –  user799301 18.12.2013 в 17:05
  • Я добавил дополнительную информацию, пожалуйста, примите, если она сработает для вас. :) –  hutchonoid 18.12.2013 в 17:13
  • Да, в моем get я создаю экземпляр HomePageModel .. как для формы. Я делаю манипуляции с формой jquery, поэтому я закодировал ее так. –  user799301 19.12.2013 в 23:12
Показать остальные комментарии
1

Вы можете попробовать

<input type="hidden" id="SomeFieldID" name="SomeFieldID" value="@Model.SomeFieldID" />
    
ответ дан Sumit Kapadia 06.03.2016 в 13:08
0

У меня была аналогичная проблема и она была решена так.

@Html.TextBoxFor(m => m.Email, new { onclick = "this.select()", Value = Model.Email, Placeholder = "E-Mail" })
    
ответ дан Rune Antonsen 27.11.2015 в 12:49
-1

Вам нужен ключ в вашей модели просмотра. Если у вас нет какого-либо свойства с именем Id в вашей модели просмотра, установите один из них (который должен быть uniqe identifiyer) в качестве ключа с [Key].

[Key]
Myproperty {get;set;}
    
ответ дан Ilker Ozan Koc 14.11.2015 в 15:57