Shopware 6: Events in Administration

Another day another funny story. I updated a plugin from 6.4 to 6.5 and one of the requirement was to update the backend view on order save.

First try: this.$root.$on

On the sw-order-detail plugin the onSaveEdits method emits an event on the root node. Many events on the shopware administration are emitted on the component itself, that means you need to access the component to register a subscriber to do anything.

This looks for example like this:

this.$emit('save-edits');

But as already said, in our case we have the luck, that the event is dispatched on the root component:

this.$root.$emit('order-edit-save');

To register a subscriber, you call $on(event, function) method on the component and as already explained, in this case on the root component:

this.$root.$on('order-edit-save', this.runAMethod);

But it didn’t work. After looking into the method, my assumption is, that the event fires too early.

async onSaveEdits() {
    this.isLoading = true;

    // change new order address
    if (this.orderAddressIds?.length) {
        await Promise.all([
            ...this.orderAddressIds
                .filter(ids => ids.orderAddressId !== ids.customerAddressId)
                .map(ids => this.changeOrderAddress(ids)),
        ]).then(() => {
            State.commit('swOrderDetail/setOrderAddressIds', false);
        }).catch((error) => {
            this.createNotificationError({
                message: error,
            });
        });
    }

    this.orderRepository.save(this.order, this.versionContext)
        .then(() => {
            this.hasOrderDeepEdit = false;
            return this.orderRepository.mergeVersion(this.versionContext.versionId, this.versionContext);
        }).catch((error) => {
            this.onError('error', error);
        }).finally(() => {
            State.commit('swOrderDetail/setVersionContext', Shopware.Context.api);

            return this.createNewVersionId().then(() => {
                State.commit('swOrderDetail/setLoading', ['order', false]);
                State.commit('swOrderDetail/setSavedSuccessful', true);
                this.isLoading = false;
            });
        });

    this.$root.$emit('order-edit-save');
},

This happens, because the Promise of this.orderRepository.save is evaluated after the AJAX call is done – and this happens maybe before, maybe after the $emit.

State.watch

Looking into the onSaveEdits, another idea was to listen on the commit. Thanks to free ChatGPT 3.5 I fiddled out, how this can work. This is how my subscriber looks like:

State.watch(
    (state) => state.swOrderDetail.savedSuccessful,
    (newValue, oldValue) => {
        if (newValue === true) {
            console.log('Saved!');
        }
    }
);

But only once!?

While testing, we recognized, that this does only work once – but why? Because commit() only triggers the subscriber when the value changes. And as you can see in the above method, the state is only changed to true, but is never reset to false. I’m not sure wether this is a bug or intended, but I opened an issue for it.

Fix to make it work always

To run our code every time the order is saved, we need to reset the state.

const {State} = Shopware;

Shopware.Component.override('sw-order-detail', {
    methods: {
        async onSaveEdits() {
            State.commit('swOrderDetail/setSavedSuccessful', false);
            await this.$super('onSaveEdits');
        }
    }
});

One thought on “Shopware 6: Events in Administration

Leave a Reply

Discover more from Winkelwagen

Subscribe now to keep reading and get access to the full archive.

Continue reading