@ Html.HiddenFor, ASP.NET MVC'deki Listelerde çalışmıyor


99

Özellik olarak Liste içeren bir model kullanıyorum. Bu listeyi SQL Server'dan aldığım öğelerle dolduruyorum. Listenin görünümde gizlenmesini ve POST eylemine aktarılmasını istiyorum. Daha sonra jQuery ile bu Listeye daha fazla öğe eklemek isteyebilirim, bu da bir diziyi daha sonra genişletme için uygunsuz hale getirir. Normalde kullanırdın

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

bu işlevselliği gerçekleştirmek için, ancak bazı nedenlerden dolayı POST'taki Liste her zaman boştur.

Çok basit bir soru, MVC'nin neden böyle davrandığını bilen var mı?


1
Normalde bu şekilde tüm listeleri gizlemezsiniz. <input />S cinsinden istediğiniz çıktı nedir ?
Cᴏʀʏ

1
ne MyListiçeriyor? HiddenForher seferinde yalnızca bir giriş için kullanılır.
Daniel A. White

1
Tür nedir Model.MyList? Listenizde manuel olarak bazı serileştirme / seriyi kaldırma işlemi yapmanız gerekebilir.
Kyle Trauberman


Yanıtlar:


163

Bu sorunla karşılaştım ve basitçe aşağıdakileri yaparak çözdüm:

@for(int i = 0; i < Model.ToGroups.Length; i++)
{
    @Html.HiddenFor(model => Model.ToGroups[i])
}

Foreach yerine bir for kullanarak model bağlama doğru şekilde çalışacak ve listedeki tüm gizli değerlerinizi alacaktır. Bu sorunu çözmenin en basit yolu gibi görünüyor.


5
Teşekkürler! gecemi kurtardım.
TSmith

7
Teşekkürler - güzel basit çözüm. Yine de küçük bir mod gerekli: Nesnenin Kimlik alanına başvurulması gerekiyor. Alanın adı RowId ise, o zaman:@Html.HiddenFor(model => Model.ToGroups[i].RowId)
Krishna Gupta

3
koleksiyondaki modellerde birden fazla alanım olduğu zaman bile benim için çalıştı. Yani bir dahaki sefere @Html.EditorFor(model => Model.ToGroups[i].Id)onu takip ediyor @Html.EditorFor(model => Model.ToGroups[i].Description)- her ikisi de for-döngüde. Ve kontrolör, onu bu alanlara sahip modellerin bir listesi ile eşleştirebildi. Ve hiçbirinin ekranda <div style="display: none;"></div>
Don Cheadle

Parlak! Güzel yapılmış. Benim için çalıştı!
AxleWack

3
@ user3186023 Burada gerçekten eski bir yorumu yanıtlamak, ancak belki başka biri de aynı sorunu foryaşayacak: -döngüyü şuna değiştirin :for(int i = 0; i < Model.Departments.Count(); i++)
Stian

28

HiddenFor, DisplayFor veya EditorFor gibi değildir. Koleksiyonlarla çalışmaz, yalnızca tek değerlerle çalışır.

Bir nesneyi Gizli bir alana serileştirmek için MVC Futures projesinde bulunan HTML Seri Hale Getirme yardımcısını kullanabilirsiniz, aksi takdirde kodu kendiniz yazmanız gerekir. Daha iyi bir çözüm, bir ID'yi basitçe serileştirmek ve geri gönderme sırasında veritabanından verileri yeniden almaktır.


Bir örnek var mı Bunu denedim ve form gönderildiğinde ViewModel değerine bağlanamadı.
Alan Macdonald

@AlanMacdonald - eğer bir şey bağlanamazsa, bunun nedeni isimlendirmenizin doğru olmamasıdır, büyük ihtimalle indeksleyici ile for yerine foreach kullandınız. Ya da belki ciltlemede uygun nitelikleri kullanmadınız. Bkz. Weblogs.asp.net/shijuvarghese/archive/2010/03/06/…
Erik Funkenbusch

Teşekkürler. Aslında denediğimde gerçekten @ Html.Serialize ("Model.ModelIDs", Model.ModelIDs) idi, burada Model benim ViewModel'imdi ve ModelIDs int array özelliği vardı. Yani döngü falan yoktu. Form gönderildiğinde ModelID'ler bağlı ViewModel'de her zaman boştu.
Alan Macdonald

@AlanMacdonald - Ada "Model" eklemediniz.
Erik Funkenbusch

16

Bu biraz zor , ancak listeniz için çalışıyorsa @Html.EditorForveya @Html.DisplayForçalışıyorsa, gönderi isteğinde gönderildiğinden ancak görünür olmadığından emin olmak istiyorsanız, display: none;bunun yerine gizlemek için kullanarak stil verebilirsiniz , örneğin:

<div style="display: none;">@Html.EditorFor(model => model.MyList)</div>

Bu, talebin postasındaki modeldeki değeri kaydetmez.
nldev

.EditorFor doğru şekilde çalışacak şekilde ayarlanmışsa, bu da çalışacağına inanıyorum.
Mark Rhodes

10

Ne bir json dizeye nesneyi serisini ve ardından Gizli alan dönüşebilir, örneğin o insert için Newtonsoft kullanma hakkında ( Model.DataResponse.Entity.Commission bir olduğunu Liste basit bir "CommissionRange" Eğer JSON göreceğimiz gibi nesneleri)

@using (Ajax.BeginForm("Settings", "AffiliateProgram", Model.DataResponse, new AjaxOptions { UpdateTargetId = "result" }))
   {
      string commissionJson = JsonConvert.SerializeObject(Model.DataResponse.Entity.Commission);
      @Html.HiddenFor(data => data.DataResponse.Entity.Guid)
      @Html.Hidden("DataResponse_Entity_Commission", commissionJson)
      [Rest of my form]
   }

Oluşturma şekli:

<input id="DataResponse_Entity_Commission" name="DataResponse_Entity_Commission" type="hidden" value="[{"RangeStart":0,"RangeEnd":0,"CommissionPercent":2.00000},{"RangeStart":1,"RangeEnd":2,"CommissionPercent":3.00000},{"RangeStart":2,"RangeEnd":0,"CommissionPercent":2.00000},{"RangeStart":3,"RangeEnd":2,"CommissionPercent":1.00000},{"RangeStart":15,"RangeEnd":10,"CommissionPercent":5.00000}]">

Benim durumumda, geri göndermeden önce gizli alanda json'u düzenlemek için bazı JS işleri yapıyorum

Denetleyicimde, seri halini kaldırmak için tekrar Newtonsoft kullanıyorum:

string jsonCommissionRange = Request.Form["DataResponse_Entity_Commission"];
List<CommissionRange> commissionRange = JsonConvert.DeserializeObject<List<CommissionRange>>(jsonCommissionRange);

Bu benim için çalıştı. Kabul edilen çözümden çok daha temiz olduğunu düşündüm.
e-on

6

Html.HiddenForyalnızca tek bir değer için tasarlanmıştır. Gizli alanı oluşturmadan önce listenizi bir şekilde serileştirmeniz gerekecek.

Örneğin, listeniz dize türündeyse, listeyi virgülle ayrılmış bir liste halinde birleştirebilir, ardından denetleyicinize geri gönderdikten sonra listeyi bölebilirsiniz.


4

Yeni öğrendim (model değerlerinin neden denetleyiciye geri dönmediğini anlamaya çalıştıktan birkaç saat sonra), EditorFor'u takip etmelidir.

Yanlış bir şey yapmıyorsam, bulduğum şey bu. Bir daha hata yapmayacağım.

Başka bir sınıfın listesini içeren bir Model bağlamında.

Bu çalışmayacaktır:

        @{
            for (int i = 0; i < Model.Categories.Count; i++)
            {
                <tr>
                    <td>
                        @Html.HiddenFor(modelItem => Model.Categories[i].Id)
                        @Html.HiddenFor(modelItem => Model.Categories[i].ProductCategoryId)
                        @Html.HiddenFor(modelItem => Model.Categories[i].CategoryName)                            
                        @Html.DisplayFor(modelItem => Model.Categories[i].CategoryName)                            
                    </td>
                    <td>
                        @Html.HiddenFor(modelItem => Model.Categories[i].DailyPurchaseLimit)                                                        
                        @Html.EditorFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
                        @Html.ValidationMessageFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
                    </td>
                    <td style="text-align: center">
                        @Html.HiddenFor(modelItem => Model.Categories[i].IsSelected)                            
                        @Html.EditorFor(modelItem => Model.Categories[i].IsSelected)
                    </td>
                </tr>
            }
        }

Bu nerede OLACAK ......

            for (int i = 0; i < Model.Categories.Count; i++)
            {
                <tr>
                    <td>
                        @Html.HiddenFor(modelItem => Model.Categories[i].Id)
                        @Html.HiddenFor(modelItem => Model.Categories[i].ProductCategoryId)
                        @Html.HiddenFor(modelItem => Model.Categories[i].CategoryName)                            
                        @Html.DisplayFor(modelItem => Model.Categories[i].CategoryName)                            
                    </td>
                    <td>
                        @Html.EditorFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
                        @Html.HiddenFor(modelItem => Model.Categories[i].DailyPurchaseLimit)                            
                        @Html.ValidationMessageFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
                    </td>
                    <td style="text-align: center">
                        @Html.EditorFor(modelItem => Model.Categories[i].IsSelected)
                        @Html.HiddenFor(modelItem => Model.Categories[i].IsSelected)                            
                    </td>
                </tr>
            }

3

Kaynak kodunu araştırmaya başladım HiddenForve gördüğünüz engel, karmaşık nesnenizin MyListdolaylı olarak türe dönüştürülemeyeceğidir string, bu nedenle çerçeve, Modeldeğerinizi kabul eder nullve valueniteliği boş hale getirir .


3

Bu çözüme bir göz atabilirsiniz .

EditorTemplate içine yalnızca HiddenFor koyun.

Ve Görünümünüze şunu koyun: @Html.EditorFor(model => model.MyList)

Çalışmalı.


3

Aynı sorunla karşılaştı. For döngüsü olmadan, listenin yalnızca ilk öğesini yayınladı. For döngüsünü yineledikten sonra tam listeyi tutabilir ve başarıyla gönderebilir.

 @if (Model.MyList!= null)
    {
    for (int i = 0; i < Model.MyList.Count; i++)
      {
        @Html.HiddenFor(x => x.MyList[i])
      }
    }

2

Diğer bir seçenek şudur:

<input type="hidden" value=@(string.Join(",", Model.MyList)) />

Bu benim de ilk fikrimdi. Ancak MyList alanı için bir int [] bekleyen bir görünüm modelim vardı ve virgülle ayrılmış dizge MVC bağlama mekanizması tarafından bir diziye ayrıştırılmadı.
Tadej Mali

2

foreachYerine döngü fordöngü biraz daha temiz bir çözüm olabilir.

@foreach(var item in Model.ToGroups)
{
    @Html.HiddenFor(model => item)
}

1

Bunu düzeltmenin bir başka olası yolu, Listenizdeki her nesneye bir kimlik vermek, ardından @Html.DropDownListFor(model => model.IDs)kimlikleri tutan bir dizi kullanmak ve doldurmaktır.


1

Geç olabilir, ancak koleksiyondaki gizli alanlar için uzantı yöntemi oluşturdum (basit veri türü öğeleriyle):

İşte burada:

/// <summary>
/// Returns an HTML hidden input element for each item in the object's property (collection) that is represented by the specified expression.
/// </summary>
public static IHtmlString HiddenForCollection<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression) where TProperty : ICollection
{
    var model = html.ViewData.Model;
    var property = model != null
                ? expression.Compile().Invoke(model)
                : default(TProperty);

    var result = new StringBuilder();
    if (property != null && property.Count > 0)
    {
        for(int i = 0; i < property.Count; i++)
        {
            var modelExp = expression.Parameters.First();
            var propertyExp = expression.Body;
            var itemExp = Expression.ArrayIndex(propertyExp, Expression.Constant(i));

            var itemExpression = Expression.Lambda<Func<TModel, object>>(itemExp, modelExp);

            result.AppendLine(html.HiddenFor(itemExpression).ToString());
        }
    }

    return new MvcHtmlString(result.ToString());
}

Kullanım şu kadar basittir:

@Html.HiddenForCollection(m => m.MyList)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.