Vue - How to pass data to child component after route is entered - javascript

Hey I'm relatively new to vue.js.
I have a Home.vue which creates a data array after successful login and entering the route.
I tried it with
<template>
<div class="home">
***
<History :data="this.cData" />
***
</div>
</template>
***
beforeRouteEnter(to, from, next) {
next(async (vm) => {
vm.cData = await vm.select(vm.handle);
console.log(vm.cData);
});
},
But the data is send before beforeRouteEnter() and the History component needs it for creating itself.
Is there a way do to it?

If the History component needs it for creating itself, then you should defer creation of the component (with v-if) until cData is ready. cData should be declared upfront in the data object with value null.
You're also doing this.cData in the template but it should be just cData.
<History v-if="cData" :data="cData" />

Related

Component's data property is not reactive when fetched via fetch method

I have a simple "show" component that fetches some data via an API call and renders it on the page.
<template>
<div class="showNote">
<div>
{{note.title}}
</div>
</div>
</template>
<script>
import NotesAPI from '#/api/notes'
export default {
data() {
return {
note: {}
}
},
async fetch() {
let id = this.$route.params.id
let response = await NotesAPI.fetchNote(id)
let data = response.data
this.note.title = data.title
}
}
</script>
I'm finding that the rendered template is blank even though the data has been fetched and set on the data field. I can confirm this via the Vue Inspector
It seems like the data property is not reactive and I'd need some way to force the re-rendering of the page. But obviously this would be the wrong approach. What am I missing? Why is the component not rendering my data changes?
Try to use this.$set to set nested value of an object :
this.$set(this.note,'title', data.title)

How to pass variable data between components in Vue js

Here I'm trying to pass the variable header_url data to my other vue pages. Since I also want to use this for push and post methods in the other vue script tags. I'm not sure how to do it? Since, I can only find examples with data been transferred between html tags.
// Home.vue
<template>
<div>
Home
<h2>logout</h2>
<a v-bind:href="url">logout</a>
</div>
</template>
<script>
export default {
data: () => ({
url:"https:..."
})
}
var header_url = window.location.href;
if (header_url.length>100) {
var token=window.location.href.match(/\#(?:id_token)\=([\S\s]*?)\&/)[1]; // eslint-disable-line
console.log(token);
}
</script>
To pass data between two URLs in single page app, you need use Vue Router
and Route Meta Fields.
From the docs :
Sometimes, you might want to attach arbitrary information to routes like transition names, who can access the route, etc. This can be achieved through the meta property which accepts an object of properties and can be accessed on the route location and navigation guards

Get list of slot names from Vue template

I'm creating an interactive style guide for some custom components we've created at my job. It goes through the list of globally registered components and then displays their props. The user can then edit the prop values and see how it affects the rendered component.
Right now I need to figure out how to allow interaction with slots for certain components we have. For example, we have our own button component that looks something like this:
<template>
<button :class="customClasses">
<slot></slot>
</button>
</template>
I have a componentPreviewRenderer component that shows a rendering of our custom components. It looks something like this:
export default {
props: {
component: String, //The name of the global component to render
props: Object //List of component props
},
render (createElement): {
return createElement(
this.component,
{
props: this.props
}
);
}
}
I need to (1) find out if the component's template I'm rendering has slots and (2) get a list of the slot names so I can pass it into the createElement() function and let the user edit the slot values. For example, for the button component they should be able to edit the "default" slot which controls the text appearing on the button.
I've already looked at this article but I'd like to be able to get the slot names directly from the Vue component I'm rendering instead of having to parse through the .vue file. I tried things like Vue.component(this.component).$slots but $slots is undefined. Does anyone know how I would get the slot names for the component being rendered?

Vue.js component within component, manipulate parent data

ive seen afew answers that sort of answer my question but not fully, so let me explain what I want to do.
We use a global #app div within the layout of our website, which is a Laravel project. So all pages will be the same main Vue instance, due to this i'm separating key functionality into components.
So, the first example is just a simple Tab component, this either separates any children into tabs, or accepts some data which the single child component then renders.
So below i'm injecting some data from another component, this ajax component literally just does an ajax call, and makes the data available within it's slot.
<ajax endpoint="/api/website/{{ $website->id }}/locations/{{ $location->slug }}/get-addresses">
<div>
<tabs :injected="data">
<div>
<div v-for="row in data">
#{{ row['example' }}
</div>
</div>
</tabs>
</div>
</ajax>
Now this is all well and good, to a point, but this falls down with the below code. This contains a component which will allow the used to drag and drop elements, it re-arranges them by literally moving the data around and letting Vue handle the DOM changes.
This will of course work fine within it's own data which you have injected in, but when you change the data within the component below this then clears this child component.
<ajax endpoint="/api/website/{{ $website->id }}/locations/{{ $location->slug }}/get-addresses">
<div>
<tabs :injected="data">
<div>
<div v-for="row in data">
<draggable :injected="row">
<div>
<div v-for="item">
#{{ item }}
</div>
</div>
</draggable>
</div>
</div>
</tabs>
</div>
</ajax>
I need to find a way to make any changes to this data apply to the parent data, rather than the data passed into the child components.
What is the best practice to do this!?
Edit 1
Basically, I need any child component's manipulate the data within the ajax component. The children within ajax could change, or there could be more, so I just need them all to do this without knowing what order or where they are.
It is hard to come up with specifics on this one, but I am going to try to put you in the right direction. There are three ways to share data between components.
1) Passing down data via props, emitting data up via custom events
The passing down of data via props is a one-way street between the parent and child components. Rerendering the parent component will also re-render the child and data will be reset to the original state. See VueJS: Change data within child component and update parent's data.
2) Using a global event-bus
Here you create an event bus and use this to emit the data to different components. All components can subscribe to updates from the event bus and update their local state accordingly. You initiate an event bus like this:
import Vue from 'vue';
export const EventBus = new Vue();
You send events like this:
import { EventBus } from './eventbus.js'
EventBus.$emit('myAwsomeEvent', payload)
And you subscribe to events like this:
import { EventBus } from './eventbus.js'
EventBus.$on('myAwsomeEvent', () => {
console.log('event received)
})
You still need to manage state in the components individually. This is a good start with an Event bus: https://alligator.io/vuejs/global-event-bus/
3) Using Vuex
Using Vuex extracts the component state into the Vuex store. Here you can store global state and mutate this state by committing mutations. You can even do this asynchonously by using actions. I think this is what you need, because your global state is external to any components you might use.
export const state = () => ({
resultOfAjaxCall: {}
})
export const mutations = {
updateAjax (state, payload) {
state.resultOfAjaxCall = payload
}
}
export const actions= {
callAjax ({commit}) {
const ajax = awaitAjax
commit('updateAjax', ajax)
}
}
Using vuex you keep your ajax results separated from your components structure. You can then populate your state with the ajax results and mutate the state from your individual components. This way, it doesn't matter whether you recall ajax, or destroy components since the state will always be there. I think this is what you need. More info on Vuex here: https://vuex.vuejs.org/

Vuejs components to wait for initialisation

To give some context, I've a vuejs application using vue-router and vuex.
app.vue Bootstrap code
foo.vue Some component that renders on route /foo
bar.vue Some component that renders on route /bar
When the application starts I need to sync the state reading from device storage. Since this is an async operation it's wrapped on a vue-action and called on app.vue.
When entering the /foo route by the time the component is mounted the $store is not yet update from the device storage
How can all components ensure the initialisation is made before they are mounted?
What I do in these situations is use a v-if on your root <router-view> element to render only when the data you expect to be there has populated, e.g.
<script>
export default {
computed: {
hasLoadedData() {
// Or whatever criteria you decide on to represent that the
// app state has finished loading.
return this.$store.state.something !== null;
}
}
}
</script>
<template>
<div id="app">
<router-view v-if="hasLoadedData" />
<p v-else>Loading...</p>
</div>
</template>

Categories

Resources