Issue encountered while developing custom Vuejs + Typescript plugin

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

https://i.sstatic.net/Oh3Gq.png

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.

https://i.sstatic.net/nDKFB.png

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

When the property "a" is set to true, it must also require the properties "b" and "c" to be included

I'm looking for a way to modify the following type structure: type Foo = { a: boolean; b: string; c: string; } I want to change it so that if a is true, then both b and c fields are required. However, if a is false or undefined, then neither b ...

Receiving contextual information from Microsoft Teams within an Angular application integrated as a tab

I am currently integrating an Angular website into a Microsoft Teams tab. In order to perform certain computations, I need to retrieve the Team ID. To achieve this, I have recently added npm install --save @microsoft/teams-js. Below is the code snippet th ...

There is no matching signature for Type when using withStyles

Struggling to convert my React App to typescript, I keep encountering the error below and cannot decipher its meaning. The app functions perfectly in plain JS. My package version is material-ui@next TS2345: Argument of type 'typeof ApplicationMenu&a ...

Tips for creating a worldwide shop Object?

Working with vueify and browserify, I have created an object in my main.js file var store = { foo: 'bar' }; var vm = new Vue({ el: '#app', data(){ return { foo: store }; }, components: { Login, Registration, ...

The select() function for this.$refs.name is not available in Vue

In my application, I'm implementing Vue refs to enable selecting and copying text when a button is clicked. The code structure looks something like this: //In template <input type="text" ref="url" value="my url"/> <button @click="copylink"&g ...

Modify the dynamic style of an Angular input field

Looking for assistance with a text box <input type="text" [ngStyle]="(show_div===true) ? {'border-color':'red','color':'red'} : {'border-color': 'green','color':'g ...

Setting a default value for a data type within Typescript

My goal is to set default values for all properties in my custom type if they are not defined. This is what I have done: // custom type with optional properties type MyType = { // an example property: str?: string } // with numerous properties, assign ...

Is it recommended for TypeScript to automatically resolve the index.ts file as the default module file?

Struggling with getting the module resolution to work in TypeScript. Consider the following file structure: /modulename/index.ts Should it be resolved like this? import * as modulename from "modulename" I can't seem to make it work. However, imp ...

What is the best method to extract the values of objects in an array that share

var data= [{tharea: "Rare Disease", value: 3405220}, {tharea: "Rare Disease", value: 1108620}, {tharea: "Rare Disease", value: 9964980}, {tharea: "Rare Disease", value: 3881360}, ...

How can a component be built into a library using vue-cli and then imported?

Using the vue-cli, I build my lib with the following command: "build": "vue-cli-service build --target lib --name myLib ./src/component.vue", After the build, how do I import my component from the dist folder? I've attempted the following: // und ...

The Typescript compiler will continue to generate JavaScript code even if there are compilation errors

As a fresh learner of TypeScript, I have been experimenting with some basic concepts. Below is the code from my file app1.ts: class Monster { constructor(name, initialPosition) { this.name = name; this.initialPosition = initialPosition ...

What is the TypeScript equivalent of the Java interface.class?

Can you write a Java code in TypeScript that achieves the same functionality as the code below: Class<?> meta = Object.class; and meta = Processor.class; // Processor is an interface In TypeScript, what would be the equivalent of .class? Specifica ...

Setting up Vue.js API endpoints

I'm a newbie in VueJS, and I recently started using RxJS, Vue rx, and Vue Resource in a mixin to facilitate making HTTP calls and receiving observables anywhere... it's fantastic! Now, I decided to experiment with the following code: subscripti ...

Automatic switching of icon position from left to right occurs when the position:absolute property is removed

Currently I am utilizing the tooltip feature provided by Vuetify. The span message is displayed as shown in image 1 below. After examining the CSS, I adjusted .tooltip__content { position: absolute; } to .tooltip__content {position: relative;}. Howe ...

Launching the Skeleton feature in NextJS with React integration

I have been working on fetching a set of video links from an Amazon S3 bucket and displaying them in a video player component called HoverVideoPlayer. However, during the loading process, multiple images/videos scale up inside a Tailwind grid component, ca ...

What is the best way to enforce input requirements in Typescript?

I am currently facing an issue with two required inputs that need to be filled in order to enable the "Add" button functionality. I have considered using *ngIf to control the visibility of the button based on input values, but it seems to not be working. ...

Unable to retrieve data in Vue using Axios for GET request

Recently delving into Vue, I'm struggling to figure out what's causing the issue in my code. Here's a simple component snippet: <template> <template v-if="loading"> Loading... </template> <te ...

Helping React and MUI components become mobile responsive - Seeking guidance to make it happen

My React component uses Material-UI (MUI) and I'm working on making it mobile responsive. Here's how it looks currently: https://i.sstatic.net/kxsSD.png But this is the look I want to achieve: https://i.sstatic.net/kJC2m.png Below is the code ...

Transfer information(text) to the clipboard using Vue (Nuxt js)

When the vs-button is clicked, I want the value of single_download_link.pdfId to be copied to the clipboard. I attempted it like this, but it did not work. I do not want to use the v-clipboard node module. Can someone please assist me with this? Thank you. ...

Challenges with date formatting arise for Spanish speakers when the date returns as NaN or an Invalid

I have been working on an Angular app Objective: My aim is to allow users to input dates in Spanish format (DD/MM/YYYY) and display them as such, while converting them back to English format when saving the data to the Database. Issue: One problem I enco ...