Search code examples
shopwareshopware6

How to use <sw-entity-single-select> correctly?


I use a <sw-entity-single-select> component like this:

<sw-entity-single-select
    entity="sales_channel"
    v-model="setting.salesChannels"
    @change="selectSalesChannel"
>
</sw-entity-single-select>

salesChannels in my entity has this Definition:

(new ManyToManyAssociationField('salesChannels', SalesChannelDefinition::class, CustomSettingSalesChannelDefinition::class, 'custom_setting_id', 'sales_channel_id'))->addFlags(new ApiAware(), new CascadeDelete()),

When I select a SalesChannel inside setting.salesChannels I have the ID of the selected entity. I know that I use a ManyToMany Field here, but only a single select and not a multi select in my component. I want it that way, because most likely I need to enhance it to a multi select in the future.

So this works, I can save the custom entity and the relation to the SalesChannel is set - I do not do this with the repository in JS, but with PHP and a custom controller like this:

'salesChannels' => [
    [
        'id' => $setting->getSalesChannels()
    ]
],

My issue is now, that when I use the same UI/Component to edit an item, I get the Objects from the Database, but I need the Ids in v-model to pre-fill the selected item in the entity-single-select component.

When I do this, the item is pre-filled and selected. However when I want to save my custom entity - and here I do not use the same php logic as above, but the repository pattern in Vue - then it does not work and I get JS errors like this:

draft.has is not a function or some failure with draft.forEach

When I do not use the ID in setting.salesChannels but the Object which comes from the database and save the custom entity, it works. But the item is not pre-filled in the select component.

So the component needs the IDs to pre-fill the item, but the object to save it?

How can I solve this - or where is my mistake? Thanks for any help!


Solution

  • In your component you could have a computed property that slices of the first id of your sales channel collection for providing the value of the entity select. In the change listener you then create a collection and add the one item selected. You also won't need the server side workaround that way.

    const { EntityCollection } = Shopware.Data;
    
    // ...
    
    computed: {
        salesChannelId() {
            if (!this.setting.salesChannels.length) {
                return null;
            }
    
            return this.setting.salesChannels.first().id;
        }
    },
    methods: {
        selectSalesChannel(id, item) {
            const collection = new EntityCollection('/sales_channel', 'sales_channel', Shopware.Context.api);
    
            if (item) {
                collection.add(item);
            }
    
            this.setting.salesChannels = collection;
        }
    }
    
    <sw-entity-single-select
        entity="sales_channel"
        :value="salesChannelId"
        @change="selectSalesChannel"
    >
    </sw-entity-single-select>