Add dynamically components in vue.js not working - javascript

I try to add dynamically component. This component set into props.
I not register components into components:{} section, because I don't now how many components and their name will be send from props.
I use ES6 syntax, where import js modules not work into ready(){} section.
My code:
let Child = Vue.extend({
data() {
return {
msg: 'CHILDREN'
}
},
template: '<div class="c-child">component {{msg}}</div>'
})
let Parent = Vue.extend({
props: {
component: ''
},
data() {
return {
msg: 'PARENT'
}
},
template: '<div class="c-parent">from component- {{msg}}<br><component :is="component"/></div>',
})
// register
Vue.component('parent-component', Parent)
// create a root instance
let vue = new Vue({
el: '#root'
})
.c-parent {
border: 1px solid red;
padding: 10px;
}
.c-child {
border: 1px solid green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.common.js"></script>
<div id="root">
<parent-component :component="Child"></parent-component>
</div>
Dynamic component not render:
<component :is="component"/>
P.S. This code work on jsfiddle - open link

You need to parse the interpreted component name to :is="" component, defining them the following way should work:
import GroupsGrid from './../../components/groups'
import RolesGrid from './../../components/roles'
import MainTabs from './../../components/main-tabs.vue' // <-- this component will be render other components
data: {
tabs: {
'GroupsGrid': 'groups-grid',
'RolesGrid': 'roles-grid'
}
},
And still used like this
<component :is="tabs.GroupsGrid"></component>

Related

vue.js dynamic component renders twice with itself as child component

I have a component proxy which renders components using vue.js build in dynamic component. The instanceName is the component to render. The data is the relevant data for the component to render.
<template>
<component v-if="getInstanceName" :is="getInstanceName" :data="data" />
</template>
<script>
import WidgetTypes from './WidgetTypes'
import { hydrateWhenVisible } from 'vue-lazy-hydration'
const components = Object.keys(WidgetTypes.types).reduce(
(components, typeKey) => {
const type = WidgetTypes.types[typeKey]
components[type] = hydrateWhenVisible(
() =>
import(
/* webpackChunkName: "[request]" */
/* webpackMode: "lazy" */
`./dynamic/${type}/${type}.vue`
),
{ observerOptions: { rootMargin: '100px' } }
)
return components
},
{}
)
export default {
name: 'WidgetComponentProxy',
components: components,
props: {
data: {
type: Object,
required: true,
default: null
}
},
computed: {
getInstanceName() {
return WidgetTypes.getInstanceName(this.data.instance_type)
}
}
}
</script>
All this works like a charm.. except ;-)
When inspecting in vue.js devtools I see my component twice. The component is somehow child to itself. I sometimes get errors trying to render components using this proxy.
Any help appreciated thanks

vue3 setting css styles from vuex store

Within vue3 is it possible to bind a value from the vuex store to a component style? for example, i have a color saved within the store as backgroundColor and would like to do something like below:
Store:
store = {
state: {
branding: {
color: '#f00'
}
}
}
component script
export default {
name: 'component',
components: {
Header,
Footer
},
branding() {
return this.$store.state.branding.color;
},
}
component style
.page{
background-color: v-bind(branding.colour);
}
i have seen an example of this working:
export default {
name: 'component',
components: {
Header,
Footer
},
data(){
return {
color: '#f00'
}
},
}
.page{
background-color: v-bind(colour);
}
but i need to grab the data from the store. im pretty new to vue but not too sure on how to resolve this.
UPDATE 6 April 2022
Apparently I was wrong and in Vue 3 it is possible to use v-bind inside CSS as shown in the documentation. So it should be possible to use Vuex getter or local computed property.
You can not access JavaScript variables from CSS. You should either set inline style to your HTML tag(s) or define the color as CSS variable and then access it from other CSS rules.
<template>
<div :style="{backgroundColor: brandingColor}">test</div>
</template>
<script>
export default
{
computed:
{
brandingColor()
{
return this.$store.state.branding.color;
}
}
}
</script>
OR
// main.js
new Vue({
created()
{
const style = document.documentElement.style;
const theme = this.$store.state.branding;
for (const key in theme)
{
style.setProperty('--branding-' + key, theme[key]);
}
}
});
MyComponent.vue:
<template>
<div class="page">text</div>
</template>
<style>
.page
{
background-color: var(--branding-color);
}
</style>

Change Vue view by object rather than url router

Writing a chrome extension with Vue.js and I need to change the views based on user action.
Typically, I would use the Vue router to auto-magically abstract all this logic away... however the router is bound to the URL.
Is it possible to change this behaviour in any way?
i.e, the <router-view/> is in App.vue as normal, but as the user clicks through the extension the router is not watching the URL in the browser address bar but instead say some other object?
Dynamic Components
Vue router is specifically for the url bar. You can use dynamic components when you want to switch a view component based on some other data. It uses a <component> tag with an is attribute:
<component :is="currentTabComponent"></component>
From the docs:
In the example above, currentTabComponent can contain either:
the name of a registered component, or
a component’s options object
Here's a demo where the variable currentTabComponent contains the name of the component:
new Vue({
el: "#app",
components: {
Home: { template: `<div class="component"><h1>Home</h1> The home component</div>` },
About: { template: `<div class="component"><h1>About</h1> An about component</div>` },
},
data() {
return {
currentTabComponent: 'Home'
}
},
methods: {
toggle() {
this.currentTabComponent = this.currentTabComponent === 'Home' ? 'About' : 'Home';
}
}
});
.component {
border: 3px solid #cccccc;
margin: 10px;
padding: 12px;
}
<div id="app">
<component :is="currentTabComponent"></component>
<button #click="toggle">Toggle</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

How to refer to Vue when using provide

I've been trying to pass down a value via a parent component to a child component without using props. I'm using provide for this on a parent component (not the highest parent). The value im passing down will be dynamically updated, so after reading the vue docs I have to do something like: Vue.computed(() => this.todos.length) but it throws an error because Vue is undefined. I seem to be unable to import Vue like this import Vue from 'vue' (or something similar). How can I make this work? To be honest, even when I try to pass down a static variable I get undefined in the (direct) child component, even when I use the exact same code as in the vue docs.
So I have 2 questions:
how to refer/import the Vue instance?
Is it possible to use provide on a direct parent component (which is not the root)?
I'm using Vue3
You can get the instance using getCurrentInstance but it's not needed for what you want to do:
import { getCurrentInstance } from 'vue';
setup() {
const internalInstance = getCurrentInstance();
}
You can provide a computed from any component. Import provide and computed in the parent and use them like:
Parent
import { provide, computed } from 'vue';
setup() {
...
const total = computed(() => x.value + y.value); // Some computed
provide('total', total);
}
Import inject in the child:
Child
import { inject } from 'vue';
setup() {
...
const total = inject('total');
}
Here's a demo (with just slightly different import syntax because the CDN doesn't use actual imports):
const { createApp, ref, computed, provide, inject } = Vue;
const app = createApp({});
// PARENT
app.component('parent', {
template: `
<div class="parent">
<child></child>
<button #click="x++">Increment</button> (from Parent)
</div>
`,
setup() {
const x = ref(5);
const y = ref(10);
const total = computed(() => x.value + y.value);
provide('total', total);
return {
x
}
}
});
// CHILD
app.component('child', {
template: `
<div class="child">
Total: {{ total }}
</div>
`,
setup() {
const total = inject('total');
return {
total
}
}
});
app.mount("#app");
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.parent, .child { padding: 24px; }
.parent {
background: #dddddd;
}
.child {
margin: 6px 0;
background: #ddeeff;
}
<div id="app">
<parent></parent>
</div>
<script src="https://unpkg.com/vue#next"></script>

Vue.js call component by variable name?

Is possible in Vue.js call component by variable name?
Components are registred:
import Component1 from 'component1'
import Component2 from 'component2'
import Component3 from 'component3'
...
components: {
Component1, Component2, Component3
},
And i am searching for something like this:
created() {
var componentName = 'Component1';
this.components[componentName]
}
You can access the components property like this:
this.$options.components[componentName]
Just a basic example on how you can use dynamic component:
link to jsFiddle to play around: link here
<div id="app">
<component v-bind:is="currentPage">
<!-- component changes when currentPage changes! -->
<!-- output: Updated About -->
</component>
</div>
new Vue({
el: '#app',
data: {
currentPage: 'home'
},
components: {
home: {
template: "<p>Home</p>"
},
about: {
template: "<p>About</p>"
},
contact: {
template: "<p>Contact</p>"
}
},
mounted(){
this.$options.components['about'].template = "<p>Updated About</p>"
this.currentPage = 'about'
}
})

Categories

Resources