1

I need to find a way to set the default values of a select-type field which has the multiple attribute.

Here is the data sent to the view through the controller:

$categories = [
    ['id' => 1, 'description' => 'Hardware'],
    ['id' => 2, 'description' => 'Sofware'],
    ['id' => 3, 'description' => 'Peopleware'],
    ['id' => 4, 'description' => 'Alienware'],
];
$selectedCategoriesIds = [1, 3];
$this->set(compact('categories', 'selectedCategoriesIds'));

And the view looks like this:

<select name="categories[_ids][]" multiple="multiple">
    <?php foreach ($categories as $category): ?>
    <option value="<?= $category->id ?>"<?= (in_array($category->id, $selectedCategoriesIds) ? 'selected' : '') ?>><?= $category->description ?></option>
    <?php endforeach; ?>
</select>

This is the HTML generated in the view:

    <select name="categories[_ids][]" multiple="multiple">
        <option value="1" selected>Hardware</option>
        <option value="2">Software</option>
        <option value="3" selected>Peopleware</option>
        <option value="4">Alienware</option>
    </select>

Everything works perfectly, my question is whether I can get this same result using CakePHP's FormHelper so I don't need to iterate over $categories and make a call to in_array() inside the view. I already consulted the Cookbook but I didn't find anything, or didn't understand how to do it in this specific case. I assume it would be something like:

<?= $this->Form->control('categories._ids', ['some params']) ?>

Thank you.

Andy Hoffner
  • 3,267
  • 2
  • 21
  • 22
godzill4
  • 25
  • 5

1 Answers1

0

You should be able to use the form class if your $categories array is structured a little differently. The Cookbook has an example here:

// HTML <option> elements with values 1 and 3 will be rendered preselected
echo $this->Form->select(
    'rooms',
    [1, 2, 3, 4, 5],
    [
        'multiple' => true,
        'value' => [1, 3]
    ]
);

First, just map $categories to a simpler mapped list of the Category id's => descriptions.

If this category list was data from a database, just select it with 'list' instead of the default method, ex:

$categories = $CategoriesTable->find('list');

But, if it's not from a Query result, you can still manually convert your array:

$categories = [
    ['id' => 1, 'description' => 'Hardware'],
    ['id' => 2, 'description' => 'Sofware'],
    ['id' => 3, 'description' => 'Peopleware'],
    ['id' => 4, 'description' => 'Alienware'],
];

$formattedCategories = [];
foreach($categories as $row){
    $formattedCategories[$row['id']] = $row['description'];
}
$categories = $formattedCategories;

Once in this format, the regular Form->select will work:

echo $this->Form->select(
    'categories[_ids][]',
    $categories,
    [
        'multiple' => true,
        'value' => $selectedCategoriesIds
    ]
);
Andy Hoffner
  • 3,267
  • 2
  • 21
  • 22
  • your example generated the option tags like this: , but what I need is like this: . I need the description in the content (.innerHTML) of the option tag and the id in the value attribute. Thanks for answering. – godzill4 May 07 '20 at 17:04
  • I just tested my code again and it generated the HTML you need, here's what I'm seeing: `` Are you getting different results? – Andy Hoffner May 07 '20 at 17:15
  • $CategoriesTable->find('list') return only ids, i replaced with $CategoriesTable->find('all', ['fields' => ['id', 'description']) and it worked! – godzill4 May 07 '20 at 18:42
  • Ah perfect! You can also just change the default "display field" in the CategoriesTable, it frequently defaults to ID. Inside the `initialize` function, ensure it says `$this->setDisplayField('description');` - this is what find('list') returns. – Andy Hoffner May 07 '20 at 18:48