I am trying to pass a variable (here, externalVar) to a component, directly when initializing. But I can't find how to do it (probably not understanding documentation well :/ ). What is the correct way to do it?
The initialization :
var externalVar = "hello world"
const leftmenu = new Vue({
el: "#left-menu",
template: "<CLM/>",
components: {CLM},
variableToPass: externalVar
});
The component I am initializing here is defined like this (getting back variableToPass in data):
<template src="./template-l-m.html"></template>
<script>
import draggable from 'vuedraggable';
export default {
name: 'leftmenu',
components: {
draggable
},
data () {
return {
jsonObject: this.variableToPass,
}
},
[ ... ]
</script>
But then , when I am trying to use this.jsonObject, it says that it's undefined. What am I doing wrong ?
If i understand you correctly you want to use props to pass data to child components
Dynamically bind a prop attribute on child component element using :variable="variableToPass"
var externalVar = "hello world"
const leftmenu = new Vue({
el: "#left-menu",
template: "<CLM :variable='variableToPass'/>",
components: {CLM},
data: {
variableToPass: externalVar
}
});
Define a props option in the child component
<template src="./template-l-m.html"></template>
<script>
import draggable from 'vuedraggable';
export default {
name: 'leftmenu',
components: {
draggable
},
props: ['variable'],
data () {
return {
jsonObject: this.variable,
}
},
[ ... ]
</script>
Use data.
var externalVar = "hello world"
const leftmenu = new Vue({
el: "#left-menu",
template: "<CLM/>",
components: {CLM},
data: {
variableToPass: externalVar
}
});
That way you can access your variable like this this.$data.variableToPass
Use $options
in child component
mounted() {
console.log(this.$parent.$options.variableToPass) // hello world
this.jsonObject = this.$parent.$options.variableToPass
}
Related
Let's say I have some data in a Vue component (we'll call it Data.vue) like this:
<script>
export default {
data(){
return{
data1: {some data}
}
}
}
</script>
I want to use that data on another page (Main.vue) in a method.
<script>
export default {
methods: {
someMethod: function(){
console.log(this.data1)
}
}
}
</script>
How would I go about doing this?
I did try importing it the data to "Main.vue" like this:
import { data1 } from '#/components/Data'
What other steps do I need to take?
Your Q is too general because It depends (From child to parent? global data? read-only data? and so on).
One basic way is by props. Example: Pass data (array/object/string and so on) From parent-to-child
https://v2.vuejs.org/v2/guide/components-props.html
"Hello world example"
Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('child', {
// camelCase in JavaScript
props: ['message_from_parent'],
template: '<h3>{{ message_from_parent }}</h3>',
created: function () {
console.log(this.message_from_parent)
}
})
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<child v-bind:message_from_parent="message"></child>
</div>
Or the opposite (From child to parent) by $emit:
https://v2.vuejs.org/v2/api/#vm-on
You may have more than one component Data and then it doesn't becomes clear which one you want to share.
If you have only one component then you can just export data
<script>
const data1 = {some data}
export { data1 }
export default {
data () {
return {
data1
}
}
}
</script>
and then your import should work.
import { data1 } from '#/components/Data'
But this is kindof hacky, you should use a store live vuex
Can anyone look through this snippet of code and tell me why I'm getting this error ?
json is undefined
(in reference to test: json below).
I've defined it, directed it to the correct component, and the json is being fetched correctly (i can see the entire object in the console). So why can't my component display it? Thanks in advance to any vuejs users who can help me with this.
The .vue file:
<template>
<div id="app">
{{ test }}
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
test: json
}
}
}
</script>
the .js file:
new Vue({
el: '#app',
data: () => ({
json: {}
}),
created: function () {
apigClient.invokeApi(apiPathParams, apiPathTemplate, apiMethod, apiAdditionalParams, apiBody).then((response) => {
this.json = response
console.log(this.json)
})
router,
template: '<app/>',
components: { App }
})
try to pass that json variable as props or define it before export default{ ...
in the main.js send that json to child component as follow :
...
template: '<app :json="json"/>'
...
in the child component receive it like:
export default {
props:["json"],
name: 'app',
data () {
return {
test: this.json
}
}
}
I tried with props and PropsData but it is not working :/
import Vue from 'vue'
import Hello from '#/components/Hello.vue'
export function createComponent(selector, params) {
const test = {name: 'Test'};
new Vue({
el: selector,
render: app => app(selector, {
propsData: test
})
})
}
I can't find why this is not possible even with some console.log here and there, i'm not really confident with VueJS so is there a way to do that ?
Edit:
After some testings, props was correctly passed by what I wrote, It seems that I am not correctly passing the component name to the Vue instance:
Here is how my code works (or how i want it to works at least...):
Random php file:
<?php
$selector = "Hello";
$data = json_encode(['name' => 'from PHP'])
?>
<div id="<?= $selector; ?>-component"></div>
<script>
createComponent(<?= $selector; ?>, <?php return $data; ?>) // I tried "$selector" format, but doesn't work either.
</script>
My main js file
import Vue from 'vue'
import Hello from '#/components/Hello'
export function createComponent(selector, params) {
new Vue({
el: '#' + selector + '-component',
render: app => app(selector, { // If I replace selector by Hello, it works, but that's not what I want.
props: params
})
})
}
In this file I tried some tricks to call the component from 'selector' but the console tells me: ReferenceError: Hello is not defined
But as we can see Hello is clearly define at the top of the file.
My single file vue component:
<template>
<h1>
Hello {{ name }}!!
</h1>
</template>
<script>
module.exports = {
props: {
name: {
type: String,
default: 'World'
}
}
}
</script>
I simplified my php code to show you the case so there may have some errors, I haven't tried it.
The mistake must come from the syntax, or else I get it wrong.
PS: I hate JS syntax :)
import Vue from 'vue'
export function createComponent(selector, propsData) {
let instance = new Vue({
el: document.createElement('div'),
render(createElement) {
return createElement(
'h' + this.level, // tag name
this.$slots.default // array of children
)
},
propsData
})
document.body.querySelector(selector).appendChild(instance.$el);
}
Assuming that you want to create dynamically VueJS instance and append it to dom. Also propsData object you need to move out from render function. Render function is optional, you can always use template string...
With some help from StackOverflow I got the following to run my loadData when the page loads and when the button is clicked.
However the text on the page is not updating. Something is wrong about my syntax with this.text = xhr.data
index.html:
<div id="app"></div>
app.js:
const Vue = window.Vue = require("vue");
Vue.prototype.$http = require("axios");
const App = require("./components/App.vue");
window.app = new Vue({
el: "#app",
render: h => h(App)
});
components/app.vue:
<template>
<div>
<h1>Test</h1>
<p>{{text}}</p>
<button #click="this.loadData">Reload</button>
</div>
</template>
<script>
export default {
mounted() {
this.loadData();
},
methods: {
loadData() {
this.$http.get("https://icanhazip.com")
// This fails
.then(xhr => this.text = xhr.data);
}
}
};
</script>
You must to define your text property in components data.
From Vue.js documentation:
Due to the limitations of modern JavaScript (and the abandonment of Object.observe), Vue cannot detect property addition or deletion. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive. For example:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` is now reactive
vm.b = 2
// `vm.b` is NOT reactive
In your case your component should look like this:
<script>
export default {
created() {
this.loadData();
},
data() {
return {
text: '',
};
},
methods: {
loadData() {
this.$http.get("https://icanhazip.com")
// This fails
.then(xhr => this.text = xhr.data);
}
}
};
</script>
I have a method initialized within the parent component called setMessage() and I'd like to be able to call it within the child component.
main.js
const messageBoard = new Vue({
el: '#message-board',
render: h => h(App),
})
App (App.vue (parent))..
export default {
data() {
return { messages: state }
},
methods: {
setMessage(message) {
console.log(message);
}
},
template: `
<div>
<child-component></child-component>
</div>
`,
}
child
const child = Vue.extend({
mounted() {
// attempting to use this function from the parent
this.$dispatch('setMessage', 'HEY THIS IS MY MESSAGE!');
}
});
Vue.component('child-component', child);
Right now I'm getting this.$dispatch is not a function error message. What am I doing wrong? How can I make use of parent functions in various child components? I've also tried $emit, it doesn't throw an error & it doesn't hit the function.
Thank you for your help in advance!
You have a couple options.
Option 1 - referencing $parent from child
The simplest is to use this.$parent from your child component. Something like this:
const Child = Vue.extend({
mounted() {
this.$parent.setMessage("child component mounted");
}
})
Option 2 - emitting an event and handling in parent
But that strongly couples the child to its parent. To fix this, you could $emit an event in the child and have the parent handle it. Like this:
const ChildComponent = Vue.extend({
mounted() {
this.$emit("message", "child component mounted (emitted)");
}
})
// in the parent component template
<child-component #message="setMessage"></child-component>
Option 3 - central event bus
One last option, if your components don't have a direct parent-child relationship, is to use a separate Vue instance as a central event bus as described in the Guide. It would look something like this:
const bus = new Vue({});
const ChildComponent = Vue.extend({
mounted() {
bus.$emit("message-bus", "child component mounted (on the bus)");
}
})
const app = new Vue({
...
methods: {
setMessage(message) {
console.log(message);
}
},
created() {
bus.$on('message-bus', this.setMessage)
},
destroyed() {
bus.$off('message-bus', this.setMessage)
}
});
Update (Option 2a) - passing setMessage as a prop
To follow up on your comment, here's how it might work to pass setMessage to the child component as a prop:
const ChildComponent = Vue.extend({
props: ["messageHandler"],
mounted() {
this.messageHandler('from message handler');
}
})
// parent template (note the naming of the prop)
<child-component :message-handler="setMessage"></child-component>
// parent component providing 'foo'
var Provider = {
methods: {
foo() {
console.log('foo');
},
},
provide: {
foo: this.foo,
},
}
// child component injecting 'foo'
var Child = {
inject: ['foo'],
created() {
this.foo() // => "foo";
},
}