ASP.NET MVC formlarındaki onay kutularını nasıl işleyebilirim?


246

Dikkat: Bu soru dokuz yıldan eski!

En iyi seçeneğiniz, daha yeni soruları aramak veya MVC'nize özgü sürümünüzü aramak için aşağıdaki cevapları aramaktır, çünkü burada birçok yanıt artık kullanılmamaktadır.

Sürümünüze uygun bir yanıt bulursanız, lütfen yanıtın kullandığınız MVC sürümünü içerdiğinden emin olun.
(Orijinal soru aşağıda başlar)


Bu bana biraz tuhaf geliyor, ama anlayabildiğim kadarıyla böyle yapıyorsun.

Bir nesne koleksiyonum var ve kullanıcıların bunlardan birini veya daha fazlasını seçmesini istiyorum. Bu bana "onay kutuları ile form" diyor. Nesnelerimin herhangi bir "seçilmiş" kavramı yok (bir wcf çağrısının serileştirilmesiyle oluşturulan temel POCO'lar). Bu yüzden aşağıdakileri yapıyorum:

public class SampleObject{
  public Guid Id {get;set;}
  public string Name {get;set;}
}

Görünümde:

<%
    using (Html.BeginForm())
    {
%>
  <%foreach (var o in ViewData.Model) {%>
    <%=Html.CheckBox(o.Id)%>&nbsp;<%= o.Name %>
  <%}%>
  <input type="submit" value="Submit" />
<%}%>

Ve denetleyicide, kullanıcının hangi nesneleri kontrol ettiğini anlamanın tek yolu budur:

public ActionResult ThisLooksWeird(FormCollection result)
{
  var winnars = from x in result.AllKeys
          where result[x] != "false"
          select x;
  // yadda
}

İlk olarak garip ve ikincisi, kullanıcının kontrol ettiği öğeler için FormCollection değerini yalnızca doğru değil, "doğru yanlış" olarak listeler.

Açıkçası, bir şey eksik. Bu html formu içinde hareket koleksiyonunda nesneleri UpdateModel()bir ModelBinder kullanılarak güncelleştirildiği düşüncesiyle inşa düşünüyorum .

Ancak nesnelerim bunun için ayarlanmamış; bu tek yolun bu olduğu anlamına mı geliyor? Bunu yapmanın başka bir yolu var mı?


2
Diğerleri bu çözümü yararlı bulabilir: stackoverflow.com/questions/3291501/…
Aaron

Yanıtlar:


262

Html.CheckBox garip bir şey yapıyor - sonuçtaki sayfada kaynak görüntülerseniz, <input type="hidden" />her onay kutusunun yanında oluşturulduğunu görürsünüz , bu da her form öğesi için gördüğünüz "gerçek yanlış" değerleri açıklar.

Kesinlikle denedim çünkü kesinlikle ASP.NET MVC Beta üzerinde çalışan bu deneyin.

Html.CheckBox () kullanmak yerine bunu görünüme koyun:

<% using (Html.BeginForm("ShowData", "Home")) {  %>
  <% foreach (var o in ViewData.Model) { %>
    <input type="checkbox" name="selectedObjects" value="<%=o.Id%>">
    <%= o.Name %>
  <%}%>
  <input type="submit" value="Submit" />
<%}%>

Onay kutularınızın tümü çağrılır selectedObjectsvevalue her onay kutusunun işareti karşılık gelen nesnenin GUID değeridir.

Ardından, aşağıdaki denetleyici eylemine (veya Response.Write () yerine yararlı bir şey yapan benzer bir şey) gönderin

public ActionResult ShowData(Guid[] selectedObjects) {
    foreach (Guid guid in selectedObjects) {
        Response.Write(guid.ToString());
    }
    Response.End();
    return (new EmptyResult());
}

Bu örnek, işaretlediğiniz kutuların GUID'lerini yazacaktır; ASP.NET MVC seçilen onay kutularının GUID değerleri Guid[] selectedObjectssizin için parametreye eşleştirir ve hatta Request.Form koleksiyonundan dizeleri oldukça güzel olduğunu düşündüğüm örnek GUID nesnelerine ayrıştırır.


Evet! Uygulamalarım için de yapmam gereken buydu!
Adhip Gupta

70
o ne lan. kontrol olarak AYNI isimle gizli girdi alanları. onun ViewState 2.0!
Simon_Weaver

3
Bu, 1.0 sürümünde de mevcuttur. @ Andrea-balducci tarafından gönderilen ve bununla başa çıkmanın akıllıca bir yolunu sunan cevaba bakın. Onay kutusu işaretli değilse, elde edilen metin 'yanlış yanlış' olmalıdır - beyin ölü tarayıcılarını hesaba katmak için iyi bir çözüm ...
Bryan Rehbein

77
Sürpriz? O ne lan? Gizli giriş onay kutusuyla aynı ada sahiptir - aynı ada sahip onay kutusu işaretlenmemişse, değeri kaydedilmez, gizli değerin gönderilir. Tarayıcı adlandırılmış bir öğeyle ilk karşılaştığında bu değeri kullanır ve aynı ada sahip diğer tüm öğeleri yok sayar. Bu, bir değerin gönderilmesini garanti eder: onay kutusu işaretliyse true (gizli öğenin üstünde bulunduğu varsayılarak) ve onay kutusu işaretli değilse false (boş onay kutusu yok sayılır ve gizli geri dönüş olur). Gerçek wtf neden başka kimsenin bunu işaret etmediğidir.
nerraga

19
@nerraga: Yanılıyorsunuz: aynı ada sahip birden çok form öğesine sahip olmak geçerli html'dir; ve eğer öyleyse, tüm öğeler gönderilir ve siparişin gerçekten tanımlandığından emin değilim (ancak pratikte sayfa düzeninde olması muhtemeldir). Değer olarak "false" kelimesini kullanmak biraz yanıltıcıdır, bu yüzden evet, bu bir WTF'dir - daha iyi, daha az yanıltıcı bir seçim "var" veya bir çizgi gibi anlamsız bir simge olurdu.
Eamon Nerbonne

95

HtmlHelper, denetleyiciyi Denetlenmeyen durumu hakkında bilgilendirmek için gizli bir giriş ekler. Doğru kontrol durumuna sahip olmak için:

bool bChecked = form[key].Contains("true");

1
Bu soruna en kolay yaklaşım budur ve her zaman kullandığım şey budur. Yardımcı yöntemleri kullanmanıza ve ASP.NET MVC'lerinin davranışını açıklamanıza olanak tanır.
Nick Daniels

8
.. veya işaretlenmemiş durumda: bool bChecked = form [anahtar] .Equals ("false"); Gerçek değer "true, false" olduğundan .Contains ("false") işlemi başarısız olur.
Mark Robinson

54

Niçin onay kutusuyla aynı ada sahip gizli bir alan yerleştirdiklerini merak ediyorsanız, nedeni aşağıdaki gibidir:

MVCBetaSource \ MVC \ src \ MvcFutures \ Mvc \ ButtonsAndLinkExtensions.cs kaynak kodundan yorum

<input type="hidden".../>Onay kutuları için bir ek oluşturun. Bu, istekte işaretlenmemiş onay kutularının gönderilmediği senaryoları ele alır. Gizli bir giriş göndermek, istek gönderildiğinde onay kutusunun sayfada bulunduğunu bilmeyi mümkün kılar.

Ben denetleyici eylem yöntemleri parametreleri bağlanmak için bu bilmeniz gereken perde arkasında sanırım. Sonra bir tri-state boolean varsayalım (nullable bool parametresine bağlı). Denemedim ama yaptıklarını umuyorum.


4
Evet, ızgaraları vb. Sayfaladığınız senaryolarda kullanışlıdır ve daha önce bazı iş nesnelerinde seçilen öğenin seçimini kaldırmak istersiniz.
RichardOD

49

Ayrıca kullanmalısınız <label for="checkbox1">Checkbox 1</label>çünkü kullanıcılar etiket metninin yanı sıra onay kutusunun kendisini de tıklayabilirler. Aynı zamanda tarzı daha kolay ve en azından IE'de sayfanın kontrolleri arasında sektiğinizde vurgulanacaktır.

<%= Html.CheckBox("cbNewColors", true) %><label for="cbNewColors">New colors</label>

Bu sadece 'oh yapabilirim' bir şey değil. Önemli bir kullanıcı deneyimi geliştirmesi. Tüm kullanıcılar bilmese bile etikete tıklayabilirler.


27

Bu cevapların hiçbiri bunun için yerleşik MVC özelliklerini kullanmamıştı.

Burada bununla ilgili bir blog yazısı yazdım , hatta etiketleri aslında onay kutusuna bağlayan. EditorTemplate'i kullandım temiz ve modüler bir şekilde gerçekleştirmek klasörünü .

Sadece EditorTemplate klasöründe şuna benzeyen yeni bir dosya elde edersiniz:

@model SampleObject

@Html.CheckBoxFor(m => m.IsChecked)
@Html.HiddenFor(m => m.Id)
@Html.LabelFor(m => m.IsChecked, Model.Id)

gerçek görünümünüzde, bunu döngüye gerek yoktur, sadece 1 satır kod:

@Html.EditorFor(x => ViewData.Model)

Daha fazla bilgi için blog yayınımı ziyaret edin .


1
Teşekkür ederim! Everboyd hala eski biçimleri kullanıyor. Ve gönderdiğinizde, tüm bu koleksiyon [] ve request.form çöp olmadan Model'e erişebilirsiniz - Aradığım şey budur. +1ve + bira
Piotr Kula

2
Bu sorunun en iyi cevabı olmalı. Çok basit ve uygulaması kolaydır.
Johan Gunawan

Bu cevabı bulmadan önce bir süre bunun için zarif bir çözüm bulmak için mücadele ettim. Birkaç yaşında ama 2016'da hala geçerli! Birkaç durumda kullanılıyorsa, buna uygun olan genel tip olarak yerleşik SelectListItem kullanın
Phil

SampleObject bir liste mi? Mesela: @ModelType Listesi (Tür)
JoshYates1980

25

İşte yaptığım şey.

Görünüm:


<input type="checkbox" name="applyChanges" />

Denetleyici:


var checkBox = Request.Form["applyChanges"];

if (checkBox == "on")
{
...
}

Html. * Yardımcı yöntemlerini bazı durumlarda çok kullanışlı bulmadım ve düz eski HTML'de yapmam daha iyi oldu. Bu onlardan biri, akla gelen diğer radyo düğmeleri.

Düzenleme: Bu önizleme 5, tabii ki sürümler arasında YMMV.


1
Sadece alternatif bir örnek eklemek istiyorum: Object.Property =! String.IsNullOrEmpty (Request.Form ["NAME"]);
Gup3rSuR4c

işaretlenmezse istisna olur
Xulfee

10

Yalnızca ilk değeri okumayı tercih ediyor gibi görünüyorlar, bu yüzden onay kutusu işaretlendiğinde bu "true" ve yalnızca gizli değer eklendiğinde "false" olur. Bu, aşağıdaki gibi bir kodla kolayca getirilir:

model.Property = collection["ElementId"].ToLower().StartsWith("true");

8

@ Dylan beattie harika bul !!! Çok teşekkür ederim. Daha da genişletmek için, bu teknik Görünüm Modeli yaklaşımı ile de mükemmel çalışır. MVC o kadar havalı ki, bir dizi Kılavuz'u bir görünüme bağlı Model nesnesiyle aynı ada bağlayacak kadar akıllı. Misal:

ViewModel:

public class SampleViewModel
{
    public IList<SampleObject> SampleObjectList { get; set; }
    public Guid[] SelectedObjectIds { get; set; }

    public class SampleObject
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }
}

Görünüm:

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Sample View</h2>
<table>
    <thead> 
        <tr>
            <th>Checked</th>
            <th>Object Name</th>
        </tr>
    </thead> 
<% using (Html.BeginForm()) %>
<%{%>                    
    <tbody>
        <% foreach (var item in Model.SampleObjectList)
           { %>
            <tr>
                <td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
                <td><%= Html.Encode(item.Name)%></td>
            </tr>
        <% } %>
    </tbody>
</table>
<input type="submit" value="Submit" />
<%}%>                    

Denetleyici:

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult SampleView(Guid id)
    {
        //Object to pass any input objects to the View Model Builder 
        BuilderIO viewModelBuilderInput = new BuilderIO();

        //The View Model Builder is a conglomerate of repositories and methods used to Construct a View Model out of Business Objects
        SampleViewModel viewModel = sampleViewModelBuilder.Build(viewModelBuilderInput);

        return View("SampleView", viewModel);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SampleView(SampleViewModel viewModel)
    {
        // The array of Guids successfully bound to the SelectedObjectIds property of the View Model!
        return View();
    }

Görünüm Modeli felsefesine aşina olan herkes sevinir, bu bir Champ gibi çalışır!


Teşekkürler, SampleViewModel orijinal cevap bazı karışıklık giderdi.
parlamento

6

Ayrıca, her onay kutusuna farklı bir ad verebileceğinizi ve bu adın actionresults parametrelerinin bir parçasına sahip olabileceğinizi belirtmek isterim.

Misal,

Görünüm:

 <%= Html.CheckBox("Rs232CheckBox", false, new { @id = "rs232" })%>RS-232

 <%= Html.CheckBox("Rs422CheckBox", false, new { @id = "rs422" })%>RS-422

Denetleyici:

public ActionResults MyAction(bool Rs232CheckBox, bool Rs422CheckBox) {
    ...
}

Görünümdeki değerler, adlar aynı olduğundan eyleme aktarılır.

Bu çözümün projeniz için ideal olmadığını biliyorum, ama fikri oraya atacağımı düşündüm.


5
<input type = "checkbox" name = "checkbox1" /> <label> Check to say hi.</label>

Denetleyiciden:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Index(FormCollection fc)
    {

         var s = fc["checkbox1"];

         if (s == "on")
         {
             string x = "Hi";
         }
    }

4

Bu sorun 1.0 sürümünde de yaşanıyor. Html.Checkbox (), orijinal onay kutunuzla aynı ad / kimliğe sahip başka bir gizli alan eklenmesine neden olur. Ve document.GetElemtentsByName () kullanarak bir onay kutusu dizisi yüklemeye çalışırken, işlerin nasıl dağıldığını tahmin edebilirsiniz. Bu tuhaf.


4

Ne toplayabilir, modeli kontrol = doğru ya da yanlış olup olmadığını tahmin etmek istemiyor, ben böyle bir formu göndermeden önce jQuery ile onay kutusu öğesinde bir değer özniteliği ayarlayarak bu var:

 $('input[type="checkbox"]').each(function () {
       $(this).attr('value', $(this).is(':checked'));
 }); 

Bu şekilde, yalnızca onay kutusunun değerini saklamak için gizli bir öğeye ihtiyacınız yoktur.


4

Bu sorunun MVC3 dışarıda olmadığında yazıldığını biliyorum, ancak bu soruya gelen ve MVC3'ü kullanan herkes için bunu yapmanın "doğru" yolunu isteyebilirsiniz.

Bence bütün yapmayı

Contains("true");

şey harika ve temiz ve tüm MVC sürümlerinde çalışıyor, sorun kültürü dikkate almaması (bir bool durumunda gerçekten önemli gibi).

En azından MVC3'te bir boolün değerini bulmanın "doğru" yolu ValueProvider kullanmaktır.

var value = (bool)ValueProvider.GetValue("key").ConvertTo(typeof(bool));

İzinleri düzenlediğimde bunu istemcimin sitelerinden birinde yapıyorum:

var allPermissionsBase = Request.Params.AllKeys.Where(x => x.Contains("permission_")).ToList();
var allPermissions = new List<KeyValuePair<int, bool>>();

foreach (var key in allPermissionsBase)
{
     // Try to parse the key as int
     int keyAsInt;
     int.TryParse(key.Replace("permission_", ""), out keyAsInt);

     // Try to get the value as bool
     var value = (bool)ValueProvider.GetValue(key).ConvertTo(typeof(bool));
}

Şimdi, bunun güzelliği, bunu hemen hemen her türlü basit tipte kullanabilmenizdir ve hatta Kültüre göre doğru olacaktır (parayı, ondalıkları vb.).

ValueProvider, İşlemlerinizi şu şekilde oluştururken kullanılan yöntemdir:

public ActionResult UpdatePermissions(bool permission_1, bool permission_2)

ancak bu listeleri dinamik olarak oluşturmaya ve değerleri kontrol etmeye çalışırken, derleme sırasında kimliği asla bilemezsiniz, bu yüzden onları anında işlemeniz gerekir.


yönteme FormCollection parametresi eklemek yerine Request.Params kullanmanızın bir nedeni var mı?
SwissCoder

Sebep yok, gerçekten bir yoldan diğerine fayda görmüyorum.
Dan VanWinkle

1
Üzgünüm, aslında bir nedeni var. Sadece koduma baktım ve 5 farklı arama için bu yöntemi kullanıyorum ve her yöntemden FormCollection geçen gibi hissetmedim. Bu, herhangi bir şey iletmeye gerek kalmadan anahtarları almanın en kolay yoluydu.
Dan VanWinkle

evet MVC'de yeniyim. Ve genel olarak, FormCollection yerine FormCollection kullanmak FormCollection yerine, FormCollection yerine yazılan bir Model kullanarak aynı daha iyi okudum (yani aslında bir model kullanmak ve genel olarak Request.Params kullanmaktan kaçının). AllPermissions değişkeni ve keyAsInt gibi kodun başka şeylerinin kullanılmadığını fark ettim. Cevapladığınız için teşekkürler.
SwissCoder

3

Bunu yapmanın en kolay yolu ...

Adı ve değeri siz belirlersiniz.

<input type="checkbox" name="selectedProducts" value="@item.ProductId" />@item.Name

Daha sonra gönderirken onay kutularının değerlerini alın ve bir int dizisine kaydedin. sonra uygun LinQ İşlevi. Bu kadar..

[HttpPost]
        public ActionResult Checkbox(int[] selectedObjects)
        {
            var selected = from x in selectedObjects
                           from y in db
                           where y.ObjectId == x
                           select y;                   

            return View(selected);
        }

3

Nautic20'nin cevabı ile aynı şekilde, ViewModel'de string / int / enum'un toplama özelliğiyle aynı ada sahip MVC varsayılan model bağlama onay kutusu listesini kullanmanız yeterlidir. İşte bu.

Ancak bir sorunun belirtilmesi gerekir. Her onay kutusu bileşeninde, MVC modelinin bağlanmasını etkileyecek "Id" değerini koymamalısınız.

Model bağlama için aşağıdaki kod çalışır:

 <% foreach (var item in Model.SampleObjectList)
       { %>
        <tr>
            <td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
            <td><%= Html.Encode(item.Name)%></td>
        </tr>
 <% } %>

Aşağıdaki kodlar modele bağlanmayacaktır (burada fark her onay kutusu için kimlik atanmasıdır)

<% foreach (var item in Model.SampleObjectList)
       { %>
        <tr>
            <td><input type="checkbox" name="SelectedObjectIds" id="[some unique key]" value="<%= item.Id%>" /></td>
            <td><%= Html.Encode(item.Name)%></td>
        </tr>
<% } %>

Yanıtladığınız için teşekkürler, ancak bu soru biraz eski. Altı yaşında, yaklaşık. Hangi MVC sürümünü kullandığınızı düzenlemek ve belirtmek isteyebilirsiniz . Bu, daha yeni bir sürüm kullanan herkesin bu cevabı bulmasına yardımcı olacaktır.

İkinci olarak. Benzersiz kimliğin kaldırılması, çok fazla baş ağrısı ve dişlerin
gıcırdamasından

Ben kullanıyorum MVC sürümü bu sorun için .net MVC 4.0 olduğunu.
ChinaHelloWorld

2

Html.CheckBox kullanırken çift değerleri kaybetmek için yaptığım budur (...

Replace("true,false","true").Split(',')

4 kutu işaretli, işaretsiz, işaretsiz, doğru, yanlış, yanlış, yanlış, doğru, yanlış, doğru, yanlış, yanlış, doğru olur. tam ihtiyacım olan


0

Böyle bir şeye ne dersin?

bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues(”chkHuman”)[0], out isChecked) == false)
    ModelState.AddModelError(”chkHuman”, Nice try.”);

0

HtmlHelper onay kutusunu kullanırken, bir dizi olarak yayınlanan onay kutusu form verileri ile çalışmayı tercih ederim. Gerçekten neden bilmiyorum, diğer yöntemler işe biliyorum, ama ben sadece virgülle ayrılmış dizeleri mümkün olduğunca bir dizi olarak tedavi tercih düşünüyorum.

Bu yüzden 'kontrol edilmiş' veya doğru test yapmak:

//looking for [true],[false]
bool isChecked = form.GetValues(key).Contains("true"); 

Yanlış kontrol yapmak şöyle olur:

//looking for [false],[false] or [false]
bool isNotChecked = !form.GetValues(key).Contains("true"); 

Ana fark, GetValuesbu bir dizi olarak döndüğü için kullanmaktır .


0

Sadece şunu yapın $(document).ready:

$('input:hidden').each(function(el) {
    var that = $(this)[0];
    if(that.id.length < 1 ) {

        console.log(that.id);
        that.parentElement.removeChild(that);

    }
});

2
Ne yazık ki, JavaScript kapalı olan kullanıcılar için sunucu tarafında garip sonuçlar alabilirsiniz (NoScript eklentisi, eski cep telefonları, Lynx ...)
ArIck

0

Benim çözümüm:

<input type="checkbox"  id="IsNew-checkbox"  checked="checked" />     
<input type="hidden"  id="IsNew" name="IsNew" value="true"  />      
<script language="javascript" type="text/javascript" >     
  $('#IsNew-checkbox').click(function () {    
      if ($('#IsNew-checkbox').is(':checked')) {    
          $('#IsNew').val('true');    
      } else {    
          $('#IsNew').val('false');    
       }    
  });   
</script>  

Daha fazlasını burada bulabilirsiniz: http://www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-recognized-as-a- geçerli-boolean /


Bunun için herhangi bir Javascript kullanmanıza gerek yoktur ... var isChecked = formData [key] .Contains ("true");
Jammer

0

Neredeyse aynı Sorun yaşadım ama Denetleyicimin dönüş Değeri diğer Değerlerle engellendi.

Basit bir Çözüm buldum ama biraz kaba görünüyor.

Viewbag.Denetleyicinizi yazmaya çalışın ve şimdi ona şöyle bir ad veriyorsunuzViewbag.Checkbool

Şimdi Görünüme geçin ve bunu deneyin @Viewbag.Checkbool , değeri Denetleyiciden çıkarın.

Denetleyici Parametrelerim şöyle:

public ActionResult Anzeigen(int productid = 90, bool islive = true)

ve Onay Kutum şu şekilde güncellenir:

<input id="isLive" type="checkbox" checked="@ViewBag.Value" ONCLICK="window.location.href = '/MixCategory/Anzeigen?isLive=' + isLive.checked.toString()" />

0

@Mmacaulay kullanarak, bool için bunu buldum:

// MVC Work around for checkboxes.
bool active = (Request.Form["active"] == "on");

Etkin olarak işaretlenirse = doğru

İşaretlenmemişse etkin = yanlış

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.