Skip to content
Advertisement

TypeError: this.$refs is not a function

So I have a problem with VueJs. I created a “Confirmation Dialogue” and added it to a On-Click-Event on buttons. It worked fine.

Now I tried to copy the implementation to add it to another button on a different parent. It says “TypeError: this.$refs.confirmDialogue.show is not a function” in the Console whenever I try to click the button. The other button still works completly normal.

Am I missing something? I already tried to remove the working button, so only one component uses the Confirm Dialogue but that also didn’t work.

I’m new to VueJs. Hope someone can help me with this problem.

Child PopupModal:

<template>
    <transition name="fade">
        <div class="popup-modal" v-if="isVisible">
            <div class="window">
                <slot></slot>
            </div>
        </div>
    </transition>
</template>

<script>
export default {
    name: 'PopupModal',

    data: () => ({
        isVisible: false,
    }),

    methods: {
        open() {
            this.isVisible = true
        },

        close() {
            this.isVisible = false
        },
    },
}
</script>

<style scoped>
/* css class for the transition */
.fade-enter-active,
.fade-leave-active {
    transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
    opacity: 0;
}

.popup-modal {
    background-color: rgba(0, 0, 0, 0.5);
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 0.5rem;
    display: flex;
    align-items: center;
    z-index: 1;
}

.window {
    background: #fff;
    border-radius: 5px;
    box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.2);
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
    padding: 1rem;
}
</style>

Parent ConfirmDialogue:

<template>
    <popup-modal ref="popup">
        <h2 style="margin-top: 0">{{ title }}</h2>
        <p>{{ message }}</p>
        <div class="btns">
            <button class="cancel-btn" @click="_cancel">{{ cancelButton }}</button>
            <span class="ok-btn" @click="_confirm">{{ okButton }}</span>
        </div>
    </popup-modal>
</template>

<script>
import PopupModal from "../confirmDialogue/PopupModal.vue"

export default {
    name: 'ConfirmDialogue',

    components: { PopupModal },

    data: () => ({
        // Parameters that change depending on the type of dialogue
        title: undefined,
        message: undefined, // Main text content
        okButton: undefined, // Text for confirm button; leave it empty because we don't know what we're using it for
        cancelButton: 'Abbrechen', // text for cancel button
        
        // Private variables
        resolvePromise: undefined,
        rejectPromise: undefined,
    }),

    methods: {
        show(opts = {}) {
            this.title = opts.title
            this.message = opts.message
            this.okButton = opts.okButton
            if (opts.cancelButton) {
                this.cancelButton = opts.cancelButton
            }
            // Once we set our config, we tell the popup modal to open
            this.$refs.popup.open()
            // Return promise so the caller can get results
            return new Promise((resolve, reject) => {
                this.resolvePromise = resolve
                this.rejectPromise = reject
            })
        },

        _confirm() {
            this.$refs.popup.close()
            this.resolvePromise(true)
        },

        _cancel() {
            this.$refs.popup.close()
            this.resolvePromise(false)
            // Or you can throw an error
            // this.rejectPromise(new Error('User cancelled the dialogue'))
        },
    },
}
</script>

<style scoped>
.btns {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

.ok-btn {
    padding: 0.5em 1em;
    background-color: #1F51FF;
    color: #fff;
    border: 2px solid #0ec5a4;
    border-radius: 5px;
    font-size: 16px;
    text-transform: uppercase;
    cursor: pointer;
}

.cancel-btn {
    padding: 0.5em 1em;
    background-color: #d5eae7;
    color: #000;
    border: 2px solid #0ec5a4;
    border-radius: 5px;
    font-size: 16px;
    text-transform: uppercase;
    cursor: pointer;
}
</style>

Working button:

            <td class="last-td last-row">
                <div class="button-wrapper">
                    <div class="wrapper-edit">
                        <button class="button button-edit">Bearbeiten</button>
                    </div>
                    <div class="wrapper-cancel">
                        <button class="button button-cancel" @click="doDelete">Löschen</button> <!-- Here is the working button -->
                        <confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
                    </div>
                </div>
            </td>
        </tr>
    </thead>
</template>

<script>
import ConfirmDialogue from '../confirmDialogue/ConfirmDialogue.vue'

export default {
    name: "bookingElements",

    components: { ConfirmDialogue },
    
    methods: {
        async doDelete() {
            const ok = await this.$refs.confirmDialogue.show({
                title: 'Buchung löschen',
                message: 'Sind Sie sicher, dass Sie die Buchung löschen wollen?',
                okButton: 'Buchung löschen',
            })
            if (ok) {
                alert('Die Buchung wurde Erfolgreich gelöscht')
            }
        },

Button that isn’t working:

            <td id="buttonCell">
                <button class="button" @click="doDelete">Buchen</button>
                <confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
            </td>
        </tr>
    </tbody>
</template>

<script>
import ConfirmDialogue from "../confirmDialogue/ConfirmDialogue.vue"

export default {
    name: "bookElements",

    components: { ConfirmDialogue },

    methods: {
        async doDelete() {
            const ok = await this.$refs.confirmDialogue.show({
                title: 'Buchung löschen',
                message: 'Sind Sie sicher, dass Sie die Buchung löschen wollen?',
                okButton: 'Buchung löschen',
            })
            if (ok) {
                alert('Die Buchung wurde Erfolgreich gelöscht')
            }
        },

Advertisement

Answer

I got found the mistake.

I created a for-each loop to create the Table. At the working button there was no for-each loop though.

So VueJs tried to generate the Confirmation Dialogue 9 times and this resulted to an error.

So I just need to put the

<confirm-dialogue ref="confirmDialogue"></confirm-dialogue>

to the top of Template like this

<template>
    <confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
    ...
</template>

because it’s vanished and only shows when the button is clicked.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement