Checkboxlist and (removing) hidden Inputs

Hey everybody,

I’m currently trying to render a checkboxlist with a individual layout. First of all, my data looks something like this on the database level: each row has an ID, a genre and a subgenre (it’s about music). The very first entry in the subgenre field for each genre is the genre itself… so it’s something like (1, Rock, Rock) (2, Rock, Alternative) and so on.

Now I wanna render a checkboxlist in which the first entry is on it’s own line (because it’s the overall genre) and all the subgenres on a new line, so ultimately something like this

[ ] Rock

----- [ ] Alternative [ ] Grunge

[ ] Electro

----- [ ] EDM [ ] House

I hope you get it… My current approach is to get an array such as [[Rock] => [Rock, Alternative, Grunge], [Electro] => [Electro, EDM, House] from my database with


$this->musicSubgenres = \yii\helpers\ArrayHelper::map(\app\models\Music::find()->all(), 'id', 'subgenre', 'genre');

After that, I render a separate checkboxlist, depending if it’s the first item in the values in the list above (the array above is saved in $model->musicSubgenres):




foreach($model->musicSubgenres as $genre) {

          // generate arrays for values and keys

          $subgenreValues = array_values($genre);

          $subgenreKeys = array_keys($genre);

          // echo first element as genre

          echo $form->field($model, 'music')->checkBoxList([$subgenreKeys[0] => $subgenreValues[0]])->label(false);

          // unset first element

          unset($subgenreKeys[0]);

          unset($subgenreValues[0]);

          // echo the rest as subgenres

          if(($count = count($subgenreValues)) > 0) {

            $result = [];

            for($i = 1; $i <= $count; $i++)

              $result[$subgenreKeys[$i]] = $subgenreValues[$i];

            echo $form->field($model, 'music')->checkBoxList($result, ['itemOptions' => ['uncheck' => false]])->label(false);

          }

        }



The main problem is, that each checkboxlist gets its own hidden input field so that all the values from the previous checkboxes are not in my $_POST. Anybody knows a better solution or how to disable the rendering of the hidden inputs? I also already tried solving it with the per ‘item’ => function(), but this generates the problem of having the right boxes checked on update.

Thanks in advance

Hey guys,

I think I figured it out, so I assumed I’ll just share my solution in case anybody else runs into a similar problem. I reverted back to using the anonymous as part of the “options” array with the “item” key.

First, here’s my view. I tried to add some explanatory comments




        // $this->musicSubgenres is a list of all subgenres

        echo $form->field($model, 'music')->checkBoxList($model->musicSubgenres, [

              'item' => function($index, $label, $name, $checked, $value) {

                  // get all genres

                  $genres = \app\models\Event::getGenres();

                  // set the last subgenre for the closing div tag

                  $lastSubgenre = \app\models\Event::getLastSubgenre();

                  // boolean to see if the current label is in the genres array

                  $bool = in_array($label, $genres);

                  // beginning tags for the genre div or the subgenre divs in the next row

                  if($label === $genres[0])

                    $divBegin = $bool ? '<div class="test">' : '';

                  else

                    $divBegin = $bool ? '</div><div class="test">' : '';

                  // closing div tag

                  if($label === $lastSubgenre)

                    $divEnd = '</div>';

                  else

                    $divEnd = $bool ? '</div><div class="test2">' : '';

                  // checked value

                  $checkedval = $checked ? 'checked' : '';

                  return "$divBegin<label><input type='checkbox' name='$name' value='$value' $checkedval>$label</label>$divEnd";

              }

        ]);



Furthermore, I defined these two static functions that can be accessed in the anonymous function:




/**

     * Returns all genres defined in the Music table

     * @return array

     */

    public static function getGenres() {

      $tmp = \yii\helpers\ArrayHelper::map(\app\models\Music::find()->all(), 'id', 'subgenre', 'genre');

      return array_keys($tmp);

    }


    /**

     * Returns the last subgenre in the Music table

     * @return string

     */

    public static function getLastSubgenre() {

      return end(\yii\helpers\ArrayHelper::map(\app\models\Music::find()->all(), 'id', 'subgenre'));

    }



And that’s all there is… Just set the $model->music and the $model->musicSubgenres attribute before rendering the view, and you’re set. Don’t know if it doesn’t have any bugs yet, but on first impression it seems to work.

Cheers!