Lucian Maran

home

HTML CheckBox - ca element de filtrare pe un View MVC

23 Mar 2013

Am ajuns sa scriu acest articol dupa ce am incercat sa rezolv o problema care nu ar fi trebuit sa-mi ia mai mult de 15 minute. Sau cel putin asa am crezut!

Situatia initiala:

Am o Lista de Produse si o Zona de Filtrare prin care pot selecta doar un subset din totalul produselor. Controalele HTML din zona de filtrare sunt grupate intr-un FORM si sunt transmise la server cu method="get". Valorile din filtrele completate sunt serializate sub forma unui QueryString, direct in URL. Daca nu modific niciun filtru, URL-ul va fi 'curat', ca la prima lansare. Totul functioneaza perfect:

Si acum problema:

Am vrut sa adaug in zona de filtrare inca un control de tip CheckBox, prin care sa pot afisa doar produsele aflate pe stoc. Prima ideie, bineinteles, a fost sa folosesc HTML helper-ul din MVC:

@Html.CheckBox("fStock",(bool)ViewBag.StockOnly) //ViewBag - o valoare returnata de server, utila pentru memorarea starii

Aici deja apare prima ciudatenie:

Nu, nu am gresit nimic, asa functioneaza helper-ul din MVC. Iar cele 2 valori apar datorita faptului ca, la randare, helper-ul adauga inca un element <input type="hidden">. Detalii aici.

Chiar si asa, problema nu e greu de rezolvat:

Solutia 1:

Pe server, citesc parametrii din querystring (eu folosesc un Action Filter descries de ungood aici). In functie de acestia, returnez in ViewBag valoare corespunzatoare (true sau false) a.i, atunci cand View-ul se reincarca, in checkbox sa ramana optiunea setata de utilizator. Codul C# care face acest lucru e urmatorul:

//Filter by StockOnly (pentru @HTML.CheckBox)
var fStock = (querystring["fStock"]); //returneaza "true,false" pt. @Html.CheckBox bifat
if (fStock != null && bool.Parse(fStock.Split(',')[0]))
     ViewBag.StockOnly = true;
else
     ViewBag.StockOnly = false;

Acum totul functioneaza dar mai am o problema de ordin estetic. Nu-mi place sa vad in URL doua valori diferite pentru Checkbox, atunci cand eu am nevoie doar de una. Si mai ales, nu-mi place sa vad in URL un parametru legat de Stoc, atunci cand eu nu activez acest filtru. Cel mai bine se vede acest lucru atunci cand niciun filtru nu e completat:

Solutia 2:

Pot corecta cele de mai sus folosind un control HTML clasic <input type='checkbox'>. Ma voi baza pe proprietatea acestuia de a nu transmite nicio valoare atunci cand nu este selectat. In acest caz, codul de pe client, respective server, se modifica astfel:

<input id="fStock" type="checkbox" value="true"  name="fStock"
     @if ((bool)ViewBag.StockOnly) {<text>checked="checked"</text>} />

iar pe server:

//Filter by StockOnly (pentru <input type="checkbox">)
var fStock = (querystring["fStock"]);
if (!string.IsNullOrEmpty(fStock))
    ViewBag.StockOnly = true;
else
    ViewBag.StockOnly = false;

In felul acesta, voi avea un singur parametru in URL (daca bifa e pusa) si niciun parametru (daca bifa lipseste). Adica exact ceea ce am dorit:

Solutia 3 (nerecomandata)

Pot trimite FORM-ul ce contine campurile de filtrare folosind atributul method="post". Desigur, e nenatural sa folosesc un POST pentru o cerere care nu altereaza nicio informatie de pe server, doar aduce date. Tot ce am scris mai sus este valabil si aici doar ca valorile campurilor vor fi transmise in BODY-ul pachetului HTTP si nu ca parametri in URL.

Pe client pot folosi acelasi helper MVC:

@Html.CheckBox("fStock",(bool)ViewBag.StockOnly) //ViewBag - o valoare returnata de server, utila pentru memorarea starii

iar pe server codul care actualizeaza ViewBag-ul se modifica doar prin modul de citire a parametrilor:

var fStock = Request.Form.GetValues("fStock"); //returneaza "true,false" pt. @Html.CheckBox bifat
if (fStock != null && bool.Parse(fStock[0]))
    ViewBag.StockOnly = true;
else
    ViewBag.StockOnly = false;

Inca odata, aceasta ultima solutie am prezentat-o doar cu scop informativ.

Alte informatii despre <input type='checkbox'>:

Considerente finale:

comments powered by Disqus