How to create a reusable component in VueJs? - vuejs2

I would like to create Side Panel as a reusable component in Framework7 with VueJS. Here is my code..
Card.vue
<f7-card>
<f7-card-header>Card header content</f7-card-header>
<f7-card-content><img src="https://wiki.videolan.org/images/Ubuntu-logo.png"></img></f7-card-content>
<f7-card-footer>Card footer content</f7-card-footer>
</f7-card>
Now i registered as a component like below,
import Vue from 'vue'
export default [
{
path: '/card/',
component: require('./Card')
},
]
In later vues i imported as,
import Card from './Card.vue'
and i try to access in another vues like,
Now i'm getting an error like
[Vue warn]: Unknown custom element: - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
Can anyone help me where have i mistaken?
Thanks,

It's not really clear from your code exactly what you are doing, but the error you are getting happens when you try to use a component as a child of another component without registering it in the parent's components setting like this:
<script>
import Card from './Card.vue'
export default {
data () {
return {
somedata: 'some value'
}
},
components: {Card: Card}, // <- you're missing this
// etc...
}
</script>
You can also register components globally. More here: https://v2.vuejs.org/v2/guide/components.html#Local-Registration

Are you showing us all of Card.vue? For a valid single-file vue component, I would expect to see <template>, <script> and <style> elements. The render function will be generated from whatever you put in the <template> element.

Make sure that the component that you want to reuse is wrapped inside a template tag
As follows
<template>
<div>
<component data/>
<div/>
<template/>
Then register it inside the parent
Like so
export default {
name: "Card",
components: {
Card
},
};

Related

Vue Test Utils: how to pass Vuelidate validation rules to child components?

while trying to write a component test by using vue test utils, testing interaction between child components and stuff, I am stuck due to usage of Vuelidate from child components. Below is an example simplified:
// parent component code
<template>
<div>
<childA />
</div>
</template>
//childA code
<template>
<input v-model="value" />
</template>
<script>
...
validations: {
value: {
required
}
}
...
</script>
// parent component test
...
const wrapper = mount(MyParentComponent, {
...,
components: {
childA,
},
validations: {
value: required
},
...
})
I have tried to find a solution out there that I could mount (note here that I WANT to mount also the child components, so shallow-mount is not what I look for) the child component, with it's respective Vuelidate validation rules, but I still haven't found any solution.
Instead, my test gives me errors like:
Cannot read property `value` of undefined
which makes sense, since the test cannot access the child component's $v instance.
Has anyone achieved it so far?
For answering your question and after i've did some test i believe you missed the data part inside your mount
mount: render child components
shallowMount: doesn't render child components
MyParentComponent need to have in the options the structure of you're child component so this is why he is returning the error
And i saw that you're passing the import of your component directly but don't forget that your test folder is outside of your src folder
import ChildA from "#/components/ChildA";
will not work instead i propose to use absolute path directly to import your child component or use a configuration to resolve them
const wrapper = mount(MyParentComponent, {
data() {
return {
value: null
}
},
components: {
ChildA: () => import('../../src/components/ChildA'),
},
validations: {
value: required
},
})

How to make a Base component that will allow other components to inherit new functionality or code from it in Vue JS

Component 1:-
<template>
<blur :isData="isData">
<!-- logic/implementation of component 1 -->
<div>
</div>
</blur>
<template>
<script>
import blur from "../shared/Blur";
name: "component-1",
components: {
blur,
},
</script>
Just like this component1.vue, I have multiple components which are using blur component. Is it possible that instead of writing and importing blur in every single component, I can make some base class that can transfer the blur functionality in every single component in the folder. Can something like this be achieved in vue ?
With Vue.component you can create globally registered components:
Vue.component('my-component-name', {
// ... options ...
})
Find out more here

Vue3: Is it possible to register single file components using app.component(...)?

Diving into vue 3, trying to add Vue to an existing asp.net core project. Since the frontend is mostly razor pages, the app isn't being mounted with a templated component that has a hierarchy of components.
const vueApp = createApp({});
What I'm trying to do:
vueApp.component('MyComponent', require('./components/MyComponent').default);
vueApp.mount('#app');
I've also tried it this way, as described in the docs:
import { createApp } from 'vue/dist/vue.esm-browser'
import MyComponent from './components/MyComponent.vue'
const vueApp = createApp({
components: {
MyComponent
}
});
vueApp.mount('#app');
I've tried every version of this. requiring MyComponent.vue, with and without the default, importing MyComponent and using it that way (instead of require), none of them work. I just continue getting [Vue warn]: Failed to resolve component 'mycomponent' (Yes I did check the html coming back from the server, It's properly capitalized...not sure why the error is lower case).
MyComponent.vue looks like this:
<template>
<lots of vanilla html>
</template>
<script>
export default {
name: 'MyComponent',
data() {
return { some: "data" }
},
methods: { ... },
mounted() { ...}
}
</script>
//no component styling
Am I missing something here? Or is this no longer possible? I'm using the default vue-cli webpack config, if that matters.
Thanks
So, after rereading the docs (for what feels like the 10th time), I think I figured out the problem. It's actually not a Vue issue at all, it's my use of the Vue component.
In my asp.net core cshtml, I was referencing the component in PascalCase, like this:
<MyComponent />
Turns out this is a no no. By convention (enforced by the browser I guess), custom elements can only be referenced in the DOM using kebab-case, like this:
<my-component />
My vue app is still defining the component in PascalCase.
My main.js file is importing MyComponent, then passing it into the createApp options.components object.
const vueApp = createApp({
components: {
MyComponent
}
});
The more you know, I guess.

Dynamic component inside a component that is rendered with render() function

I saw in the docs that you can have a dynamic component inside your VueComponent like this :
<component :is="componentName" v-bind="componentProps" #custom-event="doSomething" />
I am trying to have one of these dynamic components inside a dynamically rendered component (with the render() function, not with an HTML template). Without too much hope, I've tried this :
render(createElement: CreateElement) {
return createElement('component', props: {
'is': 'TestComponent'
});
}
but I got
[Vue warn]: Unknown custom element: <component> - did you register the component correctly?
So again, not hoping too much for a miracle, I tried to import Component and declare it as a component :
#Component({
components: {
Component,
TestComponent
}
})
export default class DynamicThingy extends Vue {
render(createElement: CreateElement): VNode {
return createElement('Component', {
props: {
'is': 'TestComponent'
}
});
}
}
But then I get
[Vue warn]: Do not use built-in or reserved HTML elements as component id: Component
Any idea how that could be possible ?
The first parameter of createElement() must be either
An HTML tag name,
component options,
or async function resolving to one of these.
https://v2.vuejs.org/v2/guide/render-function.html#createElement-Arguments
So in a render function, you can simply create a function* that returns one or another component's options based on your desired criteria, and let that be your first argument. *This function is identical to the function you'd write to determine what goes into the :is prop)
You only need the dynamic component <component /> and :is prop in a template where you don't have the possibility to do it programmatically.
You can use this smart-list component from the vue docs as an example.

Vue dynamic components - watch for mounted

I'm using Webpack dynamic imports and Vue dynamic components to lazy-load a rather large Vue markdown-parsing component.
Now, I want to add syntax highlighting with Prism.js. I'm currently using the mounted() lifecycle hook of the parent component to install syntax highlighting, but this is only working some of the time, since the syntax highlighting depends on the Markdown component to be loaded first (when I manually execute Prism.highlightAll() from the console after page load, it works every time).
Relevant source code:
<template>
<vue-markdown>
# Hello
```javascript
import { hello } from "world"
```
</vue-markdown>
</template>
<script>
export default {
components: {
"vue-markdown": () => import("vue-markdown/src/VueMarkdown"),
},
mounted() {
import("prismjs/themes/prism-tomorrow.css")
.then(() => import("prismjs").then(p => Prism.highlightAll()))
}
}
</script>
So how do I wait for a dynamic component to load? I almost want something like this:
<vue-markdown v-on:mounted="syntaxHighlighting()"></vue-markdown>
I solved the problem by creating my own component which extends the VueMarkdown component, but with a mounted() hook that activates syntax highlighting. It looks like this:
<script>
import VueMarkdown from "vue-markdown/src/VueMarkdown"
import "prismjs/themes/prism-tomorrow.css"
import Prism from "prismjs"
export default {
extends: VueMarkdown,
mounted() {
Prism.highlightAll()
}
}
</script>
Then, I dynamically import this component into the parent component.
Not sure if this is the best solution, though...