I am a beginner in Vue.js and so this question might be duplicate or naive. I want to call functions defined in a custom javascript file within a Vue component. I did something like this.
custom.js
class API{
function testCall(){
alert("test ok");
}
}
export {API}
App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<testcomponent :on-click="getData">
</testcomponent>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
import TestComponent from './components/TestComponent.vue';
import API from './js/custom.js';
export default {
name: 'app',
components: {
HelloWorld,
TestComponent,
API
},
methods: {
getData(){
const apiObj = new API();
apiObj.testCall();
}
}
}
</script>
When I build using npm run build, I get below error.
Any help with this please?
1: To define methods in a class you do not need function keyword.
class API{
testCall(){
alert("test ok");
}
}
2: Since you are doing a named export using export {API}, your import statement should be
import {API} from './js/custom.js';
3:components options is for registering vue components locally. Since API is not a vue component remove it from the components option.
API is not a Vue component - you should not include it inside the components branch. Also, if this is just a bunch of utility functions you can either export them one by one or as a containing object
// util.js - individual functions
export function testCall (call) {};
export function testUser (user) {};
// Vue app
import { testCall, testUser } from 'util.js';
// util.js - object group
function testCall (call)
{
}
function testUser (user)
{
}
export default
{
testCall,
testUser
}
// Vue app
import API from 'util.js';
Related
I am using vue 2.6.14 + composition-api 1.6.2
I want to upgrade the app as vue 2.7 (surely, remove composition-api)
I am using two repositories,
one is the main and the other is UMD library.
(both use vue, vue-cli)
The problem is, it looks like there is no active instance at UMD library.
Please look below codes
// repo B(the UMD library) > someComponent.vue
<template>
...
</template>
<script>
import { getCurrentInstance } from 'vue';
export default {
...
setup() {
const vm = getCurrentInstance();
console.log(vm); // <- null
...
onMounted(...); // <- [Vue warn] onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().
}
}
// repo A(the main) > somePage.vue
<template>
...
<someComponent>...</someComponent>
</template>
<script>
import { getCurrentInstance } from 'vue';
import { someComponent } from '#some-company/design-system';
...
export default {
...
components: {
someComponent
},
setup() {
const vm = getCurrentInstance();
console.log(vm); // <- VueComponent (It works well!)
...
onMounted(...); // No warning has logged (It works well!)
}
}
Thanks for your answer.
I need to create a component in Vue JS dynamically on click and then route to that component. I am using Vue 3. Everything needs to happen in one click.
My code looks something like this
methods:{
routerClick(value){
console.log("number is "+value)
this.$router.push({path:'New', name:'New', component: ()=>Vue.component('New')})
}
},
I do not need to move a component that is already created. I want to create a component inside this method and then route to the component using this router. Please, any suggestions will be highly appreciated.
Below is a simplistic solution that works (I'm not an expert in Vue 3).
The main point is to use addRoute before pushing to it, because you cannot specify the route component when pushing to a route.
Here is the codesandbox with the working solution.
<template>
<router-link to="/">Home</router-link>
<button #click="createComponent">Create Component</button>
<router-view></router-view>
</template>
<script>
import { getCurrentInstance } from "vue";
import { useRouter } from "vue-router";
export default {
name: "App",
setup() {
const app = getCurrentInstance().appContext.app;
const router = useRouter();
const createComponent = () => {
// Check if the component has been alreadey registered
if (!app.component("NewComponent")) {
app.component("NewComponent", {
name: "NewComponent",
template: `<div>This is a new component</div>`
});
}
const newComponent = app.component("NewComponent");
// Adding a new route to the new component
router.addRoute({ path: "/new", component: newComponent });
router.push("/new");
};
return {
createComponent,
};
},
};
</script>
I have the following structure:
src
components
Footer.vue
views
Page.vue
App.vue
I would like to be able to access the 'message' variable in App.vue, but I can´t figure out how to do it when Footer.vue is not a direct child of App.vue (but child of Page.Vue which - via the router - is child App.vue).
What do I need to add in my files? There are now as follows - and (of course) no message appears in App.vue:
//App.vue
<template>
<p>Message is: {{ message }}</p>
<router-view />
</template>
<style lang="scss">
#import "./_scss/main.scss";
</style>
.
//Page.vue
<template>
<Footer/>
</template>
<script>
import Footer from '#/components/Footer.vue'
export default {
components: {
Footer
}
}
</script>
.
//Footer.vue
<template>
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
</template>
<script>
export default {
data() {
return {
message: ''
}
}
}
</script>
Maybe Composition API and ES6 modules?
#/compositions/composition.js
import { ref } from 'vue'
const message = ref('test');
export const useComposition = function() {
// other functions, for example to mutate message ref
return {
message,
// ...
}
}
And now you import your composition in the components that need to access message:
// Footer.vue, App.vue
<script>
import { defineComponent } from 'vue'
import { useComposition } from '#/compositions/composition'
export default defineComponent({
setup() {
const { message } = useComposition();
return { // make it available in <template>
message
}
},
})
</script>
If you want to quickly get started with Composition API, see this.
I have a components folder in nuxt.js
/components/atoms/
and inside that folder I have an index.js to export all components dynamically
const req = require.context('./', true, /\.vue$/)
const components = {}
req.keys().forEach(fileName => {
const componentName = fileName.replace(/^.+\/([^/]+)\.vue/, '$1')
components[componentName] = req(fileName).default
})
export const { ButtonStyled, TextLead, InputSearch } = components
so I can import perfectly as I wish
import { ButtonStyled } from "#/components/atoms"
the problem is that I am defining the variables to be exported statically, fixed, so for each created component I would need to add another variable manually
I need to dynamically export the variable name
Example:
DynamicCreation = ['ButtonStyled', 'TextLead', 'InputSearch']
export const { DynamicCreation } = components
// output -> export const { ButtonStyled, TextLead,InputSearch } = components
I need to export the name of already unstructured variables
Note: I can not use this export default components because I can not import like this import { ButtonStyled } from "#/components/atoms"
You should be able to do it like this:
export default components
Then in your file where you want to use the components:
import * as components from '#/components/atoms'
Then when you need to use the components in your Vue files, you need to map them:
#Component({
components: {
ButtonStyled: components.ButtonStyled
}
})
And now you have:
<ButtonStyled></ButtonStyled>
You can make something like this way, check if is what do you need.
Create a file to import a conjunct of components: allComponents.js
export default {
componentOne: require('./passToOneComponent.js');
componentTwo: require('./passToOneComponent.js');
componentThree: require('./passToOneComponent.js');
}
After in index.js export the allComponents.js with the name that you wish:
export {default as SomeName } from 'allComponents.js';
So in the final file, you can make something like:
import { SomeName } from 'index.js';
SomeName.componentOne();
I created a library that does this type of export, anyone who wants can install via npm
I created a Webpack Plugin that makes named exports from a component, maybe this helps other people
Weback Plugin - named-exports
I'm working with typescript and vue.
In my app there is a service which is a global for every sub component.
I found this native vue solution on vue JS to inject this property on the child components.
on main.ts
const service = new MyService(...);
new Vue({
router,
provide() { return { service }; } // provide the service to be injected
render: h => h(App),
}).$mount("#app");
on any typescript vue component
import Vue from "vue";
export default Vue.extend({
inject: ["service"], // inject the service
mounted() {
console.log(this.service); // this.service does exists
},
});
This way I'm able to get the injected service on my Child components.
However I'm getting the fallowing error
Property 'service' does not exist on type 'CombinedVueInstance < Vue, {}, {}, {}, Readonly < Record < never, any > > >'.
How can I solve this typescript compilation error?
You don't need to use class components in order to get this. For object component declaration you have two ways of doing it:
Patching data return type
export default {
inject: ['myInjection'],
data(): { myInjection?: MyInjection } {
return {}
},
}
The downside is that you'll have to mark it as optional to be able to add it do data return.
Extending Vue context
declare module 'vue/types/vue' {
interface Vue {
myInjection: MyInjection
}
}
export default {
inject: ['myInjection'],
}
Using plugins
If you whant to use some service in all Vue components, you can try to use plugins.
In main.ts you just import it:
import Vue from "vue";
import "#/plugins/myService";
In plugins/myService.ts you must write someting like this:
import _Vue from "vue";
import MyService from "#/services/MyService";
export default function MyServicePlugin(Vue: typeof _Vue, options?: any): void {
Vue.prototype.$myService = new MyService(...); // you can import 'service' from other place
}
_Vue.use(MyServicePlugin);
And in any vue component you can use this:
<template>
<div> {{ $myService.name }}</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
#Component
export default class MyComponent extends Vue {
private created() {
const some = this.$myService.getStuff();
}
}
</script>
Don't forget to declare $myService on d.ts file. Somewhere in your project add file myService.d.ts with the following content:
import MyService from "#/services/MyService";
declare module "vue/types/vue" {
interface Vue {
$myService: MyService;
}
}
Using Vue property decorator
Vue-property-decorator, which internally re-exports decorators from vue-class-component, expose a series of typescript decorators that give really good intellisense. You must use the class api though.
#Inject and #Provide are two of such decorators:
In the provider:
import {Vue, Component, Provide} from 'vue-property-decorator';
#Component
export default class MyClass {
#Provide('service') service: Service = new MyServiceImpl(); // or whatever this is
}
In the provided component:
import {Vue, Component, Inject} from 'vue-property-decorator';
#Component
export default class MyClass {
#inject('service') service!: Service; // or whatever type this service has
mounted() {
console.log(this.service); // no typescript error here
},
}
This I think is the optimal solution, in the sense it gives the better intellisense available when working with Vue.
Now, however, you may don't want to change the definition of all your components or simply cannot due to external constraints. In such case you can do the next trick:
Casting this
You can cast this to any whenever you're about to use this.service. Not probably the best thing, but it works:
mounted() {
console.log((this as any).service);
},
There must be other ways, but I'm not used to Vue.extends api anymore. If you have the time and the opportunity, I strongly suggest you to switch to the class API and start using the vue-property-decorators, they really give the best intellisense.
Extend Vue for injected components only
Create an interface for the injection and extend Vue for the specific components where it is needed:
main.ts:
const service = new MyService(...);
export interface ServiceInjection {
service: MyService;
}
new Vue({
router,
provide(): ServiceInjection { return { service }; } // provide the service to be injected
render: h => h(App),
}).$mount("#app");
A components that uses your interface
import Vue from "vue";
import { ServiceInjection } from 'main.ts';
export default ( Vue as VueConstructor<Vue & ServiceInjection> ).extend({
inject: ["service"], // inject the service
mounted() {
console.log(this.service); // this.service does exists
},
});