MVC3 Сохраняются только опубликованные значения формы? - PullRequest
0 голосов
/ 16 мая 2011

Я использую строго типизированные представления в веб-приложении MVC3.Я заметил, что когда форма отправляется, ViewModel, который передается в контроллер, имеет значения только для свойств, с которыми связаны элементы формы.Например, в приведенном ниже примере показан простой вид подтверждения с флажком и номером телефона, который пользователь должен подтвердить перед продолжением.Когда форма передается в действие контроллера, свойство UserConfirmed содержит значение, но свойство PhoneNumber имеет значение null.

Есть ли способ, чтобы ViewModel сохранил все свои значения, или мне нужно заново заполнить свойства ViewModel, у которых нет связанных с ними элементов формы?1006 *

Контроллер

[HttpPost]
public ActionResult ScheduleConfirmation(ScheduleConfirmationViewModel model)
{
if (model.UserConfirmed)
{
    // add ViewModel data to repository
}
else
{
    ModelState.AddModelError("ERROR", WebResources.strERROR_ConfirmSchedule);
}

return View(model);
}

Ответы [ 5 ]

1 голос
/ 16 мая 2011

После того, как вы записали номер телефона в качестве вывода на страницу, он не будет автоматически отправлен обратно (вы узнали эту часть). Что вы можете сделать, это заполнить скрытое поле или поле только для чтения с номером телефона, чтобы онбыть отправлены обратно на ваш контроллер.Второй вариант - сделать новый вызов вашего источника данных и заново заполнить ваш объект, прежде чем сохранить его обратно в ваш источник данных.

1 голос
/ 11 ноября 2011

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

В вашем случае это так же просто, как

@model WebMeterReplacement.ViewModels.Appointment.ScheduleConfirmationViewModel
@using (Html.BeginForm()) {
@Html.ValidationSummary(false)

@Html.CheckBoxFor(model => model.UserConfirmed) 
<span>Please confirm before proceeding</span>
<div>
    @Html.HiddenFor(m => m.PhoneNumber)
    Phone Number: @Model.PhoneNumber
</div>
<input type="submit" value="Confirm"/>

Дляссылка на будущее:

Если вы возвращаете сложные объекты обратно, вам нужно одно скрытое поле для каждого атрибута (Hiddenfor НЕ выполняет итерацию)

Просмотр

WRONG
@Html.HiddenFor(m => m.PagingData)

RIGHT
@Html.HiddenFor(m => m.PagingData.Count)
@Html.HiddenFor(m => m.PagingData.Skip)
@Html.HiddenFor(m => m.PagingData.PageSize)

Действие

public HomeController(AViewModel Model)
{
   PagingData PagingData = Model.PagingData;
   Skip = PagingData.Skip;
}

Если вы передаете Массивы, вы можете сделать это следующим образом

Просмотр

@if (Model.HiddenFields != null)
{   
foreach (string HiddenField in Model.HiddenFields)
{
    @Html.Hidden("HiddenFields", HiddenField)    
}
}

Действие

public HomeController(AViewModel Model)
{
    String[] HiddenFields = Model.HiddenFields;
}
0 голосов
/ 11 декабря 2013

Да, просто поместите скрытые поля в форму для тех значений, которые вы не используете и хотите вернуть к управлению сервером.Спасибо

0 голосов
/ 23 февраля 2012

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

Я нахожусь в аналогичной ситуации, когда мои объекты передаются в представление, и представление может отображать только часть этого объекта для редактирования. Очевидно, что когда контроллер получает модель обратно из подшивки модели по умолчанию, а значения, не отправленные обратно, становятся нулевыми ... и сохранение этого означает, что значение БД становится нулевым только потому, что оно не отображалось / не возвращалось из представления.

Мне не понравилась идея создания модели для каждого вида. Я знаю, что это, вероятно, правильный способ ... но я искал шаблон многократного использования, который можно было бы реализовать довольно быстро. См. Метод «MergeWith» ... так как он будет использован для получения копии объекта из базы данных и объединения ее с копией, возвращенной из представления (отправлено обратно)

    namespace SIP.Models
{
    [Table("agents")]
    public class Agent
    {
        [Key]
        public int id { get; set; }

        [Searchable]
        [DisplayName("Name")]
        [Column("name")]
        [Required]
        [StringLength(50, MinimumLength = 4)]
        public string AgentName { get; set; }

        [Searchable]
        [DisplayName("Address")]
        [Column("address")]
        [DataType(DataType.MultilineText)]
        public string Address { get; set; }


        [DisplayName("Region")]
        [Searchable]
        [Column("region")]
        [StringLength(50, MinimumLength = 3)]
        public string Region { get; set; }


        [DisplayName("Phone")]
        [Column("phone")]
        [StringLength(50, MinimumLength = 4)]
        public string Phone { get; set; }

        [DisplayName("Fax")]
        [Column("fax")]
        [StringLength(50, MinimumLength = 4)]
        public string Fax { get; set; }


        [DisplayName("Email")]
        [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
        [Column("email")]
        [StringLength(50, MinimumLength = 4)]
        public string Email { get; set; }


        [DisplayName("Notes")]
        [Column("notes")]
        [DataType(DataType.MultilineText)]
        public string Notes{ get; set; }

        [DisplayName("Active")]
        [Column("active")]
        public bool Active { get; set; }


        public override string ToString()
        {
            return AgentName;
        }

        public bool MergeWith(Agent a, string[] fields)
        {
            try
            {
                foreach (PropertyInfo pi in this.GetType().GetProperties())
                {
                    foreach (string f in fields)
                    {
                        if (pi.Name == f && pi.Name.ToLower() != "id")
                        {
                            var newVal = a.GetType().GetProperty(f).GetValue(a,null);
                            pi.SetValue(this, newVal, null);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                return false;
                //todo: Log output to file...
            }

            return true;
        }
    }
}

И чтобы использовать это в контроллере .. у вас будет что-то вроде ..

 [HttpPost]
    public ActionResult Edit(Agent agent)
    {


        if (ModelState.IsValid)
        {
            Agent ag = db.Agents.Where(a => a.id == agent.id).ToList<Agent>().First<Agent>();
            ag.MergeWith(agent, Request.Params.AllKeys);

            db.Entry(ag).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(agent);
    }

Таким образом, во время обратной отправки он берет объект из базы данных и обновляет его, используя объект из поля зрения ..., но обновляет только те значения, которые были отправлены обратно. Так что если у вас есть поле типа "адрес" или что-то, что не появляется в представлении .. это не затрагивается во время обновления.

Я проверял это до сих пор, и я работаю для своих целей, поэтому я приветствую любые отзывы, так как я стремлюсь увидеть, как другие преодолели эту ситуацию. Это первая версия, и я уверен, что ее можно реализовать лучше, например, с помощью метода расширения или чего-то еще ... но сейчас MergeWith можно копировать / вставлять в каждый объект модели.

0 голосов
/ 16 мая 2011

Хорошо, форма будет содержать только те элементы POST, которые вы создали. Как вы узнали, простой записи номера телефона на странице будет недостаточно. Связыватель модели может связывать только те свойства, которые существуют в проведенных данных.

Обычно у вас есть несколько вариантов здесь:

1) Вы можете создавать элементы ввода для всех свойств вашей модели, используя видимые элементы (например, текстовое поле) для тех свойств, которые вы хотите редактировать, и скрытые элементы, которые должны быть опубликованы, но не имеют пользовательского интерфейса

2) Отправьте обратно частичное представление вашей модели (как вы делаете сейчас), прочитайте сущность обратно из ее источника данных (я предполагаю, что вы используете какой-то источник данных, возможно, EF), а затем измените свойства этой сущности со свойствами вашей формы.

Оба сценария являются общими, но это действительно зависит от сложности вашей модели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...