none
Как добавить теги id и name в @Html.EditorFor и ему подобных RRS feed

  • Вопрос

  • Коллеги!

    Помогите разобраться, пожалуйста :)

    ASP.NET MVC 3 Razor

    В представлении есть код:

    <div class="editor-label">
        @Html.LabelFor(model => model.Number)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Number, new { id = Model.Id })
        @Html.ValidationMessageFor(model => model.Number)
    </div>
    

    однако на выводе генерится следующая размета:

    <div class="editor-label">
        <label for="Number">Номер</label>
    </div>
    <div class="editor-field">
         <input class="text-box single-line" data-val="true" data-val-required="The Номер field is required." id="Number" name="Number" type="text" value="Во-5/11" />
         <span class="field-validation-valid" data-valmsg-for="Number" data-valmsg-replace="true"></span>
    </div>
    
    
    Думаю вопрос очевидный: Почему при выводе указывается id="Number", а не подставляется значение Model.Id?

    23 октября 2011 г. 17:31

Ответы

  • Одинаковые Id это некорректно, но привязка модели работает по Name. У вас сейчас name="item.Qty" , а должно быть Order.Product.Qty. Тогда в контроллере вы получите Order с заполненными полями каждого Product. Привязка модели выполняется с помощью рефлексии имяОбъекта.имяСвойства.имяПодсвойства и т.д в случае сложных типов.

     

    Такая разметка сформируется автоматически, если вы сделаете EditorTemplate для Product и Order и напишете в нем EditorFor для каждого нужного свойства. 

     

    • Помечено в качестве ответа MrSena 26 октября 2011 г. 7:06
    25 октября 2011 г. 14:07

Все ответы

  • Вызов @Html.EditorFor(model => model.Number, new { id = Model.Id }) не означает, что аттрибуту "id" будет поставлено указанное значение.

    Это означает, что во ViewData будет добавлена пара ключ/значение "Id" : Model.Id

    Воспользоваться этим вы сможете только если сами указали EditorTemplate для данного свойства модели. Тогда в нем вы сможете обратиться в коде разметки к указанному значению,  напр.

     

    <div id="@ViewData["id"]"></div>

     


     http://msdn.microsoft.com/ru-ru/library/ff406462.aspx

    24 октября 2011 г. 6:50
  • Тобишь стандартным способом указать теги id и name невозможно и нужно переопределять EditorTemplate для каждого типа?
    24 октября 2011 г. 9:04
  • Тобишь стандартным способом указать теги id и name невозможно и нужно переопределять EditorTemplate для каждого типа?

    Честно говоря, не уверен, что невозможно, но я по другому не умею.)

    А какая задача решается? Может есть более простой подход? Чем вас не устраивает стандартная реализация - когда аттрибут Id равен имени свойства модели? Во всяком случае, аттрибут Name точно не стоит менять - потом при отправке формы нарушится механизм привязки данных модели, который как раз и основан на именах.

    24 октября 2011 г. 10:06
  • Задача простая - создать форму редактирования списка. При этом все элементы списка должны редактироваться в одной форме.

    При стандартной реализации получаються элементы с одинаковыми id и name. Соответсвенно, список в контроллер коректно не возвращается, а сообщения валидации не могут быть привязаны к каждой строке отдельно.

    24 октября 2011 г. 11:37
  • список в контроллер коректно не возвращается, а сообщения валидации не могут быть привязаны к каждой строке отдельно.

    Список должен возвращаться нормально в случае простых типов. Если у вас в форме набор элементов <input name="myCollection">, то в Action контроллера после отправки формы вы получите объект Ienumerable<>  myCollection.

    В случае привязки коллекции сложных типов, в foreach внутри формы их надо записывать не отдельными EditorFor для каждого свойства, а EditorFor(m => m) - т.е для типа коллекции. Для этого может понадобиться написать свой EditorTemplate. Вот в этой теме проблема объяснена - http://stackoverflow.com/questions/6523131/mvc3-submit-returning-null-on-my-complex-data-type.

    К тому же при использовании EditorTemplate вы сможете переопределить и другие аттрибуты, как я отвечал выше. 

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


    • Изменено J.W.Harding 24 октября 2011 г. 12:43
    24 октября 2011 г. 12:42
  • А есть ли где нибуть рабочий пример, где реализована возможность редактирования списка? Все мои эксперементы все равно возвращают в контроллер null.

     

    24 октября 2011 г. 19:28
  • Уважаемый пользователь, пожалуйста, не забудьте отметить сообщение или сообщения, которые являются решением вашей проблемы, даже если это ваше собстевенное сообщение. Это можно сделать с помощью кнопки 'Пометить как ответ', которая есть под каждым сообщением.

    Спасибо.


    Для связи [mail]
    25 октября 2011 г. 9:54
    Модератор
  • А есть ли где нибуть рабочий пример, где реализована возможность редактирования списка? Все мои эксперементы все равно возвращают в контроллер null.

     

    Вы приведите пример html-разметки формы и кода соответствующего действия контроллера.
    25 октября 2011 г. 12:23
  • Итак, есть шаблонный проект ASP.NET MVC 3
    Создал модель:
        public class Order
        {
            public Guid Id { get; set; }
            public string Number { get; set; }
    
            public virtual ICollection<Product> Products { get; set; }
        }
    
        public class Product
        {
            public Guid Id { get; set; }
            public string Name { get; set; }
            public int Qty { get; set; }
    
            public Guid OrderId { get; set; }
            public virtual Order Order { get; set; }
        }
    
    Далее создал контекст:
        public class TestMultiEditContext : DbContext
        {
            public DbSet<Order> Order { get; set; }
            public DbSet<Product> Product { get; set; }
        }
    

    Далее создал контроллер Edit:
            public ActionResult Edit(Guid id)
            {
                Order order = db.Order.Find(id);
                return View(order);
            }
    
            [HttpPost]
            public ActionResult Edit(Order order)
            {
                if (ModelState.IsValid)
                {
                    db.Entry(order).State = EntityState.Modified;
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
                return View(order);
            }
    
    

    Далее создал View:
    @model TestMultiEdit.Models.Order
    @{
        ViewBag.Title = "Edit";
    }
    <h2>
        Edit</h2>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    @using (Html.BeginForm())
    {
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>Order</legend>
            @Html.HiddenFor(model => model.Id)
            <div class="editor-label">
                @Html.LabelFor(model => model.Number)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Number)
                @Html.ValidationMessageFor(model => model.Number)
            </div>
            <fieldset>
            <legend>Products</legend>
            <table>
                <tr>
                    <th>
                        Name
                    </th>
                    <th>
                        Qty
                    </th>
                    <th>
                    </th>
                </tr>
                @foreach (TestMultiEdit.Models.Product item in Model.Products)
                {
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.Name)
                        </td>
                        <td>
                            @Html.EditorFor(modelItem => item.Qty)
                            @Html.ValidationMessageFor(modelItem => item.Qty)
                        </td>
                        <td>
                            @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                            @Html.ActionLink("Details", "Details", new { id = item.Id }) |
                            @Html.ActionLink("Delete", "Delete", new { id = item.Id })
                        </td>
                    </tr>
                }
                </table>
                </fieldset>
                <p>
                    <input type="submit" value="Save" />
                </p>
        </fieldset>
    }
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
    
    

    В итоге на выходе получаю такую разметку для табличной части:
    <tr>
        <td>
            Product 1
        </td>
        <td>
            <input class="text-box single-line" data-val="true" data-val-number="The field Qty must be a number."
                data-val-required="The Qty field is required." id="item_Qty" name="item.Qty"
                type="text" value="4" />
            <span class="field-validation-valid" data-valmsg-for="item.Qty" data-valmsg-replace="true">
            </span>
        </td>
        <td>
            <a href="/Order/Edit/1bf38793-8b7a-4183-b851-1cff36ddf497">Edit</a> | <a href="/Order/Details/1bf38793-8b7a-4183-b851-1cff36ddf497">
                Details</a> | <a href="/Order/Delete/1bf38793-8b7a-4183-b851-1cff36ddf497">Delete</a>
        </td>
    </tr>
    <tr>
        <td>
            Product 2
        </td>
        <td>
            <input class="text-box single-line" id="item_Qty" name="item.Qty" type="text" value="7" />
            <span class="field-validation-valid" data-valmsg-for="item.Qty" data-valmsg-replace="true">
            </span>
        </td>
        <td>
            <a href="/Order/Edit/d65cee49-d85f-4b55-9673-b744eb0e2f34">Edit</a> | <a href="/Order/Details/d65cee49-d85f-4b55-9673-b744eb0e2f34">
                Details</a> | <a href="/Order/Delete/d65cee49-d85f-4b55-9673-b744eb0e2f34">Delete</a>
        </td>
    </tr>
    
    

    На мой взгляд, этот код некоректный, поскольку теги <input> имеют одинаковые id и name.
    Соответсвенно, когда срабатывает контроллер, то там видим Products=null
    Подскажите, где найти пример реализации редактирования списка?
    25 октября 2011 г. 13:40
  • Одинаковые Id это некорректно, но привязка модели работает по Name. У вас сейчас name="item.Qty" , а должно быть Order.Product.Qty. Тогда в контроллере вы получите Order с заполненными полями каждого Product. Привязка модели выполняется с помощью рефлексии имяОбъекта.имяСвойства.имяПодсвойства и т.д в случае сложных типов.

     

    Такая разметка сформируется автоматически, если вы сделаете EditorTemplate для Product и Order и напишете в нем EditorFor для каждого нужного свойства. 

     

    • Помечено в качестве ответа MrSena 26 октября 2011 г. 7:06
    25 октября 2011 г. 14:07
  • Такая разметка сформируется автоматически, если вы сделаете EditorTemplate для Product и Order и напишете в нем EditorFor для каждого нужного свойства.  


    Огромное спасибо!

    На деле оказалось, что:

    1. Отдельный EditorTemplate для Order делать не нужно, нужно только для Product

    2. Не нужно создавать конструкцию foreach для элементов списка Product, а требуется просто указать @Html.EditorFor(model => model.Products)

    И тогда все работает правильно!

    Еще раз спасибо!

    26 октября 2011 г. 7:09