Bagaimana menangani kotak centang dalam formulir ASP.NET MVC?

246

Perhatian: Pertanyaan ini sudah lebih dari sembilan tahun!

Pilihan terbaik Anda adalah mencari pertanyaan yang lebih baru, atau mencari jawaban di bawah ini untuk mencari versi spesifik MVC Anda, karena banyak jawaban di sini sudah usang sekarang.

Jika Anda menemukan jawaban yang berfungsi untuk versi Anda, pastikan jawabannya berisi versi MVC yang Anda gunakan.
(Pertanyaan awal dimulai di bawah)


Ini agak aneh bagi saya, tetapi sejauh yang saya tahu, ini adalah bagaimana Anda melakukannya.

Saya memiliki koleksi objek, dan saya ingin pengguna memilih satu atau lebih dari itu. Ini mengatakan kepada saya "formulir dengan kotak centang." Objek saya tidak memiliki konsep "terpilih" (itu adalah POCO yang belum sempurna yang dibentuk oleh deserialisasi panggilan wcf). Jadi, saya melakukan hal berikut:

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

Dalam tampilan:

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

Dan, dalam controller, ini adalah satu-satunya cara saya bisa melihat untuk mengetahui objek apa yang diperiksa pengguna:

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

Yang aneh di tempat pertama, dan kedua, untuk barang-barang yang diperiksa pengguna, FormCollection mendaftar nilainya sebagai "benar salah" daripada hanya benar.

Jelas, saya kehilangan sesuatu. Saya pikir ini dibangun dengan ide dalam pikiran bahwa objek dalam koleksi yang ditindaklanjuti dalam bentuk html diperbarui menggunakan UpdateModel()atau melalui ModelBinder.

Tetapi objek saya tidak diatur untuk ini; apakah itu berarti bahwa ini adalah satu-satunya cara? Apakah ada cara lain untuk melakukannya?

Uwe Keim
sumber
2
Orang lain mungkin menganggap solusi ini berguna: stackoverflow.com/questions/3291501/…
Aaron

Jawaban:

262

Html.CheckBox melakukan sesuatu yang aneh - jika Anda melihat sumber di halaman hasil, Anda akan melihat ada <input type="hidden" />yang dihasilkan di samping setiap kotak centang, yang menjelaskan nilai "true false" yang Anda lihat untuk setiap elemen formulir.

Coba ini, yang pasti berfungsi pada ASP.NET MVC Beta karena saya baru saja mencobanya.

Letakkan ini dalam tampilan alih-alih menggunakan Html.CheckBox ():

<% 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" />
<%}%>

Kotak centang Anda semuanya dipanggil selectedObjects, dan valuekotak centang masing-masing adalah GUID dari objek yang sesuai.

Kemudian poskan ke tindakan pengontrol berikut (atau sesuatu yang serupa yang melakukan sesuatu yang bermanfaat alih-alih Response.Write ())

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

Contoh ini hanya akan menulis GUID kotak yang Anda centang; ASP.NET MVC memetakan nilai-nilai GUID dari kotak centang yang dipilih ke dalam Guid[] selectedObjectsparameter untuk Anda, dan bahkan mem-parsing string dari koleksi Request.Form menjadi objek-objek GUID yang di-instan, yang menurut saya agak bagus.

Dylan Beattie
sumber
Ya! Inilah yang harus saya lakukan untuk aplikasi saya juga!
Adhip Gupta
70
wtf. bidang input tersembunyi dengan nama SAMA sebagai kontrol. ViewState 2.0-nya!
Simon_Weaver
3
Ini juga hadir dalam rilis 1.0. Lihatlah jawaban @ andrea-balducci yang dikirimkan yang memberi Anda cara yang cerdas untuk menangani hal ini. Jika kotak centang tidak dicentang, teks yang dihasilkan diambil harus 'false false' - nya solusi yang baik untuk akun untuk browser mati otak ...
Bryan Rehbein
77
Mengherankan? Wtf? Input tersembunyi memiliki nama yang sama dengan kotak centang - jika kotak centang dengan nama yang sama tidak dicentang maka nilainya tidak diposting sedangkan nilai yang tersembunyi diposting. Pertama kali browser menemukan elemen bernama itu akan menggunakan nilai itu dan mengabaikan semua elemen lain dengan nama yang sama. Ini menjamin bahwa nilai dikirimkan: benar jika kotak centang dicentang (dengan asumsi itu ditemukan di atas elemen tersembunyi) dan salah jika kotak centang tidak dicentang (kotak centang kosong diabaikan dan yang disembunyikan menjadi mundur kembali). Wtf yang sebenarnya adalah mengapa tidak ada orang lain yang menunjukkan hal ini.
nerraga
19
@nerraga: Anda salah: html valid untuk memiliki beberapa elemen formulir dengan nama yang sama; dan jika demikian, semua elemen diposting, dan saya tidak yakin urutannya benar-benar didefinisikan (meskipun kemungkinan hanya dalam urutan halaman dalam praktiknya). Menggunakan kata "false" sebagai nilai agak menyesatkan, jadi ya, itu adalah WTF - pilihan yang lebih baik, kurang menyesatkan akan menjadi sesuatu seperti "ada" atau beberapa tanda yang tidak berarti seperti tanda hubung.
Eamon Nerbonne
95

HtmlHelper menambahkan input tersembunyi untuk memberi tahu pengontrol tentang status Tidak Dicentang. Jadi untuk memiliki status yang diperiksa benar:

bool bChecked = form[key].Contains("true");
Andrea Balducci
sumber
1
Ini adalah pendekatan termudah untuk masalah ini dan itulah yang selalu saya gunakan. Ini memungkinkan Anda untuk menggunakan metode pembantu dan akun untuk perilaku ASP.NET MVCs.
Nick Daniels
8
.. atau dalam kasus untuk tidak dicentang: bool bChecked = form [key] .Equals ("false"); Melakukan .Contains ("false") gagal karena nilai sebenarnya adalah "true, false".
Mark Robinson
54

Jika Anda bertanya-tanya MENGAPA mereka memasukkan bidang tersembunyi dengan nama yang sama dengan kotak centang alasannya adalah sebagai berikut:

Komentar dari sourcecode MVCBetaSource \ MVC \ src \ MvcFutures \ Mvc \ ButtonsAndLinkExtensions.cs

Berikan tambahan <input type="hidden".../>untuk kotak centang. Ini membahas skenario di mana kotak centang tidak dicentang tidak dikirim dalam permintaan. Mengirimkan input tersembunyi memungkinkan untuk mengetahui bahwa kotak centang hadir pada halaman ketika permintaan diajukan.

Saya kira di balik layar mereka perlu tahu ini untuk mengikat parameter pada metode aksi pengontrol. Anda kemudian dapat memiliki boolean tri-state saya kira (terikat ke parameter bool nullable). Saya belum mencobanya tetapi saya berharap itulah yang mereka lakukan.

Simon_Weaver
sumber
4
Ya ini berguna dalam skenario di mana Anda memiliki paged grid dll dan Anda ingin membatalkan pilihan pada item yang sebelumnya dipilih di beberapa objek bisnis.
RichardOD
49

Anda juga harus menggunakan <label for="checkbox1">Checkbox 1</label>karena dengan begitu orang dapat mengklik teks label serta kotak centang itu sendiri. Ini juga lebih mudah untuk ditata dan setidaknya di IE akan disorot ketika Anda tab melalui kontrol halaman.

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

Ini bukan hanya 'oh saya bisa melakukannya'. Ini merupakan peningkatan pengalaman pengguna yang signifikan. Bahkan jika tidak semua pengguna tahu mereka bisa mengklik label banyak yang mau.

Simon_Weaver
sumber
27

Saya terkejut tidak ada jawaban ini menggunakan fitur built in MVC untuk ini.

Saya menulis posting blog tentang ini di sini , yang bahkan sebenarnya menautkan label ke kotak centang. Saya menggunakan folder EditorTemplate untuk melakukan ini dengan cara yang bersih dan modular.

Anda hanya akan berakhir dengan file baru di folder EditorTemplate yang terlihat seperti ini:

@model SampleObject

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

dalam tampilan Anda yang sebenarnya, tidak perlu mengulang ini, cukup 1 baris kode:

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

Kunjungi posting blog saya untuk lebih jelasnya.

Shawn Mclean
sumber
1
Terima kasih! Everboyd masih menggunakan cara bentuk lama. Dan ketika Anda mengirimkan, Anda dapat mengakses Model tanpa semua koleksi ini [] dan request.form sampah - Ini yang saya cari. +1dan + bir
Piotr Kula
2
Ini harus menjadi jawaban teratas untuk pertanyaan itu. Sangat sederhana dan mudah diimplementasikan.
Johan Gunawan
Berjuang selama beberapa waktu untuk menemukan solusi elegan untuk ini sebelum saya menemukan jawaban ini. Ini berumur beberapa tahun tetapi masih berlaku pada tahun 2016! Jika menggunakan dalam beberapa kasus, gunakan SelectListItem bawaan sebagai tipe generik yang sangat cocok untuk ini
Phil
Apakah SampleObject daftar? Seperti: @ModelType List (Dari Jenis)
JoshYates1980
25

Inilah yang saya lakukan.

Melihat:


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

Pengendali:


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

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

Saya menemukan metode bantuan html. * Tidak begitu berguna dalam beberapa kasus, dan saya lebih baik melakukannya dalam HTML biasa. Karena ini salah satunya, yang lain yang muncul di benak saya adalah tombol radio.

Sunting: ini pada Pratinjau 5, jelas YMMV antara versi.

mmacaulay
sumber
1
Saya hanya ingin menambahkan contoh alternatif: Object.Property =! String.IsNullOrEmpty (Request.Form ["NAME"]);
Gup3rSuR4c
jika tidak dicentang maka pengecualian
Xulfee
10

Mereka tampaknya memilih untuk membaca nilai pertama saja, jadi ini "benar" ketika kotak centang dicentang, dan "salah" ketika hanya nilai tersembunyi yang disertakan. Ini mudah diambil dengan kode seperti ini:

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

@Dylan Beattie Great Find !!! Terima kasih banyak Untuk memperluas lebih jauh, teknik ini juga berfungsi sempurna dengan pendekatan View Model. MVC sangat keren, cukup pintar untuk mengikat array Guids ke properti dengan nama yang sama dari objek Model yang terikat ke View. Contoh:

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; }
    }
}

Melihat:

<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" />
<%}%>                    

Pengendali:

    [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();
    }

Siapa pun yang akrab dengan filosofi Model Tampilan akan bersukacita, ini berfungsi seperti Champ!

nautic20
sumber
Terima kasih, SampleViewModel Anda menghilangkan beberapa kebingungan dalam jawaban aslinya.
parlemen
6

Saya juga ingin menunjukkan bahwa Anda dapat memberi nama pada masing-masing kotak centang nama yang berbeda, dan meminta nama itu menjadi bagian dari parameter hasil tindakan.

Contoh,

Melihat:

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

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

Pengendali:

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

Nilai-nilai dari tampilan diteruskan ke tindakan karena namanya sama.

Saya tahu solusi ini tidak ideal untuk proyek Anda, tetapi saya pikir saya akan membuang ide itu ke sana.

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

Dari Pengendali:

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

         var s = fc["checkbox1"];

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

Masalah ini terjadi di rilis 1.0 juga. Html.Checkbox () menyebabkan bidang tersembunyi lainnya ditambahkan dengan nama / id yang sama dengan kotak centang asli Anda. Dan ketika saya mencoba memuat array kotak centang menggunakan document.GetElemtentsByName (), Anda dapat menebak bagaimana segala sesuatu menjadi kacau. Ini aneh.

Farhan Zia
sumber
4

Dari apa yang dapat saya kumpulkan, model tidak ingin menebak apakah dicentang = benar atau salah, saya menyiasatinya dengan menetapkan atribut nilai pada elemen kotak centang dengan jQuery sebelum mengirimkan formulir seperti ini:

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

Dengan cara ini, Anda tidak perlu elemen tersembunyi hanya untuk menyimpan nilai kotak centang.

BraveNewMath
sumber
4

Saya tahu bahwa pertanyaan ini ditulis ketika MVC3 tidak keluar, tetapi bagi siapa pun yang datang ke pertanyaan ini dan menggunakan MVC3, Anda mungkin menginginkan cara "benar" untuk melakukan ini.

Sementara saya berpikir melakukan keseluruhan

Contains("true");

hal yang hebat dan bersih, dan bekerja pada semua versi MVC, masalahnya adalah tidak memperhitungkan budaya (seolah-olah itu benar-benar penting dalam kasus bool).

Cara "benar" untuk mengetahui nilai bool, setidaknya di MVC3, adalah dengan menggunakan ValueProvider.

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

Saya melakukan ini di salah satu situs klien saya ketika saya mengedit izin:

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));
}

Sekarang, keindahan dari ini adalah Anda dapat menggunakan ini dengan hampir semua jenis sederhana, dan itu bahkan akan benar berdasarkan pada Budaya (pikirkan uang, desimal, dll).

ValueProvider adalah apa yang digunakan saat Anda membentuk Tindakan seperti ini:

public ActionResult UpdatePermissions(bool permission_1, bool permission_2)

tetapi ketika Anda mencoba untuk membuat daftar ini secara dinamis dan memeriksa nilainya, Anda tidak akan pernah tahu ID pada waktu kompilasi, jadi Anda harus memprosesnya dengan cepat.

Dan VanWinkle
sumber
apakah ada alasan Anda menggunakan Request.Params alih-alih menambahkan parameter FormCollection ke metode ini?
SwissCoder
Tanpa alasan, saya tidak benar-benar melihat manfaat dari satu cara di atas yang lain.
Dan VanWinkle
1
Maaf, sebenarnya ada alasannya. Hanya melihat kode saya, dan saya menggunakan metode yang satu ini untuk 5 panggilan berbeda, dan saya merasa tidak ingin melewati FormCollection dari setiap metode. Ini adalah cara termudah untuk mendapatkan kunci tanpa harus membagikan apa pun.
Dan VanWinkle
ya saya baru mengenal MVC. Dan saya membaca di suatu tempat bahwa secara umum lebih baik menggunakan FormCollection daripada Request.Params, sama seperti menggunakan Model yang diketik daripada FormCollection (jadi sebenarnya akan lebih baik menggunakan model dan menghindari menggunakan Request.Params secara umum). Saya perhatikan hal-hal lain dari kode tidak digunakan, seperti variabel allPermissions dan keyAsInt. Terimakasih telah menjawab.
SwissCoder
3

Cara termudah untuk melakukannya adalah ...

Anda menetapkan nama dan nilai.

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

Kemudian saat mengirim ambil nilai kotak centang dan simpan dalam array int. maka Fungsi LinQ yang sesuai. Itu dia..

[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);
        }
kk-dev11
sumber
3

Sama dengan jawaban nautic20, cukup gunakan MVC default model binding list checkbox dengan nama yang sama dengan properti kumpulan string / int / enum di ViewModel. Hanya itu saja.

Tetapi satu masalah perlu ditunjukkan. Di setiap komponen kotak centang, Anda tidak boleh memasukkan "Id" di dalamnya yang akan mempengaruhi pengikatan model MVC.

Kode berikut akan berfungsi untuk penjilidan model:

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

Kode berikut tidak akan mengikat ke model (perbedaan di sini adalah id yang ditetapkan untuk setiap kotak centang)

<% 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>
<% } %>
ChinaHelloWorld
sumber
Terima kasih untuk menjawab, tapi pertanyaan ini adalah juuuust agak tua. Enam tahun, sekitar. Anda mungkin ingin mengedit dan menentukan versi MVC mana yang Anda gunakan. Itu akan membantu siapa saja yang menggunakan versi yang lebih baru menemukan jawaban ini.
Saya yang kedua itu. Menghapus ID unik memecahkan masalah ini setelah banyak sakit kepala dan kertakan gigi
Ody
Versi MVC yang saya gunakan adalah .net MVC 4.0 untuk masalah ini.
ChinaHelloWorld
2

ini adalah apa yang saya lakukan untuk kehilangan nilai ganda saat menggunakan Html.CheckBox (...

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

dengan 4 kotak dicentang, tidak dicentang, tidak dicentang, dicentang ternyata benar, salah, salah, salah, benar, salah menjadi benar, salah, salah, benar. apa yang saya butuhkan

Jeroen
sumber
0

Bagaimana dengan sesuatu yang seperti ini?

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

Saat menggunakan kotak centang HtmlHelper, saya lebih suka bekerja dengan data formulir kotak centang yang diposting sebagai array. Saya tidak benar-benar tahu mengapa, saya tahu metode lain bekerja, tapi saya pikir saya lebih suka memperlakukan string yang dipisahkan koma sebagai array sebanyak mungkin.

Jadi melakukan tes 'diperiksa' atau benar adalah:

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

Melakukan cek palsu adalah:

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

Perbedaan utama adalah untuk digunakan GetValueskarena ini kembali sebagai array.

eyesnz
sumber
0

Lakukan ini pada $(document).ready:

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

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

    }
});
doronAv
sumber
2
Sayangnya, Anda mungkin mendapatkan hasil aneh di sisi server untuk orang-orang yang menonaktifkan JavaScript (plug-in NoScript, ponsel lama, Lynx ...)
ArIck
0

Solusi saya adalah:

<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>  

Lebih banyak lagi dapat Anda temukan di sini: http://www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-not- diakui-as-a- valid-boolean /

pawlom84
sumber
Anda tidak perlu menggunakan Javascript apa pun untuk ini ... var isChecked = formData [key] .Contains ("true");
Jammer
0

Saya memiliki masalah yang hampir sama tetapi Nilai kembalinya Controller saya diblokir dengan Nilai lainnya.

Menemukan Solusi sederhana tetapi tampaknya agak kasar.

Cobalah untuk mengetik Viewbag.Kontroler Anda dan sekarang Anda memberinya nama sepertiViewbag.Checkbool

Sekarang beralihlah ke View dan coba ini @Viewbag.Checkbool dengan ini Anda akan mendapatkan nilai dari Controller.

Parameter Kontroler saya terlihat seperti ini:

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

dan kotak centang saya akan diperbarui seperti ini:

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

Menggunakan @mmacaulay, saya membuat ini untuk bool:

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

Jika dicentang aktif = benar

Jika tidak dicentang aktif = salah

Ravi Ram
sumber