Extend and re-assign vuetify component - vue.js

I want to add custom props to v-card-title component of vuetify.
But, I want to still use to call the vuetify component with my custom props, how can I do that?
I'm trying this, but doesn't succeed.
Example at codesandbox: https://codesandbox.io/s/71nr1w3qvq
<template>
<!-- How to add computed at VCardTitle? -->
</template>
<script>
import VCardTitle from "./somepath/VCardTitle";
export default {
name: "App",
props: ['variant'],
extends: VCardTitle,
computed: {
addVariant: function() {
if(this.variant === 'light') {
return 'light-theme'
}
return 'dark-theme'
}
}
};
</script>
<style>
</style>

You can use jsx like this
//App.js
export default {
name : 'App',
render(createElement){
return createElement(
'VCardTitle',
'My title'
)
}
}
//if you want more information go to this documentation:
//https://vuejs.org/v2/guide/render-function.html#createElement-Arguments

Related

Vuejs build/render component inside a method and output into template

I have a string (example, because it's an object with many key/values, want to loop and append to htmloutput) with a component name. Is it possible to render/build the component inside a method and display the html output?
Is that possible and how can i achieve that?
<template>
<div v-html="htmloutput"></div>
</template>
<script>
export default {
component: {
ComponentTest
},
data() {
return {
htmloutput: ''
}
},
methods:{
makeHtml(){
let string = 'component-test';//ComponentTest
//render the ComponentTest directly
this.htmloutput = ===>'HERE TO RENDER/BUILD THE COMPONENTTEST'<==
}
},
created(){
this.makeHtml();
}
</script>
You might be looking for dynamic components:
https://v2.vuejs.org/v2/guide/components-dynamic-async.html
Example:
<template>
<component :is="changeableComponent">
</component>
</template>
<script>
import FirstComponent from '#/views/first';
import SecondComponent from '#/views/second';
export default {
components: {
FirstComponent, SecondComponent
},
computed: {
changeableComponent() {
// Return 'first-component' or 'second-component' here which corresponds
// to one of the 2 included components.
return 'first-component';
}
}
}
</script>
Maybe this will help - https://forum.vuejs.org/t/how-can-i-get-rendered-html-code-of-vue-component/19421
StarRating is a sample Vue component. You can get it HTML code by run:
new Vue({
...StarRating,
parent: this,
propsData: { /* pass props here*/ }
}).$mount().$el.outerHTML
in Your method. Remember about import Vue from 'vue'; and of course import component.
What you're trying to do really isn't best practice for Vue.
It's better to use v-if and v-for to conditionally render your component in the <template> section.
Yes you can use the render function for that here is an example :
Vue.component('CompnentTest', {
data() {
return {
text: 'some text inside the header'
}
},
render(createElement) {
return createElement('h1', this.text)
}
})
new Vue({
el: '#app',
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<Compnent-test />
</div>
Or :
if you are using Vue-cli :
on your componentTest component :
export default {
render(createElement) {
return createElement('h1', 'sometext')
}
// Same as
// <template>
// <h1>sometext</h1>
// </template>
//
}
and on your root element (App.vue as default) :
export default {
....
component: {
ComponentTest
}
}
<template>
<div>
....
<Component-test />
</div>
</template>
example : codesandbox
you can read more about
Render Functions & JSX

Vue.js single file component 'name' not honored in consumer

Please pardon my syntax, I'm new to vue.js and may not be getting the terms correct.
I've got a single file component (SFC) named CreateTodo.vue. I've given it the name 'create-todo-item' (in the name property). When I import it in my app.vue file, I can only use the component if I use the markup <create-todo>. If I use <create-todo-item>, the component won't render on the page.
I've since learned that I can do what I want if I list the component in my app.vue in the format components: { 'create-todo-item': CreateTodo } instead of components: { CreateTodo }.
My question is this: is there any point to giving the component a name in the name property? It's not being honored in the consumer, and if I leave it empty, the app runs without error.
Also, am I correct in my belief that vue-loader is assigning the kebab-case element name for template use based on the PascalCase import statement?
Bad - component name property
Here's the code where I try to name the SFC (CreateTodo.vue)
<script>
export default {
name: 'create-todo-item',
data() {
return {
titleText: '',
projectText: '',
isCreating: false,
};
},
};
</script>
The name as listed in the component is ignored by my App.vue. The html renders fine even though I have the element <create-todo> instead of <create-todo-item>:
<template>
<div>
<!--Render the TodoList component-->
<!--TodoList becomes-->
<todo-list v-bind:todos="todos"></todo-list>
<create-todo v-on:make-todo="addTodo"></create-todo>
</div>
</template>
<script>
import TodoList from './components/TodoList.vue'
import CreateTodo from './components/CreateTodo.vue'
export default {
name: 'app',
components: {
TodoList,
CreateTodo,
},
// data function avails data to the template
data() {
return {
};
},
methods: {
addTodo(todo) {
this.todos.push({
title: todo.title,
project: todo.project,
done: false,
});
},
}
};
</script>
Good - don't use component name property at all
Here's my CreateTodo.vue without using the name property:
<script>
export default {
data() {
return {
titleText: '',
projectText: '',
isCreating: false,
};
},
};
</script>
And here's my App.vue using the changed component:
<template>
<div>
<!--Render the TodoList component-->
<!--TodoList becomes-->
<todo-list v-bind:todos="todos"></todo-list>
<create-todo-item v-on:make-todo="addTodo"></create-todo-item>
</div>
</template>
<script>
import TodoList from './components/TodoList.vue'
import CreateTodo from './components/CreateTodo.vue'
export default {
name: 'app',
components: {
TodoList,
'create-todo-item': CreateTodo,
},
// data function avails data to the template
data() {
return {
};
},
methods: {
addTodo(todo) {
this.todos.push({
title: todo.title,
project: todo.project,
done: false,
});
},
}
};
</script>
First note that the .name property in a SFC module is mostly just a convenience for debugging. (It's also helpful for recursion.) Other than that, it doesn't really matter when you locally register the component in parent components.
As to the specific details, in the first example, you're using an ES2015 shorthand notation
components: {
TodoList,
CreateTodo,
},
is equivalent to
components: {
'TodoList': TodoList,
'CreateTodo': CreateTodo
},
so that the component that is imported as CreateTodo is given the name 'CreateTodo' which is equivalent to <create-todo>.
In the second example, you give the name explicitly by forgoing the shorthand notation
components: {
TodoList,
'create-todo-item': CreateTodo,
},
That's equivalent, btw to
components: {
TodoList,
'CreateTodoItem': CreateTodo,
},
So you can see, in that case, that you're giving the component the name 'CreateTodoItem' or, equivalently, <create-todo-item>

How can I pass parameters from vue custom element to a vue component?

I don't have a whole vue app, so I use custom elements to replace some elements that should be handled with vue.
I simply want to use the vue multiselect plugin in a html file.
So I tried the following:
index.ts
import Vue from "vue"
import VueCustomElement from 'vue-custom-element'
import Autocomplete from "./vue/autocomplete.vue"
Vue.use(VueCustomElement);
Vue.customElement('auto-complete', Autocomplete);
test.html
<auto-complete
v-model="value"
:options="options"
placeholder="test"
#search-change="getData"
>
</auto-complete>
test.vue
<template>
<multiselect v-model="value" :options="options" #search-change="getData"></multiselect>
</template>
<script type="ts">
const Multiselect = require('vue-multiselect').default
export default {
components: { Multiselect },
data () {
return {
value: 'test',
options: ['list', 'of', 'options']
}
},
methods: {
getData (query) {
console.log(123)
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
In the output the data of the custom element is always ignored and only the parameters in the part in the .vue file is used.
How can i achieve that the parameters like placeholder or #search-change are used from the custom element?
I am also using vue-custom-elements in one of my projects.
You are passing option as props so you need to add it as a prop in your autocomplete.vue.
<template>
<multiselect v-model="value" :options="options" #search-change="getData"></multiselect>
</template>
<script type="ts">
const Multiselect = require('vue-multiselect').default
export default {
props: ['options'],
components: { Multiselect },
data () {
return {
value: 'test'
}
},
methods: {
getData (query) {
console.log('123')
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

Why this.$listeners is undefined in Vue JS?

Vue.js version: 2.4.2
Below component always print this.$listeners as undefined.
module.exports = {
template: `<h1>My Component</h1>`,
mounted() {
alert(this.$listeners);
}
}
I register the component and put it inside a parent component.
Can someone tell me why?
You have to understand what $listeners are.
this.$listeners will be populated once there are components that listen to events that your components is emitting.
let's assume 2 components:
child.vue - emits an event each time something is written to input field.
<template>
<input #input="emitEvent">
</input>
</template>
<script>
export default {
methods: {
emitEvent() {
this.$emit('important-event')
console.log(this.$listeners)
}
}
}
</script>
parent.vue - listen to the events from child component.
<template>
<div class="foo">
<child #important-event="doSomething"></child>
</div>
</template>
<script>
import child from './child.vue'
export default {
data() {
return {
newcomment: {
post_id: 'this is default value'
}
}
},
components: { child },
methods: {
doSomething() {
// do something
}
}
}
</script>
With this setup, when you type something to the input field, this object should be written to the console:
{
`important-event`: function () { // some native vue.js code}
}
I added the following alias to my webpack.config.js file and this resolved the issue for me:-
resolve: {
alias: {
'vue$': path.resolve(__dirname, 'node_modules/vue/dist/vue.js')
}
},

How to use helper functions for imported modules in vuejs .vue template?

I have a helper.js file with contains:
module.exports = {
getSrmColor: (color) => {
return color;
}
}
My .vue file has:
<template>
<div>
{{ recipeHelper.getSrmColor(recipe.color) }}
</div>
</template>
<script>
import recipeHelper from "./helpers.js";
export default {
name: "Recipe",
props: ["recipe"]
}
</script>
I get the following error:
Property or method "recipeHelper" is not defined on the instance but referenced during render.
Make sure to declare reactive data properties in the data option.
Make new helper instance inside your vue component, like below.
<script>
import recipeHelper from "./helpers.js";
export default {
name: "Recipe",
props: [
"recipe"
],
mounted: function() {
this.recipeHelper = recipeHelper;
}
}
</script>
I think you need to create "data value" for your import value. Could you try something like that:
<script>
import recipeHelper from "./helpers.js";
export default {
name: "Recipe",
props: ["recipe"],
data: function() {return {
recipeHelper: recipeHelper
}}
}
</script>