2013-02-05 15 views
7

Mam model widoku, który zawiera powtarzające się elementy. Umieszczam je w moim widoku za pomocą metody EditorFor().MVC4 jak dynamicznie dodać element zamówienia do pola EditorFor?

Widok:

@model Models.MyModel 

@using (Html.BeginForm(@Model.Action, @Model.Controller)) 
{ 
    <div class="section" id="Terms"> 
     @Html.EditorFor(m => m.Terms) 
    </div> 

    <input type="submit" value="Save" /> 
} 

Model:

public class MyModel 
{ 
    public IEnumerable<Term> Terms { get; set; } 
} 

EditorTemplates \ Term.cshtml:

@model Models.Term 

@if (Model != null) 
{ 
    <fieldset> 
     <legend>Term</legend> 

     @Html.HiddenFor(model => model.TermID) 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.Identifier) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Identifier) 
      @Html.ValidationMessageFor(model => model.Identifier) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.Description) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Description) 
      @Html.ValidationMessageFor(model => model.Description) 
     </div> 

    </fieldset> 
} 

Chcę b e stanie dynamicznie dodawać/usuwać elementy z listy w widoku, jak tego przykład knockout.js, ale jak mam zachować AUTO-ID w MVC tworzy ??:

http://knockoutjs.com/examples/cartEditor.html

Oto moje wymagania dla tego:

  • dodawać nowe terminy
  • Usuń terminy
  • zatwierdzić nowe widoki terminów, które są dodawane

Czytałem inne pytania na temat SO i nie znalazłem realnej odpowiedzi w tej sprawie. Czy knockout.js to przyjęty sposób na zrobienie tego? Czy są jakieś przykłady robienia tego z Knockout AND MVC?

Dzięki!

Odpowiedz

0

Chcesz knockout MVC http://knockoutmvc.com/CartEditor

Nie trzeba używać nokaut za to, czego naprawdę potrzebujesz, to javascript z walidacji i tworzenie/usuwanie działań, które mapy na spokojny działań kontrolera na stronie MVC rzeczy. W jaki sposób wdrażasz to, co należy do Ciebie. Knockout ułatwia jednak.

+0

widzę jak to działa jednak tak naprawdę nie pokazuje, jak używać go z EditorFor(). Czy nie muszę już go używać? Ten przykład nie pokazuje go w ramach metody BeginForm() i post, czy model jest poprawnie powiązany? –

0

trzeba zrobić następujące:

  1. Wyślij model kontrolera i renderowania jeden edytowalne pole do wyrażenia.
  2. Możesz poprosić użytkownika o przesłanie go lub kliknij przycisk dodaj, aby dodać więcej terminów.
  3. Jeśli użytkownik kliknie przycisk Dodaj, utwórz kopię istniejących pól i opróżnij je lub cokolwiek, aby można było utworzyć nowe.
  4. Gdy użytkownik prześle go, odeśle go do działania, które akceptuje tablicę terminów i dodaje ją do bazy danych lub nie. Lub możesz użyć ajaxa jak w powyższym przykładzie lub z this example możesz zobaczyć, co wysyła do serwera to obiekt tablicy json, a nie formularz z nazwanymi elementami.
  5. Możesz przetwarzać je w miarę ich tworzenia lub przetwarzać po przesłaniu.

Zależy od aplikacji, więc nokaut pomaga tylko klientowi w kroku 3, w którym tworzysz nową ze starej kopii. Możesz również pozwać szablony JQuery i json2, aby serializować ze starszą obsługą przeglądarki.

Wszystko, co musisz wiedzieć, to to, że gdy jesteś na kliencie, wysłałeś tu swój model, więc nie martw się o stronę serwera. Niezależnie od tego, co budujesz po stronie klienta, możesz wysłać jeden model naraz do akcji saveTerm, która retrsuje json z określeniem id i innymi informacjami, lub możesz zwrócić kolekcję saveTerm jako tablicę json i będzie działała dobrze.

Jeśli myślisz o wysłaniu tablicy na postBack, a nie ajax, po prostu zachowaj nazwy elementów formularza tak samo i zduplikuj pola wprowadzania terminów i wyślij. MVC zamapuje je na tablicę terminów, podobnie jak w przypadku json.

1

Znalazłem ten post Nested Collection Models in MVC3 przez Jarretta Meyera, który ma rozwiązanie, które nie korzysta z nokautu i maksymalizuje ponowne użycie kodu.

Obejmuje to metody dodawania i usuwania. Opiszę tutaj metodę dodawania.

modelu

public class Person { 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public IList<PhoneNumber> PhoneNumbers { get; set; } 
    public IList<EmailAddress> EmailAddresses { get; set; } 
    public IList<Address> Addresses { get; set; } 
} 

Odwiedzin

//New.cshtml:  
@using (Html.BeginForm("New", "Person", FormMethod.Post)) 
{ 
    @Html.EditorForModel() 
    <p> 
    <button type="submit"> 
     Create Person 
    </button> 
    </p> 
} 

//Person.cshtml: 
@Html.AntiForgeryToken() 
@Html.HiddenFor(x => x.Id) 

<p> 
    <label>First Name</label> 
    @Html.TextBoxFor(x => x.FirstName) 
</p> 
<p> 
    <label>Last Name</label> 
    @Html.TextBoxFor(x => x.LastName) 
</p> 
<div id="phoneNumbers"> 
    @Html.EditorFor(x => x.PhoneNumbers) 
</div> 
<p> 
    @Html.LinkToAddNestedForm("Add Phone Number", "#phoneNumbers", ".phoneNumber", "PhoneNumbers", typeof(PhoneNumber)) 
</p> 

//PhoneNumber.cshtml: 
<div class="phoneNumber"> 
    <p> 
    <label>Telephone Number</label> 
    @Html.TextBoxFor(x => x.Number) 
    </p> 
    <br/> 
</div> 

Helper

/// <param name="linkText">Text for Link</param> 
/// <param name="containerElement">where this block will be inserted in the HTML using a jQuery append method</param> 
/// <param name="counterElement">name of the class inserting, used for counting the number of items on the form</param> 
/// <param name="collectionProperty">the prefix that needs to be added to the generated HTML elements</param> 
/// <param name="nestedType">The type of the class you're inserting</param> 
public static IHtmlString LinkToAddNestedForm<TModel>(this HtmlHelper<TModel> htmlHelper, string linkText, 
    string containerElement, string counterElement, string collectionProperty, Type nestedType) 
{ 
    var ticks = DateTime.UtcNow.Ticks; 
    var nestedObject = Activator.CreateInstance(nestedType); 
    var partial = htmlHelper.EditorFor(x => nestedObject).ToHtmlString().JsEncode(); 

    partial = partial.Replace("id=\\\"nestedObject", "id=\\\"" + collectionProperty + "_" + ticks + "_"); 
    partial = partial.Replace("name=\\\"nestedObject", "name=\\\"" + collectionProperty + "[" + ticks + "]"); 

    var js = string.Format("javascript:addNestedForm('{0}','{1}','{2}','{3}');return false;", containerElement, 
     counterElement, ticks, partial); 

    TagBuilder tb = new TagBuilder("a"); 
    tb.Attributes.Add("href", "#"); 
    tb.Attributes.Add("onclick", js); 
    tb.InnerHtml = linkText; 

    var tag = tb.ToString(TagRenderMode.Normal); 
    return MvcHtmlString.Create(tag); 
} 

private static string JsEncode(this string s) 
{ 
    if (string.IsNullOrEmpty(s)) return ""; 
    int i; 
    int len = s.Length; 

    StringBuilder sb = new StringBuilder(len + 4); 
    string t; 

    for (i = 0; i < len; i += 1) 
    { 
     char c = s[i]; 
     switch (c) 
     { 
      case '>': 
      case '"': 
      case '\\': 
       sb.Append('\\'); 
       sb.Append(c); 
       break; 
      case '\b': 
       sb.Append("\\b"); 
       break; 
      case '\t': 
       sb.Append("\\t"); 
       break; 
      case '\n': 
       //sb.Append("\\n"); 
       break; 
      case '\f': 
       sb.Append("\\f"); 
       break; 
      case '\r': 
       //sb.Append("\\r"); 
       break; 
      default: 
       if (c < ' ') 
       { 
        //t = "000" + Integer.toHexString(c); 
        string tmp = new string(c, 1); 
        t = "000" + int.Parse(tmp, System.Globalization.NumberStyles.HexNumber); 
        sb.Append("\\u" + t.Substring(t.Length - 4)); 
       } 
       else 
       { 
        sb.Append(c); 
       } 
       break; 
     } 
    } 
    return sb.ToString(); 
} 

JavaScript

//since the html helper can change the text of the item inserted but not the index, 
//this replaces the 'ticks' with the correct naming for the collection of properties 
function addNestedForm(container, counter, ticks, content) { 
    var nextIndex = $(counter).length; 
    var pattern = new RegExp(ticks, "gi"); 

    content = content.replace(pattern, nextIndex); 
    $(container).append(content); 
} 
+0

Dodanie zagnieżdżonego formularza jest wysoce zależne od posiadania unikalnej wartości właściwości "ticks", która może nie wystąpić na wolnym komputerze. Aby to zapewnić, możesz użyć GUID lub zrobić coś takiego: System.Threading.Thread.Sleep (1); długie takty = DateTime.UtcNow.Ticks; –

Powiązane problemy