I'm making a Vue3 Single File Component for a custom list. In my single file component, I want to export the main default Vue component, but also the enum declaring what type of list it is:
child:
<template>
<Listbox>
<template #header>
<h5>{{listType}}</h5>
</template>
</Listbox>
</template>
<script lang="ts">
export enum PagesListType {
RecentlyCreated = 'Recently Created',
RecentlyModified = 'Recently Modified',
Starred = 'Starred'
};
export default {
props: {
listType: PagesListType
},
data() {
return {
pages: [],
PagesListType
};
},
};
</script>
The enum only makes sense within the context of this component, so I don't want to put it in some other folder of types. It only relates to the behavior of this list. But when I try to do this in the parent component, it fails:
parent:
<template>
<div>
<PagesList :listType="PagesListType.RecentlyCreated"></PagesList>
<PagesList :listType="PagesListType.RecentlyModified"></PagesList>
<PagesList :listType="PagesListType.Starred"></PagesList>
</div>
</template>
<script lang="ts">
import PagesList, { PagesListType } from './PagesList.vue';
export default {
//parent component details
};
</script>
When I import the named PagesListType enum, it is just undefined. What do I need to do to export the named enum correctly? Thanks!
I opine you need to export enum into a separate file and import it in different files to use it. Where do you put this file depends on you mainly, how you want to structure your project.
For instance, types.ts file in the src folder can define and export the enum like:
export enum PagesListType {
RecentlyCreated = 'Recently Created',
RecentlyModified = 'Recently Modified',
Starred = 'Starred'
}
you can use the enum anywhere by importing it like:
import { PagesListType } from '#/types';
you have to use #/ instead of src/. because of the src folder to # in your TypeScript configuration available in the tsconfig.json file.
I was able to kinda get this to work by not exporting the enum, but adding it as a property to the exported default component:
child:
enum PagesListType {
RecentlyCreated = 'Recently Created',
RecentlyModified = 'Recently Modified',
Starred = 'Starred'
};
export default {
props: {
listType: PagesListType
},
PagesListType,
data() {
return {
pages: [],
PagesListType
};
},
};
parent:
<template>
<div>
<PagesList :listType="created"></PagesList>
<PagesList :listType="modified"></PagesList>
<PagesList :listType="starred"></PagesList>
</div>
</template>
<script lang="ts">
import PagesList from './PagesList.vue';
export default {
computed: {
created() {
return PagesList.PagesListType.RecentlyCreated;
},
modified() {
return PagesList.PagesListType.RecentlyModified;
},
starred() {
return PagesList.PagesListType.Starred;
}
},
//other parent implementation details omitted
};
</script>
Related
I tried following:
https://github.com/visualfanatic/vue-svg-loader/tree/master
but there's a version conflict with vue-template-compiler since that's used in Vue 2.
I tried:
https://github.com/visualfanatic/vue-svg-loader
but I'm missing a specific vue dependency.
I noticed there's a caveat with using typescript and you need to declare the type definition file. However, I still get "Cannot find module '../../assets/myLogo.svg' or its corresponding type declarations."
Here's what I added:
vue.config.js
module.exports = {
chainWebpack: (config) =>
{
const svgRule = config.module.rule('svg');
svgRule.uses.clear();
svgRule
.use('vue-loader-v16')
.loader('vue-loader-v16')
.end()
.use('vue-svg-loader')
.loader('vue-svg-loader');
},
configureWebpack: process.env.NODE_ENV === 'production' ? {} : {
devtool: 'source-map'
},
publicPath: process.env.NODE_ENV === 'production' ?
'/PersonalWebsite/' : '/'
}
shims-svg.d.ts
declare module '*.svg' {
const content: any;
export default content;
}
MyComponent.vue
<template>
<div>
<MyLogo />
</div>
</template>
<script lang="ts">
import * as MyLogo from "../../assets/myLogo.svg";
export default defineComponent({
name: "MyComponent",
components: {
MyLogo
},
props: {
},
setup(props)
{
return {
props
};
}
});
</script>
Actually SVGs are supported right out of the box with Vue CLI. It uses file-loader internally. You can confirm it by running the following command on the terminal:
vue inspect --rules
If "svg" is listed (it should be), then all you've got to do is:
<template>
<div>
<img :src="myLogoSrc" alt="my-logo" />
</div>
</template>
<script lang="ts">
// Please just use `#` to refer to the root "src" directory of the project
import myLogoSrc from "#/assets/myLogo.svg";
export default defineComponent({
name: "MyComponent",
setup() {
return {
myLogoSrc
};
}
});
</script>
So there's no need for any third party library—that is if your sheer purpose is only to display SVGs.
And of course, to satisfy the TypeScript compiler on the type declaration:
declare module '*.svg' {
// It's really a string, precisely a resolved path pointing to the image file
const filePath: string;
export default filePath;
}
Can't say for sure, since I haven't tried with ts, but as posted here
this should work.
declare module '*.svg' {
import type { DefineComponent } from 'vue';
const component: DefineComponent;
export default component;
}
I see you're using:
import * as MyLogo from "../../assets/myLogo.svg";
I believe that should be:
import MyLogo from "../../assets/myLogo.svg";
vue-svg-loader is not compatible with vue 3. To import svg and use it as a component, simply wrap the contents of the file in 'template'
In component:
<template>
<div class="title">
<span>Lorem ipsum</span>
<Icon />
</div>
</template>
<script>
import Icon from '~/common/icons/icon.svg';
export default {
name: 'PageTitle',
components: { Icon },
};
</script>
Webpack:
{
test: /\.svg$/,
use: ['vue-loader', path.resolve(__dirname, 'scripts/svg-to-vue.js')],
}
scripts/svg-to-vue.js:
module.exports = function (source) {
return `<template>\n${source}\n</template>`;
};
Example from fresh installed vue.js 3.2:
<img alt="Vue logo" class="logo" src="#/assets/logo.svg" width="125" height="125"/>
I want to be able to swap out a template for a component based on a data property, or a prop. Is this possible?
This is my idea, however this doesn't work of course.
./index.vue
export default {
props:{
},
template: import(`./Themes/Templates/${this.template}`),
data: function() {
return {
template: 'Default'
}
},
./Themes/Templates/Default.vue
<div>
<p>Default template</p>
</div>
Currently getting this error:
invalid template option:[object Module]
Use component that vue.js provide:
<template>
<component :is="myComp"></component>
</template>
...
// You need to import all the possible components
import CompOne from '/CompOne.vue';
import CompTwo from '/CompTwo.vue'
props:{
myComp: {
default: 'comp-one',
type: String,
},
},
...
Try require("./Themes/Templates/Default.vue")
Update:
In Default.vue:
...
export default {
name: "Default"
}
...
and in index.vue:
...
template: this.temp,
data() {
const { Default } = import("./Themes/Templates/Default.vue");
return {
temp: Default
}
}
...
I've tried to override VueJS component method from another component.
Here I want to override checkForm method from another VueJS file.
inside ./src/components/auth_form.vue:
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
props: {...},
methods: {
checkForm: function(e: any) {
console.log('Please override this method!')
}
}
})
</script>
I want to override this method from ./src/views/signup.vue:
<script lang="ts">
import Vue from 'vue'
import authForm from '../components/auth_form.vue'
export default Vue.extend({
name: 'signup',
components: {
authForm
},
data: function() {...},
methods: {
// This does not override the method above!
checkForm: function(e: any) {
console.log("success")
// Reset the form
this.signupForm = {} as SignupForm
}
}
})
</script>
Yes they will not override because the 2 functions are in 2 different scopes. They can have same name and works independently. In order to do what you want, you have to put the checkForm function of auth_form inside its props.
So in auth_form:
props: {
checkForm: {
type: Function,
default(e) {
console.log('Please override this method!')
}
}
}
then when calling it in signup.vue
<auth-form :check-form="checkForm" /> //pass parent's method into children props
methods: {
checkForm() {
console.log("success") // this will override the default one
}
}
I have component 'Page' that should display a component which is retrieved via its props.
I managed to get my component loads when I harcode my component path in my component data like this :
<template>
<div>
<div v-if="includeHeader">
<header>
<fv-header/>
</header>
</div>
<component :is="this.componentDisplayed" />
<div v-if="includeFooter">
<footer>
<fv-complete-footer/>
</footer>
</div>
</div>
</template>
<script>
import Header from '#/components/Header/Header';
import CompleteFooter from '#/components/CompleteFooter/CompleteFooter';
export default {
name: 'Page',
props: {
componentPath: String,
includeHeader: Boolean,
includeFooter: Boolean
},
data() {
componentDisplayed: function () {
const path = '#/components/my_component';
return import(path);
},
},
components: {
'fv-header': Header,
'fv-complete-footer': CompleteFooter,
},
}
</script>
But with the data I cannot refer to my props within my function as this is undefined.
I tried to used computed properties instead of data but I have the error "src lazy?0309:5 Uncaught (in promise) Error: Cannot find module '#/components/my_component'. But the module exists! But maybe not at that time ?
computed: {
componentDisplayed: function () {
const path = `#/components/${this.componentPath}`;
return import(path);
},
},
There must be away to deal with that but I am quite a beginner to vue.js :)
Instead of trying to import the component in your child component, instead import it in the parent component and pass the entire component as a prop.
<template>
<div :is="component" />
</template>
<script>
export default {
name: "page",
props: {
component: {
required: true
}
}
};
</script>
And in the parent
<page :component="component" />
and
import Page from './components/Page';
// and further down
data () {
return {
component: HelloWorld
}
}
I'm trying to import an array into a Vue component:
The (simplified) component:
<script type="text/babel">
const countryCodes = require('./country_codes.js');
export default {
props: [],
data() {
return {
countryCodes: countryCodes
}
},
}
</script>
country_codes.js
(function() {
return ['DE', 'EN']; // This, of course, is way bigger; simplified for readability
});
Both the component and the country_codes.js files are in the same directory, but the countryCodes property is always an empty object.
What am I doing wrong?
I can't tell for what reason your code isn't working. Maybe you just need to export your data from countryCodes.js
So, I am sure this will work
import countryCodes from './countryCodes.js'
countryCodes.js
export const countryCodes = {
return ['DE', 'EN'];
}