0%

【MVC】EditorTemplate (二) 動態新增欄位

此篇範例程式 : 下載  (此範例在DynamicController之中)

呈上一篇,EditorTemplate (一) 我們可以來看到產生的原始碼如下

Name的部分是由 productList[index].屬性名組成,換句話說,如果今天要由前端動態新增一筆書籍資料,則必須按照這個規則編排下去,後端才能透過ViewModel的方式取得書籍資料

看起來一切美好圓滿,但如果今天的列表是可以新增之外,還要能動態刪除呢?
是不是我的[index]就要一直重新計算,不然送到後端就會不見了

*如果今天有4個textbox但是name分別是
productList[0].id
productList[1].id
productList[2].id
productList[5].id
這樣後端只會拿到0~2的ID,不按照順序編排的就會消失

還好.NET其實提供另外一種方式來繫結ViewModel

1
2
3
<input type="hidden" name="productList.Index" value="0072b890-0e1a-4c93-a5a7-9cafe84b65f8" /> 
<input id="productList_0072b890-0e1a-4c93-a5a7-9cafe84b65f8__id" name="productList[0072b890-0e1a-4c93-a5a7-9cafe84b65f8].id" type="text" >

這樣的話就可以不用管排序,自由的新增刪除List的項目,但EditorTemplate也需要改一改,不然EditTemplate產出的是[0]這種格是,但是前端產出的格是是[Guid],這樣會有問題。

所以EditTemplate改成用這個方法產出
*以下程式碼轉載自:  
搞搞就懂 - 點部落 :[ASP Net MVC] 如何綁定可動態新增或移除之資料集合(EditorTemplate)

  • 新增一組HtmlHelper ```csharp
    public static MvcHtmlString EditorForMany<TModel, TValue>(

          this HtmlHelper<TModel> html,
          Expression<Func<TModel, IEnumerable<TValue>>> expression,
          string htmlFieldName = null) where TModel : class
      {
          var items = expression.Compile()(html.ViewData.Model);
          var sb = new StringBuilder();
          var hasPrefix = false;
    
              if (String.IsNullOrEmpty(htmlFieldName))
          {
              var prefix = html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
              hasPrefix = !String.IsNullOrEmpty(prefix);
              htmlFieldName = (prefix.Length > 0 ? (prefix + ".") : String.Empty) + ExpressionHelper.GetExpressionText(expression);
          }
    
              if (items != null)
          {
              foreach (var item in items)
              {
                  var dummy = new { Item = item };
                  var guid = Guid.NewGuid().ToString();
    
                      var memberExp = Expression.MakeMemberAccess(Expression.Constant(dummy), dummy.GetType().GetProperty("Item"));
                  var singleItemExp = Expression.Lambda<Func<TModel, TValue>>(memberExp, expression.Parameters);
    
                      sb.Append(String.Format(@"<input type=""hidden"" name=""{0}.Index"" value=""{1}"" />", htmlFieldName, guid));
                  sb.Append(html.EditorFor(singleItemExp, null, String.Format("{0}[{1}]", hasPrefix ? ExpressionHelper.GetExpressionText(expression) : htmlFieldName, guid)));
              }
          }
          return new MvcHtmlString(sb.ToString());
      }
    

    }

1
2
3
4
5

* 原本EditorFor改成自訂的EditorForMany ```html
@Html.EditorFor(x => x.productList)
@Html.EditorForMany(x => x.productList)

這樣產出來的格式就會是帶Guid的方式了,可以正常跟前端結合了