Issue encountered while developing custom Vuejs + Typescript plugin

In my index.ts and service plugin files, I have this structure:

service.ts

declare interface Params {
  title: string;
  description?: string;
  type?: string;
  duration?: number;
}

export default class ServiceToast {
  public toastRef: any; // component

  public constructor(modalRef: any) {
    this.toastRef = modalRef;
    console.log(this.toastRef);
  }

  public open(params: Params) {
    this.toastRef.open(params);
  }
}

I have created a service that interacts with the component easily by receiving it as a parameter.

index.ts:

import _Vue from 'vue';
import Toast from '@/components/_includes/layouts/Toast.vue';
import ServiceToast from './service';

const ToastPlugin = {
  install: (Vue: typeof _Vue, options?: any) => {
    Vue.mixin({
      created() {
        Vue.prototype.$toast = new ServiceToast(Toast);
      },
    });
  },
};

export default ToastPlugin;

In this setup, I install the plugin and use the service mentioned above.

When I try to call the plugin in any component using:

<a @click="$toast.open({ title: 'Hola mundo' })">Click me for a greeting!</a>

I encounter the error message: "TypeError: this.toastRef.open is not a function"

In the shims-vue-plugin.d.ts file:

/* eslint-disable */
import Vue from 'vue';
import { AxiosInstance } from 'axios';
import 'webpack-env';
import { FieldFlagsBag } from 'vee-validate';
import { SnackbarProgrammatic as Snackbar, DialogProgrammatic as Dialog } from 'buefy';
import ServiceToast from './app-config/toast/service';

declare module 'vue/types/vue' {
  interface Vue {
    $auth: any;
    $axios: AxiosInstance;
    veeFields: FieldFlagsBag;
    $dialog: typeof Dialog;
    $snackbar: typeof Snackbar;
    $toast: ServiceToast;
  }
}


declare namespace NodeJS {
  interface Process extends __WebpackModuleApi.NodeProcess {
    server: boolean;
  }
}

Can anyone help me identify what might be causing this error or if there's something missing? I've been unable to resolve it:/

Answer №1

this.$toast in any component is not going to be an instance of Toast.vue. It's the export. To actually have an instance, you must call $mount():

import _Vue from 'vue'; 

// create a class
const ToastClass = _Vue.extend(this.$toast.toastRef);

// get an instance of the class
const instance = new ToastClass();

// mount it
instance.$mount();
// now you can use its methods, for example: 
// instance.open();
// however, it's not yet appended to the DOM. To append it to the current component:

this.$el.appendChild(instance.$el);

I am not sure what your goal is, but having an instance of a component in every single one of your app's components may not be ideal. Each toast instance will also have its own this.$toast. Toast-ception :)

You might consider keeping an array of toasts in $store and a container attached to your app's root element, with something like:

<toast v-for="toast in toasts" />

Remove expired toasts from the state when needed.
Just add a new one by pushing it to the array.

Answer №2

After following tao's solution, the code now looks like this:

import _Vue from 'vue';
import Toast from '../../components/_includes/layouts/Toast.vue';
import ServiceToast from './service';

export default {
  install: (Vue: typeof _Vue, options?: any) => {
    const toastComponent = new Toast();
    Vue.mixin({
      created() {
        Vue.prototype.$toast = new ServiceToast(toastComponent);
      },
      mounted() {
        const el = document.createElement('div');
        document.body.append(el);
        toastComponent.$mount(el);
      },
    });
  },
};

Everything is working perfectly now :)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having difficulty in utilizing localStorage to update the state

I've attempted to log back in using the stored credentials, however it's not working despite trying everything. The dispatch function is functioning properly with the form, but not when accessing localStorage. App.tsx : useEffect(() => { ...

Display an input field in VueJS with a default value set

Dealing with a form containing various editable fields, I devised a solution. By incorporating a button, clicking it would conceal the label and button itself, while revealing a text box alongside a save button. The challenge lays in pre-filling the textbo ...

Is it planned to include StencilJS as a development choice in Ionic?

I'm curious about the potential adoption of Stencil JS for developing mobile apps within the Ionic framework. When I mention "an option for developing," I'm referring to frameworks like NativeScript where developers can choose between Angular + ...

What is the best way to retrieve an empty instance using a getter in Vuex?

My store has a default setting that returns undefined for a specific attribute: // store.js export const state = { locationLoading: false, locationsLoading: false, locations: [], location: undefined, <-- }; In my component, I am utiliz ...

What is the best way to add an element from a parent component to an array within a child component in a Vue 3 application?

I am in the process of transitioning from Vue's Options API to the Composition API, and as part of this transition, I have built a small Todo App. Within App.vue, my code looks like this: <template> <div id="app"> <div ...

Angular 5 is throwing an error that says: "There is a TypeError and it cannot read the property 'nativeElement' because it

Being aware that I may not be the first to inquire about this issue, I find myself working on an Angular 5 application where I need to programmatically open an accordion. Everything seems to function as expected in stackblitz, but unfortunately, I am enco ...

Is there a way to access the rootPath or other client-side information from the language server side?

I'm currently developing a language extension based on the example "language server" available at https://code.visualstudio.com/docs/extensions/example-language-server. In order to determine the current folder being used by vscode on the server side, ...

Do Typescript interfaces check method parameters for validation?

interface optionsParameter { url: string; } function DEC(options: optionsParameter){ } DEC(2) //typescript check compilation error let obj:any = { name: "Hello" } obj.DEC = function(options: optionsParameter){} obj.DEC(1); // no compilation ...

Exploring Vue and Webpack: Optimizing global variables for development and production environments

I have been using vue-cli to create my web application. Throughout the app, I am making use of an API by including it in various places like this: axios.post(API + '/sign-up', data).then(res => { // do something }); The API variable is a c ...

Vue JS: Uncaught TypeError - Unable to access property 'preventDefault' as it is undefined

When using v-model in my input field, I encountered an error stating preventDefault of undefined. What could be causing this issue? This is the code snippet from my AddUser component: <template> <form @submit="onSubmit()"> ...

Running a method at any given time within an ngFor loop in Angular 5

On my angular page, I am facing a challenge with updating a variable and displaying it in the HTML within an *ngFor loop. Here is an example of what I need: HTML: <table *ngFor="let data of Dataset"> somehowRunThis(data) <div>{{meth ...

I am facing an issue with the asynchronous function as it is displaying an error message

**I am facing an issue with displaying categories. I have attempted to do this using async function, however the data is not showing up** <div class="form-group"> <label for="category">Category</label> <select id="categor ...

VueJs and Vuetify come together in perfect harmony in the V-select outlined component

I am new to using VueJS and Vuetify. I have noticed that with v-select outlined, the label is not directly on the border of the field. Instead, I have to click in the field first before it appears. Can anyone explain why this is happening? Here is my code ...

Managing multiple asynchronous requests through Observables in web development

I am working on an Angular2 website that sends multiple ajax requests using Json Web Tokens for authorization when it is initialized Here are two examples: public getUser(): Observable<User> { // Code block to get user data } public getFriends ...

Position the text alongside the thumbnail rather than in the center

In the current setup, my username text is positioned in the center of the view. I want to reconfigure it so that it displays directly to the right of the thumbnail. However, removing the alignItems: 'center', property from the item disrupts the e ...

Which directories and files are necessary in a Laravel project when using Vue and Vuetify?

Recently, I've been delving into the world of Laravel, Vue, and Vuetify in an attempt to broaden my skills. However, despite my best efforts, I have struggled to find a comprehensive guide that actually works for installing these technologies successf ...

Create duplicates of both the array and its individual elements by value

I'm having trouble figuring out how to properly copy an array along with all its elements. In my model, I have a name and options, both of which are strings. This is what I currently have: const myArrayToDuplicate = [myModel, myModel, myModel] My ...

Unable to dynamically attach a class in Vue.js

I have exhausted all possible variations of this issue. I meticulously followed the official Vue guides, consulted numerous stack overflow posts, and went through various tutorials. I experimented with different syntaxes, quotations, array structures, and ...

Warning in TypeScript: TS7017 - The index signature of the object type is implictly assigned as type "any"

An alert for TypeScript warning is popping up with the message - Index signature of object type implicitly has any type The warning is triggered by the following code block: Object.keys(events).forEach(function (k: string) { const ev: ISumanEvent ...

include the ReactToastify.css file in your project using the import statement

Error in file path C:\Users\User\Documents\GitHub\zampliasurveys_frontend\node_modules\react-toastify\dist\ReactToastify.css:1 ({"Object.":function(module,exports,require,__dirname,__filename,jest){:ro ...