středa 7. prosince 2011

“Vyber vše” aneb kombinace ASP.NET MVC a jQuery

V tomto článku popíši možné řešení zadání, podle kterého se má uživateli zobrazit seznam možností ve formě zaškrtávacího políčka, přičemž jedno ze zaškrtávacích políček má sloužit jako “Vyber vše” – pokud jej uživatel zaškrtne, zaškrtnou se všechny možnosti, pokud zaškrtnutí zruší, zruší se i všechny možnosti:
 image     image     image
Řešení podobného zadání jsou na netu mraky – takže k tomuto mraku přispěji dalším obláčkem.  Aby řešení bylo co nejvíce univerzální, stanovil jsem si tyto podmínky:
  • Všechny ovládané zaškrtávátka musí být uzavřeny do elementu <fieldset>
  • První zaškrtávátko slouží pro výběr všeho.

Obecné Html a javacript

Html kód splňující výše uvedené podmínky  pak vypadá takto:
<fieldset>
    <input type="checkbox" name="all" /><label for="all">Vyber ve</label><br /><br/>
    <input type="checkbox" name="praha" /><label for="praha">Praha</label><br />
    <input type="checkbox" name="brno" /><label for="brno">Brno</label><br />
    <input type="checkbox" name="ostrava" /><label for="ostrava">Ostrava</label>
</fieldset>
a odpovídající jQuery javascript pak takto:
selectAllCheckbox.js
  1. jQuery(function () {
  2.     jQuery('fieldset :checkbox').click(function () {
  3.         var $checkboxes = jQuery(this).closest('fieldset').find(':checkbox');
  4.         if ($checkboxes.index(this) == 0) {
  5.             $checkboxes.not(this).attr('checked', this.checked);
  6.         }
  7.         else {
  8.             $checkboxes.setSelectAllCheckbox();
  9.         }
  10.     });
  11.  
  12.     jQuery('fieldset').each(function () {
  13.         jQuery(this).find(':checkbox').setSelectAllCheckbox();
  14.     });
  15. })
  16.  
  17. jQuery.fn.setSelectAllCheckbox = function SetSelectAll() {
  18.     var first = this.first();
  19.     jQuery(first).attr('checked', this.not(first).filter(':checked').length == (this.length - 1));
  20. }
Metoda na řádcích 17.-20. nastaví předané ovládací zaškrtávátko buď do stavu zaškrtnuto a nebo nezaškrtnuto podle stavu ostatní zaškrtávátka (ovládací zaškrtávátko bude zaškrtnuto, pokud všechna ostatní jsou zaškrtnuta.
Kód na řádcích 2-10 zajišťuje, že při každém kliknutí na zaškrtávátko umístněné v elementu <fieldset> je zjištěno, zda se jedná o první zaškrtávátko v daném elementu. Pokud ano, nastaví se všechna ostatní zaškrtávátka podle stavu právě kliknutého (řádek 5.). Pokud ne, provede se funkce na řádcích 17. – 20.
Kód na řádcích 12. 15. slouží pro správná nastavení po načtení stránky do prohlížeče.
Upozorňuji, že kód není dokonalý, například neřeší důsledně situace, kdy je do sebe zanořeno více elementů fieldset.

Html helper method

Element <fieldset> nemusím generovat ručně. Můžeme použít rozšíření HtmlHelperu a použít tuto konstrukci v našem view. Tvorbu jednoduchých rozšíření nemá asi cenu popisovat, proto rovnou popíši něco o stupeň složitější, tedy konstrukci podobnou @using(Html.BeginForm….):
@using (Html.BeginSelectAllCheckbox())
{
    <input type="checkbox" name="all" /><label for="all">Vyber ve</label><br />
    @Html.CheckBox("Praha")<label>Praha</label><br />
    @Html.CheckBox("Brno")<label>Brno</label><br />
    @Html.CheckBox("Ostrava")<label>Ostrava</label>
}
Upozornění - je mi jasné, že v tomto případě se může hloubavému čtenáři zdát, že jde o přístup “s kanónem na vrabce”, ale chci na tomto jednoduchém příkladu demonstrovat tvorbu vlastních rozšíření – v některém z dalších příspěvků chci popsat složitější řešení a není tedy na škodu  začít jednoduchým příkladem.
Metoda BeginSelectAllCheckbox je pak statické metoda statické třídy, která vypadá takto:
public static class HelperExtension
    {
        public static IDisposable BeginSelectAllCheckbox(this HtmlHelper helper )
        {
            Action begin = () => {helper.ViewContext.Writer.Write("<fieldset>");};
            Action end = () =>    {helper.ViewContext.Writer.Write("</fieldset>");};

            return new DisposableHelper(begin, end);
        }
       
        private class DisposableHelper : IDisposable
        {
            private readonly Action end;

            public DisposableHelper(Action begin, Action end)
            {
                this.end = end;
                begin();
            }

            public void Dispose()
            {
                end();
            }
        }
    }
Tvorba vlastních rozšíření HtmlHelperu objektu v MVC tedy není složitá a princip je doufám z kódu patrný – díky using dojde kzavolání Dispose metody, která provede závěrečnou akci – zavolá metodu, kterou jsme při vytváření třídy definovali pomocí delegáta Action.
Přiložen je i ukázkový MVC projekt s veškerým kódem.

Žádné komentáře:

Okomentovat