How to add Vuejs component dynamically to the DOM - vuejs2

I want to add a vue component to the DOM when an option is selected from the drop down list, so it's dynamically displayed
The code that I have tried is as follows
var html = "<component :is=\"dynamickeyvalue\"></component>";
$('#extraOptionsElements').html(html);
is there anyway to load the vue component when it's added as all I am getting now is blank.

I have used the component tag to load the component dynamically. The button click will simulate the component changing feature.
<template>
<button
#click="changeComponent()"
>Click me to change component</button>
<component
:is="theSelectedComponent"
></component>
</template>
<script>
import Component1 from '#/components/Component1'
import Component2 from '#/components/Component2'
import Component3 from '#/components/Component3'
export default {
components: {
Component1,
Component2,
Component3
},
data () {
return {
theSelectedComponent: 'Component1'
}
},
methods: {
changeComponent () {
if (this.theSelectedComponent === 'Component1') {
this.theSelectedComponent = 'Component2'
} else if (this.theSelectedComponent === 'Component2') {
this.theSelectedComponent = 'Component3'
} else {
this.theSelectedComponent = 'Component1'
}
}
}
}
</script>

Related

Vue Material Modal in Child Component is not showing when child component is imported to a parent component

I am having trouble in displaying the modal from a child component when I imported it into the parent component as tab content.
So first, the parent component looks something like this:
parent.vue
<template>
<div>
<nav-tabs-card no-label tabs-plain>
<template slot = "content">
<md-tabs>
<md-tab id="child" label="Child Component">
<child-component/>
</md-tab>
</md-tabs>
</template>
</nav-tabs-card>
</div>
</template>
<script>
import {NavTabsCard} from '#/components';
import childComponent from '../child-component.vue';
export default {
components: {
NavTabsCard,
"child-component": childComponent
}
}
</script>
then child-component.vue
<template>
<div>
<md-button #click = "myModalShow">
</md-button>
<modal v-if="myModal" #close = "myModalHide"/>
</div>
</template>
<script>
import {Modal} from '#/components';
export default {
components: {
Modal
},
data() {
return {
myModal: false
};
},
methods: {
myModalShow() {
this.myModal = true
console.log("Modal is visible");
},
myModalHide() {
this.myModal = false;
console.log("Modal is hidden.");
}
}
}
</script>
When I click the button to display the modal, the console.log returns that the myModal value is true, but the modal is not shown at all. I also tried to increase the modal's z-index but it does not work too.

Buefy switch how to click on it in parent component

I have a Vue 2 app with Buefy. there is a component which contains Buefy switch. In some moment I need to click on the switch component. So I add ref property to the switch component and then I call it like this.$refs.switcherName.click(). But it throws me an error click is not a function. If I dump the $refs.switcherComponent it is component instance.
This is the code where I call the click()
watch: {
storeSelected(prevVal, newVal) {
this.$refs.onlySelectedToggler.click();
},
},
Can you be more specific on what you're trying to accomplish please? The error does tell you that "click()" is not a function of a Buefy switch, which is true. To change whether the switch is "on" or "off", you can use a v-model and data attribute to just change the value. For example:
<template>
<section>
<b-field>
<b-switch v-model="isSwitched">Default</b-switch>
</b-field>
<b-button #click="changeSwitch">Click to Change</b-button>
</section>
</template>
<script>
export default {
data() {
return {
isSwitched: false
}
},
methods: {
changeSwitch () {
this.isSwitched = !this.isSwitched
}
}
}
</script>

Component stays visible when using props in composition API

I have a vue 3 app which display product information. The home component displays all available products. Each of them has a button which takes me to a component displaying information about said product called Single Box. It gets the product ID from the route params and then fetches additional information via graphql. It looks like this:
<template>
<BoxDisplay :box="box"></BoxDisplay>
</template>
<script>
import { useQuery, useResult } from '#vue/apollo-composable';
import { useRoute } from 'vue-router'
import singleBoxQuery from '../graphql/singleBox.query.gql'
import BoxDisplay from '../components/BoxDisplay'
export default {
components: {
BoxDisplay
},
setup() {
const route = useRoute();
const boxId = route.params.id
const {result } = useQuery(singleBoxQuery, {id: boxId})
const box = useResult(result, null)
return {
boxId,
box
}
}
}
</script>
The BoxDisplay component is then used to show the infos of the current box. There is going to be more going on this page later so the BoxDisplay is needed. It looks like this:
<template>
<div class="p-d-flex p-jc-center">
<div v-if="box">
<h1>{{box.Name}}</h1>
<div v-html="myhtml"></div>
</div>
<div v-else>
<ProgressSpinner />
</div>
</div>
</template>
<script>
export default {
props: {
box: {}
},
setup(props){
const myhtml = "<h1>hello</h1>" + props.box.Name
return {
myhtml
}
}
}
</script>
The problem is now, that as soon as I use props in setup() the component stay visible when I click back in my browser. It stays there until I refresh the page. What am I doing wrong?
Use ref and computed
https://v3.vuejs.org/guide/composition-api-introduction.html#reactive-variables-with-ref
```
import { ref, computed } from 'vue'
```
const myhtml = computed(() => '<h1>hello</h1>' + props.box.Name)
or
const myhtml = ref('<h1>hello</h1>' + props.box.Name)

Vue - Switching between components

Imagine I have a order form with 3 stages - Personal details, Order details, payment.
I want to toggle the next component from within the previous one (hoping to adjust the value of 'step')
<Component1 v-if="step = 1"></Component1>
<Component2 v-else-if="step = 2"></Component2>
<Component3 v-else></Component3>
So, with those on my view, is it possible for me to pass the value of 'step' in to component1 and do something like
<button v-on:click="step = 2">
Submit
</button>
then on that click, update the value of step on my main view (with the 3 components) and with that, hide my first completed component and displaying the second?
Thanks for any insight!
Why you dont use dynamic components?
On your parent component you listen to the event that changes yours step, i named it here nextStep. This event triggers the method changeStep that changes the component name.
<component #nextStep="changeStep" :name="selectedComponent"></component>
import component1 from "../components/component1.vue";
import component2 from "../components/component2.vue";
import component3 from "../components/component3.vue";
export default {
data(){
return {
selectedComponent: "component1"
}
}
},
methods: {
changeStep(step){
this.selectedComponent = step;
}
},
components: {
component1,
component2,
component3
}
//in the child component
method: {
changeStep(){
this.$emit("nextStep", "component2");
}
}
This is how you emit the event to the parent to change the component
You just need to change the property selectedComponent to the component name you want and it will change it
If you are still searching for the answer. This first code to add as your parent component.
<template>
<main>
<component #nextStep="changeStep" v-bind:is="selectedComponent"></component>
</main>
</template>
<script lang="ts">
import Setup1 from '#/components/Setup/Setup1.vue';
import Setup2 from '#/components/Setup/Setup2.vue';
import Setup3 from '#/components/Setup/Setup3.vue';
export default {
name: "SetupView",
components: {
Setup1, Setup2, Setup3
},
data() {
return {
selectedComponent: "Setup1"
}
}, methods: {
changeStep(step: string) {
this.selectedComponent = step;
}
},
}
</script>
Add the code below as the child component .
<template>
<div>
Setup step 1
<button #click="changeStep">Next step</button>
</div>
</template>
<script lang="ts">
export default {
name: "setup1",
methods: {
changeStep() {
this.$emit("nextStep", "Setup2");
}
}
}
</script>
v-bind:is="selectedComponent"

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