magento2: Using a multiselect product attribute with a custom source model in the adminhtml doesn't render selected value.
Preconditions
Magento 2.4-develop
Issue Description
I’ve created a custom source model to use as a product attribute of the type ‘multiselect’. The Source model extends Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
and it shows up just fine. Saving the entities also work: the value gets stored in the database.
However, when the product page is loaded in the adminhtml, the proper values or not re-selected. I’ve tracked this down to the JavaScript configuration used for the attribute. If I create a multiselect product attribute from the adminhtml, I see in the JSON that the value of the options are strings:
{"value":"4","label":"Foo"},{"value":"5","label":"Bar"}
However, the values of my custom source model are rendered as integers:
{"value":4,"label":"Foo"},{"value":5,"label":"Bar"}
I’ve debugged the JavaScript by setting breakpoints in the inspector and everything is parsed correctly. That is: the values from the database are passed through to Magento. The only difference is the value
in the JavaScript object:
So I’m guessing that when you use custom source models, the values are not passed as strings, causing Knockout to not set the proper values
Steps to reproduce
1. Generate a custom EAV source model.
For example:
use Magento\Customer\Api\GroupManagementInterface;
/**
* Class CustomerGroup
*/
class CustomerGroup
extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
implements \Magento\Framework\Option\ArrayInterface
{
/**
* @var GroupManagementInterface
*/
protected $groupManagement;
/**
* CustomerGroup constructor.
* @param GroupManagementInterface $groupManagement
*/
public function __construct(
GroupManagementInterface $groupManagement
)
{
$this->groupManagement = $groupManagement;
}
/**
* @return array
*/
public function toArray()
{
$groups = [];
foreach ($this->groupManagement->getLoggedInGroups() as $group) {
$groups[$group->getId()] = $group->getCode();
}
return $groups;
}
/**
* Options getter
* @return array
*/
final public function toOptionArray()
{
$arr = $this->toArray();
$ret = [];
foreach ($arr as $key => $value) {
$ret[] = [
'value' => $key,
'label' => $value
];
}
return $ret;
}
/**
* Get options in "key-value" format
* @return array
*/
public function toArray()
{
return [];
}
/**
* @return array
*/
public function getAllOptions()
{
return $this->toOptionArray();
}
}
2. Create a product attribute and set the source model in the database to your custom source model.
3. Add it to an attribute set and save a product with some values
- Check the database: values are stored.
- Reload the product detail page: options are not selected, although they are present in the JS configuration / Knockout
It could be that I’m missing a step here with custom source models, but this always works with select
-elements, but multiselect
works different.
Actual Result:
values of my custom source model are rendered as integers
Expected Result:
values of my custom should be rendered as a string
Update:
I’m currently able to fix this by making sure that the toOptionArray()
-method of my source model always returns a string:
/**
* Options getter
* @return array
*/
final public function toOptionArray()
{
$arr = $this->toArray();
$ret = [];
foreach ($arr as $key => $value) {
$ret[] = [
// Always return a string:
'value' => (string) $key,
'label' => $value
];
}
return $ret;
}
However, in my opinion this issue can still be considered a bug, because for semantics it’s very strange I have to force my ID’s (which are integers) to strings, just to get the Knockout multiselect component working.
Besides that, I have no idea what other things might break from this ‘fix’, since source models are broadly accepted and it might throw exceptions when an integer is expected.
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 3
- Comments: 18 (10 by maintainers)
Is there any news or at least some confirmation on this ticket?