how to render component from a component in vue js - javascript

I have a component with following template:
<div v-for:"item in store" v-bind:key="item.type">
<a>{{item.type}}</a>
</div>
I have another component called 'StoreComponent'
On click of a element in first component I want to clear the current component and show the StoreComponent and able to pass item.type to StoreComponent.
I don't want to use router-link or router.push as I don't want to create a new url but override the current component with the new one depending on the item.type value.
StoreComponent.vue
export default{
name: 'StoreComponent',
props: ['item'],
data: function () {
return {
datum: this.item
}
},
methods: {
//custom methods
}
}

You could use dynamic components and pass the item-type as a prop.
Vue.component('foo', {
name: 'foo',
template: '#foo'
});
Vue.component('bar', {
name: 'bar',
template: '#bar',
props: ['test']
});
new Vue({
el: "#app",
data: {
theComponent: 'foo', // this is the 'name' of the current component
somethingWeWantToPass: {
test: 123 // the prop we are passing
},
},
methods: {
goFoo: function() {
this.theComponent = 'foo';
},
goBar: function() {
this.theComponent = 'bar';
},
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<button #click="goFoo">Foo</button>
<button #click="goBar">Bar</button>
<component :is="theComponent" v-bind="somethingWeWantToPass"></component>
</div>
<template id="foo">
<div>
Foo
</div>
</template>
<template id="bar">
<div>
Bar
<div>This is a prop: {{ this.test }}</div>
</div>
</template>

Related

Vue bind child component data from parent

I need to bind my child component data (inputData) from parent component but it's not working i cannot find where is my mistake
app.js
let vm = new Vue({
el: "#app",
components: {
'modal-panel': modal,
'rich-select': richSelect,
'file-upload': uploader,
},
data(){ return {
isModalActive: false,
inputData: null
}} ,
methods: {
toggleModal(){
this.isModalActive = !this.isModalActive
},
modalData(){
this.inputData = 'Example Data'
}
}
});
Modal.vue
<template>
<input type="text" :value="inputData" >
</template>
export default {
name: 'modal',
props: ['inputData'],
mounted(){
console.log('modal Mounted')
}
};
inside my blade i'am calling modal component like this
<div class="container" id="app">
<modal-panel v-if="isModalActive" #close="toggleModal" :inputData="inputData"></modal-panel>
</div>
when i test that code all methods are working but inside Modal.vue input still not binding
You've to use the prop with kebab-case format as follows :
<modal-panel v-if="isModalActive" #close="toggleModal" :input-data="inputData"></modal-panel>

Vue state not updated with default injected value

If you click the button, you can see the value of state updated in the console, but it isn't updated in the page output. How can I make it work with a default injected value?
const Component = {
inject: {
state: {
default: () => ({
example: 1
})
}
},
template: `<div>
<div>{{ state }}</div>
<button #click="click">click</button>
</div>`,
methods: {
click() {
this.state.example += 1
console.log(this.state)
}
}
}
new Vue({
el: "#app",
components: {
Component
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<component></component>
</div>
Is it related to as Vue docs say "Note: the provide and inject bindings are NOT reactive. This is intentional. However, if you pass down an observed object, properties on that object do remain reactive."? I'm confused about the difference between the BINDINGS not being reactive but the OBSERVED OBJECT being reactive. Could you show an example to demo the difference?
Sorry, but it is not clear what you want - where's the provider for the "injection"? Why do you use inject in the same component as you use the value itself?
Here's your code, without inject:
1. Use the data attribute
const Component = {
data() {
return {
state: {
example: 1
}
}
},
template: `<div>
<div>{{ state }}</div>
<button #click="click">click</button>
</div>`,
methods: {
click() {
this.state.example += 1
console.log(this.state)
}
}
}
new Vue({
el: "#app",
components: {
Component
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<component></component>
</div>
Just use the data attribute - you can have a default value for example.
2. Use injection
inject is something completely different - it's a way to pass values from a provider to a consumer:
const Component = {
inject: ['state1'],
data() {
return {
state: {
example: 1
}
}
},
template: `<div>
<div>injected: {{ state1 }}</div>
<div>{{ state }}</div>
<button #click="click">click</button>
</div>`,
methods: {
click() {
this.state.example += 1
console.log(this.state)
}
}
}
new Vue({
el: "#app",
provide: {
state1: {
example1: 1
}
},
components: {
Component
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<component></component>
</div>
You can "skip" levels of components and use the provided value in components where you inject it - you don't have to pass it all the way down as props.
3. Create reactive inection
If you want to have reactive injection then you need to pass down something more complex:
const Component1 = {
inject: ['state2'],
data() {
return {
state: {
example: 1
}
}
},
template: `<div>
<div>injected: {{ state2.state2P }}</div>
<div>{{ state }}</div>
<button #click="click">click</button>
</div>`,
methods: {
click() {
this.state.example += 1
console.log(this.state)
}
}
}
new Vue({
el: "#app",
data() {
return {
state2: {
example2: 1
}
}
},
provide() {
// create an object (state2)
const state2 = {}
// define a property on the object (state2P), that
// has a get() function that always gets the provider's
// value you want to inject
Object.defineProperty(state2, 'state2P', {
enumerable: true,
get: () => this.state2,
})
// return the created object (with a property that always
// gets the value in the parent)
return {
state2
}
},
components: {
Component1
},
methods: {
parentClick() {
this.state2.example2 += 1
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<component1></component1>
<button #click="parentClick">PARENT CLICK</button>
</div>
I added a button to the template, so you can see that a method defined in the provider component's scope changes the value displayed in the consumer component's scope. (Also had to change the component's name, as Vue started to "whine" about using a restricted word.)

Unable to pass data to vue template

I am trying to pass the name from data to my settingTemplate.
However, I have not been able to make it work. Could anyone advice how I should approach this? I am new to Vue.
app.js
var app = new Vue({
el: '#app',
components: {
settingTemplate
},
data: {
name: 'Elon'
}
})
setting-template.js
const settingTemplate = {
template:
`<div class="d-flex flex-column text-md-center">
<div class="p-2">
<b-btn id="popoverButton-disable" variant="primary"></b-btn>
</div>
<div class="p-2">
<b-popover :disabled.sync="disabled" target="popoverButton-disable" title="{{name}}">
<a>Profile</a> | <a>Logout</a>
</b-popover>
</div>
</div>`
,
data() {
return {
disabled: false
}
},
methods: {
disableByRef() {
if (this.disabled){
this.$refs.popover.$emit('enable')
}else{
this.$refs.popover.$emit('disable')
}
}
},
props: ['name']
}
You should pass name to your component by attribute, not by data:
<div id="app">
<setting-template name="Elon" />
</div>
Here you can check working example:
https://codepen.io/anon/pen/dwrOqY?editors=1111
data is component private data - it's not passed to child components.
If you still need name in your main component data you can pass it to the child component like this:
<div id="app">
<setting-template :name="name" />
</div>
var app = new Vue({
el: '#app',
components: {
settingTemplate
},
data: {
name: 'Leon'
}
})
https://codepen.io/anon/pen/qLvqeO?editors=1111

How to pass data to nested child components vue js?

I get how to pass data from parent to child with props in a situation like:
<template>
<div>
<div v-for="stuff in content" v-bind:key="stuff.id">
<ul>
<li>
{{ stuff.items }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: stuff,
props: ['content'],
data () {
return {
}
}
}
</script>
And then bind the data to the component in the parent component like,
<template>
<div>
<stuff v-bind:content="stuffToPass"></stuff>
</div>
</template>
<script>
import stuff from './stuff.vue';
export default {
data () {
return {
stuffToPass: [
{id: 1, items: 'foo'},
{id: 2, items: 'bar'},
{id: 3, items: 'baz'}
]
}
},
components: {
stuff
}
}
</script>
But say I have the root component, and I want to pass data to the stuff component, like in the above, but when I have a number of other components like parent > x > y > stuff, and it's still the stuff component that will ultimately be receiving that data, I don't know how to do that.
I heard of provide/inject, but I'm not sure that's the appropriate use, or at least I couldn't get it working.
Then I tried passing props, but then I found myself trying to bind a prop to a component to pass as a prop to a child component and that doesn't sound right, so then I just re-wrote my components in the 'stuff' component, but I feel that's probably re-writing way to much code to be close to reasonable.
there are a few possibilities to pass data parent > x > y > stuff
props - applicable but you would have to pipe the data through all components...
store (vuex) - applicable but could become complicated to handle
event bus - the most flexible and direct way
below, a simple example on how to implement the event bus:
// src/services/eventBus.js
import Vue from 'vue';
export default new Vue();
the code from where you want to emit the event:
// src/components/parent.vue
<script>
import EventBus from '#/services/eventBus';
export default {
...
methods: {
eventHandler(val) {
EventBus.$emit('EVENT_NAME', val);
},
},
...
};
</script>
the code for where you want to listen for the event:
// src/components/stuff.vue
<script>
import EventBus from '#/services/eventBus';
export default {
...
mounted() {
EventBus.$on('EVENT_NAME', val => {
// do whatever you like with "val"
});
},
...
};
</script>
Use watchers or computed properties https://v2.vuejs.org/v2/guide/computed.html
const Stuff = Vue.component('stuff', {
props: ['content'],
template: `<div>
<div v-for="stuff in content" v-bind:key="stuff.id">
<ul>
<li>
{{ stuff.items }}
</li>
</ul>
</div>
</div>`
});
const Adapter = Vue.component('adapter', {
components: { Stuff },
props: ['data'],
template: `<div>
<Stuff :content="newData"/>
</div>`,
data() {
return {
newData: []
};
},
created() {
this.changeData();
},
watch: {
data: {
deep: true,
handler: function() {
this.changeData();
}
}
},
methods: {
changeData() {
this.newData = JSON.parse(JSON.stringify(this.data));
}
}
});
const app = new Vue({
el: '#app',
components: { Adapter },
data() {
return {
stuffToPass: [
{ id: 1, items: 'foo' },
{ id: 2, items: 'bar' },
{ id: 3, items: 'baz' }
]
};
},
methods: {
addItem() {
this.stuffToPass.push({ id: this.stuffToPass.length + 1, items: 'new' });
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.1/vue.js"></script>
<div id="app">
<button #click="addItem">Add</button>
<Adapter :data="stuffToPass"/>
</div>

Vue.js pass function as prop and make child call it with data

I have a posts list component and a post component.
I pass a method to call from the posts list to the post component, so when a button is click it will be called.
But I want to pass the post id when this function is clicked
Code:
let PostsFeed = Vue.extend({
data: function () {
return {
posts: [....]
}
},
template: `
<div>
<post v-for="post in posts" :clicked="clicked" />
</div>
`,
methods: {
clicked: function(id) {
alert(id);
}
}
}
let Post = Vue.extend({
props: ['clicked'],
data: function () {
return {}
},
template: `
<div>
<button #click="clicked" />
</div>
`
}
as you can see in Post component you have a click that runs a method he got from a prop, I want to add a variable to that method.
How do you do that?
Normally, the click event handler will receive the event as its first argument, but you can use bind to tell the function what to use for its this and first argument(s):
:clicked="clicked.bind(null, post)
Updated answer: However, it might be more straightforward (and it is more Vue-standard) to have the child emit an event and have the parent handle it.
let Post = Vue.extend({
template: `
<div>
<button #click="clicked">Click me</button>
</div>
`,
methods: {
clicked() {
this.$emit('clicked');
}
}
});
let PostsFeed = Vue.extend({
data: function() {
return {
posts: [1, 2, 3]
}
},
template: `
<div>
<post v-for="post in posts" #clicked="clicked(post)" />
</div>
`,
methods: {
clicked(id) {
alert(id);
}
},
components: {
post: Post
}
});
new Vue({
el: 'body',
components: {
'post-feed': PostsFeed
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<post-feed></post-feed>
Using Vue 2 and expanding on #Roy J's code above, I created a method in the child component (Post) that calls the prop function and sends back a data object as part of the callback. I also passed in the post as a prop and used its ID value in the callback.
Back in the Posts component (parent), I modified the clicked function by referencing the event and getting the ID property that way.
Check out the working Fiddle here
And this is the code:
let Post = Vue.extend({
props: {
onClicked: Function,
post: Object
},
template: `
<div>
<button #click="clicked">Click me</button>
</div>
`,
methods: {
clicked() {
this.onClicked({
id: this.post.id
});
}
}
});
let PostsFeed = Vue.extend({
data: function() {
return {
posts: [
{id: 1, title: 'Roadtrip', content: 'Awesome content goes here'},
{id: 2, title: 'Cool post', content: 'Awesome content goes here'},
{id: 3, title: 'Motorcycle', content: 'Awesome content goes here'},
]
}
},
template: `
<div>
<post v-for="post in posts" :post="post" :onClicked="clicked" />
</div>
`,
methods: {
clicked(event) {
alert(event.id);
}
},
components: {
post: Post
}
});
new Vue({
el: '#app',
components: {
'post-feed': PostsFeed
}
});
And this is the HTML
<div id="app">
<post-feed></post-feed>
</div>
this is the service:
export const getBuilding = () => {
console.log("service");
return 0;
};
in the parent component:
<Update-Theme :method="parentMethod"/>
import { getBuilding } from "./service";
methods: {
parentMethod() {
console.log("Parent");
getBuilding();
},
}
and in the child component
<v-btn color="green darken-1" text #click="closeDialog()">
props: [ "method"],
methods: {
closeDialog() {
this.method();
//this.$emit("update:dialog", false);
},
}

Categories

Resources