Basically I want to be able to access some centralized data by setting up a dataBus as a vue instance object, and then access and tweak this data from different components.
I cant seems to access by data from my componenets, even basic string interpolation is not getting rendered to the DOM.
export const dataBus = new Vue({
data: {
numQuotes: 4,
stringVar: 'Hellow There'
}
});
I also tried setting up my data as the return of the function data(). But being as my data bus is an actual vue instance I don't think this is correct. (I could be wrong). Following is the component in which I import my dataBus and try to output my data.
<template>
<div>
<h1>Quotes Added</h1>
<div id="trackerBar">
<div id="trackerBarActual">
<h2>{{numQuotes}}/10</h2>
</div>
</div>
</div>
</template>
<script>
import { dataBus } from '../main.js';
export default{
}
</script>
I am getting the following error: Property or method "numQuotes" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
Am I missing something obvious? Is it even possible to access data this way? Or do I have to access it as a method?
You're missing the part where you assign data to your component. Try
<script>
import { dataBus } from '../main.js';
export default{
data () {
return dataBus.$data
}
}
</script>
You should definitely look into Vuex for state management though.
Related
I found a seloution for how to access to vue-router and other services that works only inside the vue component. In the created option of App.vue i save the "this" of vue app inside state of vuex.
does it's a good way or can make some problems in future?
instead to write:
this.$router.push('route-name')
from some component, is save the this keyword in the state as context key for example,
and now from the Actions i'm using the context instead this
such like this:
state.context.router.push('route-name')
and its works..
my question is if its good solution or not.
I think that is not a good solution, if you want to use this, you should try with the actions or getter returned value, inside a Vue file instead using it directly in an action.
I'm giving an example and an explanation
Example:
Getter:
export function getRedirect(state){
return state.routerName
}
Vue file:
<template>
Page
<button #onClick="redirect" > Redirect </button>
</template>
<script>
import {mapGetters} from 'vuex'
export default: {
computed:{
...mapGetters('VuexStoreName',['getRedirect'])
},
methods:{
redirect(){
this.$router.push(this.getRedirect)
}
}
}
</script>
So, instead of using the redirect inside an JS file, creating an action and passing this inside the parameter or getting it by state, you'll be using it correctly in a Vue file.
The probblem setting this in the state is that when it changes the instance saved will not change, and you'll have to update every time and everywhere. And calling this inside a Vue file, it'll always be updated
Hopefully this is an easy fix and i can just chalk it up to my inexperience with Vue
In my main template, I can use v-for to access any objects in the templates data return and I'm successfully loading a separate component in my html
However, when I try to access info from that external component outside of my component call it doesn't show.
I'm trying to create something that I can turn into a modal which would be separate from all imported components but still be able to access data from any component in my main template's modal
How can I access data from any called component in my main template?
<template>
<!--this content shows-->
<subItem-component></subItemComponent>
<!--this doesn't-->
<p v-for="subItem in subItems>{{ subItem.title }}</p>
</template>
subitemComponent
data() {
return {
subItems: [],
}
}
You cannot access the scope of a child component within the parent. Usually, you would load the required data in the parent, if you are needing it there, and then pass it along to the child component as a prop like this:
ParentComponent:
<template>
<sub-item-component sub-item="subItem"></sub-item-component>
<p v-for="subItem in subItems>{{ subItem.title }}</p>
</template>
<script>
import SubItemComponent from '...';
export default {
name: 'ParentComponent',
components: {
SubItemComponent
},
data () {
return {
subItems: []
};
}
}
</script>
SubItemComponent:
<template>
{{ subItem }}
</template>
<script>
export default {
name: 'SubItemComponent',
props: {
subItem: {
type: Array,
required: true
}
}
}
</script>
You could also use a Vuex store to persist the data in one place. With this approach you would have access to the data from each component and do not have pass the data from component to component. To use a store like Vuex, you need to define a Vuex state and at least one mutation method to add the data.
If you want to communicate from the child up to the parent, the way to go would be by using events. You would use a listener on the child component in the parent component like this:
<sub-item-component #new-sub-item="handleNewSubItem"></sub-item-component>
You need to define a method handleNewSubItem in the parent, which is reacting each time the new-sub-item event is thrown in the child component.
The event can then be thrown within the script part of the child component like this:
const subItem = { test: 123 };
this.$emit('new-sub-item', subItem);
You don't. Your options are:
The parent component needs to manage the data and pass it down to its children via props. Child components can then subsequently emit events which the parent can listen for and modify its state.
Use a state handler outside of both the components like Vuex or Apollo (if using GraphQL).
I am exporting a value from a JS file and using it in my Vue. I display the value like in my template, but I would like to also use this value elsewhere, outside of the template.
Here is a simplified version of my setup and what I would like to achieve:
In my myJS.js (in actual app this file is used to call my API):
const appService = {
getPosts() {
return 123456;
}
}
export default appService
and then I have a VUE component that looks like this:
<template>
{{ info }}
</template>
alert(info);
import appService from '../myJS'
export default {
name: 'myvue',
props: {
msg: String
},
data () {
return {
info: {}
}
}
async created () {
this.info = await appService.getPosts();
}
}
The value is displayed in the template, but the alert(info) triggers a 'info is undefined' error.
How can I use this value in normal JavaScript outside of my template?
Hope that makes sense.
Thanks in advance!
There's basically two ways:
Assign the value to a variable, inside the file, but outside the component definition. So in your example you would say let info; and in your created() hook you would go this.info = info = await appService.getPosts().
Assign the component itself to a variable before you export it:
const myComponent = { component definition... }
// Access with myComponent.info
export default myComponent;
However! You will see that myComponent.info is initially undefined. And unlike in the template, the value of info will not reactively update when the asynchronous call resolves. Reactivity magic only works in the template and in the code of the actual component, e.g. in computed and watch properties. How to handle the specifics of asynchronous loading elegantly really depends on the specifics of how you want to use this variable.
Finally: the reason you don't just get access to the variable throughout the .vue file is because under the hood, the template compiles to a function which is executed in the context of the component. For convenience, all of the fields of the component are then made available as variables without the usual this prefix. In fact, in your template, info is treated as a shorthand for this.info. (Notice that you can substitute this.info for info in the template and it will still work.) This privilege doesn't apply to any other code in the file; that stuff is just vanilla js code.
I'm starting to make a universal input vue component. Before I worry about changing the data in the input, I just wanted to get the initial value from the store.
I have something like this:
<template lang="html">
<input class="input-text" type="text" name="" :value="value">
</template>
<script>
import store from '#/store/index';
export default {
name: 'InputText',
props: [
'dataModel',
'propertyName',
],
computed: {
value() {
return store.state[this.dataModel][this.propertyName];
},
},
};
</script>
This works. Instead of the value function in computed. I wanted to leverage mapGetters. So I tried something like this instead:
...mapGetters({
value: `${this.dataModel}/${this.propertyName}`,
}),
As soon as I tried the latter I got undefined for both values this.dataModel and this.propertyName. The context of this changes when invoking mapGetters because were in a new object. Is there a way to pass component props into mapGetters? Is there a way to set the context of this to be the component rather than the object argument? Or was my original approach/another approach the correct way to tackle this problem?
First, don t import the store in components, its available as this.$store, so remove:
import store from '#/store/index';
You can't use this like you are in mapGetters because it doesn't exist in the context youre trying to use it yet. The component is still early in it's lifecycle when when setting up properties. As far as I know, the name must be defined beforehand.
I'm trying to pass php/laravel data to my component from a custom global variable. I've seen examples of this going into the new Vue({}) area directly but I haven't seen any way to pass this by going into right into the component
<script>
var itemData = //json object
</script>
<custom-component item-data="ITEMDATAVAR"></custom-component>
I should specify that I do have item-data in my component props. The issue is that I'm not sure how to tell my component's html that I'm passing the value of the variable itemData and not the string "itemData"
I think you are referring to dynamic props
<custom-component v-bind:item-data="ITEMDATAVAR"></custom-component>
or use the shorthand syntax
<custom-component :item-data="ITEMDATAVAR"></custom-component>
You should add the item-data to the props array like this:
Vue.component('custom-component', {
props: ['item-data'],
...
}
You can research this Vue.js example
Create a variable
new Vue({
el: '#el',
data: yourJsonObject
})
In you component you have to write about props
Vue.component('custom-component', {
props: ['item-data']
...
}
Pass the data to the component the same way
<custom-component item-data="ITEMDATAVAR"></custom-component>
I have not tested how it will work, guided by the documentation.