Class as function in functional component - Vue - javascript

I am writing a simple functional component in vuejs. Currently stuck at a situation where I want to add conditional css class based on the props passed to it.
However the below doesn't work as expected and I am wondering what wrong am I doing here.
<script>
export default {
name: "BasePill",
functional: true,
props: {
variant: String
},
render(createElement, { children, props }) {
const componentData = {
staticClass: "text-sm text-center"
class: function() {
if (props.variant === 'secondary') {
return 'bg-secondary'
}
return 'bg-primary'
}
};
return createElement("span", componentData, children);
},
};
</script>

The class property cannot be a function, it needs to be a string/array/object.
Do this instead:
const componentData = {
staticClass: 'text-sm text-center',
class: props.variant === 'secondary' ? 'bg-secondary' : 'bg-primary',
};

Related

how to render common using mixin in vue.js?

Can i render common using mixin in vue.js?
for example
<template>test: {{ test }}</template>
<script>
export default {
data() {
return {
test: 1,
}
},
}
</script>
// mixin
export default {
data() {
return {
mixinData: 10,
}
},
render() {
if (this.mixinData === 10) {
// mixin render, not component render
} else {
// component render, not mixin render
}
}
}
can i do this using mixin in vue.js?
i want to know way about common render using mixin.

How to make a server/srr render only as vue components?

I am using vue-no-ssr (https://github.com/egoist/vue-no-ssr), but it creates components that only render on the client side. I want to render my component on the server side. Is there any way to make a vue component that only renders on the server?
I tried to use the source code of vue-no-ssr below, but I don't understand how to adept it.
export default {
name: 'NoSsr',
functional: true,
props: {
placeholder: String,
placeholderTag: {
type: String,
default: 'div'
}
},
render(h, { parent, slots, props }) {
const { default: defaultSlot = [], placeholder: placeholderSlot } = slots()
if (parent._isMounted) {
return defaultSlot
}
parent.$once('hook:mounted', () => {
parent.$forceUpdate()
})
if (props.placeholderTag && (props.placeholder || placeholderSlot)) {
return h(
props.placeholderTag,
{
class: ['no-ssr-placeholder']
},
props.placeholder || placeholderSlot
)
}
// Return a placeholder element for each child in the default slot
// Or if no children return a single placeholder
return defaultSlot.length > 0 ? defaultSlot.map(() => h(false)) : h(false)
}
}
vue-lazy-hydration
https://github.com/maoberlehner/vue-lazy-hydration
looks like can do ssr-only when-idle when-visible ... and more

v-if is not working in my child component

I am trying to show a span whenever v-if is equal to true in my child component. Could anyone advice what I did wrong. Currently, I have no idea what I did incorrectly.
Child Component
const cardsTemplate = {
template:
`
<fieldset v-if="show.seach_checkboxes">
<span>HELLO WORLD</span>
</fieldset>
`,
props: ['js_local'],
data() {
return {
show:{
search_checkboxes : {
type: Boolean,
default: true,
}
}
}
},
methods :{
change_boolean : function(reverse_boolean){
this.show[reverse_boolean] = !this.show[reverse_boolean]
console.log(this.show)
},
show_search_template: function(){
this.change_boolean('search_checkboxes')
},
get_search_template : function(){
$.post(this.js_local.ajaxurl,
{action : 'get_search_templates'}
).done((data)=>{
this.name = JSON.parse(data)
}).fail((error)=>{
console.log(error)
})
},
}
}
It looks like you're trying to use data() with type checking, the same way props is used. Try this:
data() {
return {
show: {
search_checkboxes: true
}
}
}
Also, in your template HTML, you've misspelled search_checkboxes, it's missing an "r".
<fieldset v-if="show.seach_checkboxes">
^^^

Vue component using computed property of the mixin

I have a simple component that uses mixin that's shared across multiple components with similar functionality.
When I run it I seem to be getting
Property or method "activeClass" is not defined on the instance but
referenced during render.
Here's my mixin
<script>
export default {
data() {
return {
opened: false,
identity: ''
}
},
computed: {
activeClass() {
return {
active: this.opened
};
}
},
created() {
window.EventHandler.listen(this.identity + '-toggled', opened => this.opened = opened);
},
methods: {
toggle() {
window.EventHandler.fire('toggle-' + this.identity);
}
}
}
</script>
and my component
<template>
<span class="pointer" :class="activeClass" #click="toggle"><i class="fas fa-search"></i></span>
</template>
<script>
import Trigger from '../../mixins/Trigger';
export default {
data() {
return {
mixins: [Trigger],
data() {
return {
identity: 'language'
}
}
}
}
}
</script>
For some reason I cannot seem to be able to access activeClass computed property from within the component. Any idea why is this happening?
Try to move mixin to components main scope. Not in data function rerurn

Working with dynamic components in vue.js

I have a simple application which need to render 2 components dynamically.
Component A - needs to have onClick event.
Component B - needs to have onChange event.
How is it possible to dynamically attach different events to component A/B?
<template>
<component v-bind:is="currentView">
</component>
</template>
<script>
import A from '../components/a.vue'
import B from '../components/b.vue'
export default {
data: function () {
return {
currentView: A
}
},
components: { A, B }
}
</script>
Here is a solution for a little more complicated and realistic use case. In this use case you have to render multiple different components using v-for.
The parent component passes an array of components to create-components. create-components will use v-for on this array, and display all those components with the correct event.
I'm using a custom directive custom-events to achieve this behavior.
parent:
<template>
<div class="parent">
<create-components :components="components"></create-components>
</div>
</template>
<script>
import CreateComponents from '#/components/CreateComponents'
import ComponentA from '#/components/ComponentA'
import ComponentB from '#/components/ComponentB'
export default {
name: 'parent',
data() {
return {
components: [
{
is: ComponentA,
events: {
"change":this.componentA_onChange.bind(this)
}
},
{
is: ComponentB,
events: {
"click":this.componentB_onClick.bind(this)
}
}
]
}
},
methods: {
componentA_onChange() {
alert('componentA_onChange');
},
componentB_onClick() {
alert('componentB_onClick');
}
},
components: { CreateComponents }
};
</script>
create-components:
<template>
<div class="create-components">
<div v-for="(component, componentIndex) in components">
<component v-bind:is="component.is" v-custom-events="component.events"></component>
</div>
</div>
</template>
<script>
export default {
name: 'create-components',
props: {
components: {
type: Array
}
},
directives: {
CustomEvents: {
bind: function (el, binding, vnode) {
let allEvents = binding.value;
if(typeof allEvents !== "undefined"){
let allEventsName = Object.keys(binding.value);
allEventsName.forEach(function(event) {
vnode.componentInstance.$on(event, (eventData) => {
allEvents[event](eventData);
});
});
}
},
unbind: function (el, binding, vnode) {
vnode.componentInstance.$off();
}
}
}
}
</script>
You don't have to dynamically add them.
<component v-bind:is="currentView" #click="onClick" #change="onChange">
If you want to be careful you can bail in the handler of the currentView is not correct.
methods: {
onClick(){
if (this.currentView != A) return
// handle click
},
onChange(){
if (this.currentView != B) return
// handle change
}
}

Categories