Vue, access variable in parent component - vue.js

I want to access topicCategories in child component. I've tried $this.$parent.$parent.topicCategories but it is undefined, even though i can see it in console?
So i tried the below method but this only shows topicCategories of the previous page not the current page. So first time you view a post, it is empty, then the next post, you see the topicCategories of the previous post.
parent (post.vue)
this.topicCategories = this.Categories.map((category: any) => category.id);
this.$store.dispatch('app/setCurrentCategories', topicCategories);
child component (read.vue)
if(this.$store.state.app.currentCategories.length) {
const categories = this.$store.state.app.currentCategories.map((category: any) => category.id);
}
How do i get topicCategories in the child component of the current page?

Related

How do I pass a value to state from another page?

For routing I use react-navigation.
There are two pages :
HomePage (main page).
HomePageList(main page only all items in list view)
Need to do so:
When I click on an item from the list on the HomePageList page. Must pass a value in state to the HomePage page.
Let's say I click on the 12 element on the HomePageList page.
On Numerate to state activeSlide should be passed 12.
There is an array of 6 elements there.
On page - HomePage. Slider with pagination . The Index of the object is stored in state. In the activeslide value.
Visit HomePageList all the same 6 element.Only list and search.
When I click on any element of the HomePageList. Occurs _GoHome.
_GoHome = async ( ) => {
this.props.navigation.navigate(HOMEPAGE);
};
As I pass through the function of another item.index in state HomePage.
I tried to do it this way:
To make a sort of constant ActiveSlide in a separate file which you want to save the item.index.
Then in HomePage to do so:
if (ActiveSlide !== null){
this.setState({
activeSlide: ActiveSlide
})
}else{
this.setState({
activeSlide: 0
})
}
But for some reason doesn't work says:
Error: ActiveSlide read only
With react navigation you can pass parameters in navigate()
On the view that wants to pass the parameter:
this.props.navigation.navigate(HOMEPAGE, { something: value })
On the view that wants to receive the paramter:
value = this.props.navigation.getParam('something')
See the docs here

vuejs where in the code/lifecycle should data retrieval be triggered

I am working on a vuejs SPA.
I have a view that shows a list of items and another view that shows details for a specific Item.
when I click the item I switch views using:
this.$router.push('/item/' + event.ItemId );
The data is managed using vuex modules.
I would like to allow some temporary display while the item details are being retried (i.e. not to block the rendering of the item details view which should know on its own to indicate that it is still awaiting data).
And I would also have to consider that it should work if the URL is changed (I think I read that there is an issue with the view not being reloaded/recreated when only the item id would change in the URL.
Where would be the appropriate place (code/lifecycle) to trigger the (async) retrieval of the data required for rendering the item details view?
I would like to allow some temporary display while the item details are being retried (i.e. not to block the rendering of the item details view which should know on its own to indicate that it is still awaiting data).
One way to achieve this, is to define a state variable, named e.g. isLoading, in the data context of the Vue component. This variable would then be true while the data is retrieved asynchronously. In the template, you can use v-if to display a spinner while loading, and displaying the content after that.
If you are retrieving the data multiple times (refreshing the view), I would move the retrieving code into a method, e.g. called loadData. In the mounted section of the Vue component you then can just initially call this method once.
Here is some example code:
<template>
<div>
<button #click="loadData" :disabled="isLoading">Refresh</button>
<div class="item" v-if="!isLoading">
{{ item }}
</div>
<div class="spinner" v-else>
Loading...
</div>
</div>
</template>
<script>
import HttpService from '#/services/HttpService';
export default {
name: 'item-details',
data () {
return {
isLoading: false,
item: {}
};
},
methods: {
loadData () {
this.isLoading = true;
HttpService.loadData().then(response => {
this.item = response.data;
this.isLoading = false;
}, () => {
this.item = {};
this.isLoading = false;
});
}
},
mounted () {
this.loadData();
}
};
</script>
And I would also have to consider that it should work if the URL is changed (I think I read that there is an issue with the view not being reloaded/recreated when only the item id would change in the URL.
This issue you mentioned occurs if you are not using the HTML5 history mode, but an anchor (#) in the URL instead. If you are just changing the part after the anchor in the URL, the page is not actually refreshed by the browser. The Vue component won't be reloaded in this case and the state is still old. There are basically two ways around this:
You are switching from anchors in the URL to a real URL with the HTML5 history mode, supported by the Vue Router. This requires some back-end configuration, though. The browser then does not have this faulty behavior, because there is no anchor. It will reload the page on every manual URL change.
You can watch the $route object to get notified on every route change. Depending on if the user is changing the part after the anchor, or before, the behavior is different (it also depends where the cursor is, when you hit enter). If the part after the anchor is changed (your actual Vue route), only the component is notified. Otherwise, a full page refresh is made. Here's some example code:
// ...inside a Vue component
watch: {
'$route' (to, from) {
this.loadData();
}
}

Vuejs 2 - watch route when going from child to parent

I have the following route structure
/event/:id/schedule/:id
What I want is that, when the user goes to a child component/route, some elements of the parent hide. When the user goes back to the parent, those elements should come back.
On the parent component, i've tried watching the $route object, but nothing is triggered. Attaching hooks at mounted/created methods of the parents component, won't work, because the user is still in those routes. I saw something about
watch(){
$route: {
console.log('route change');
}
}
I also tried this:
route: {
canReuse: false
},
It didn't work, and if it didn't, I wouldn't want to use it.
Any other ideas would be really helpful. thanks.
just discovered some route hooks/navigation guards in the vue-router docs.Just used the following for to the parent component.
beforeRouteUpdate (to, from, next) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, for a route with dynamic params /foo/:id, when we
// navigate between /foo/1 and /foo/2, the same Foo component instance
// will be reused, and this hook will be called when that happens.
// has access to `this` component instance.
},
this worked perfectly
You need quotes around the $route object in this context:
watch: {
'$route': {
console.log('route change');
}
}

how can component delete itself in Vue 2.0

as title, how can I do that
from offical documentation just tell us that $delete can use argument 'object' and 'key'
but I want delete a component by itself like this
this.$delete(this)
I couldn't find instructions on completely removing a Vue instance, so here's what I wound up with:
module.exports = {
...
methods: {
close () {
// destroy the vue listeners, etc
this.$destroy();
// remove the element from the DOM
this.$el.parentNode.removeChild(this.$el);
}
}
};
Vue 3 is basically the same, but you'd use root from the context argument:
export default {
setup(props, { root }){
const close = () => {
root.$destroy();
root.$el.parentNode.removeChild(root.$el);
};
return { close };
}
}
In both Vue 2 and Vue 3 you can use the instance you created:
const instance = new Vue({ ... });
...
instance.$destroy();
instance.$el.parentNode.removeChild(instance.$el);
No, you will not be able to delete a component directly. The parent component will have to use v-if to remove the child component from the DOM.
Ref: https://v2.vuejs.org/v2/api/#v-if
Quoted from docs:
Conditionally render the element based on the truthy-ness of the expression value. The element and its contained directives / components are destroyed and re-constructed during toggles.
If the child component is created as part of some data object on parent, you will have to send an event to parent via $emit, modify (or remove) the data and the child component will go away on its own. There was another question on this recently: Delete a Vue child component
You could use the beforeDestroy method on the component and make it remove itself from the DOM.
beforeDestroy () {
this.$root.$el.parentNode.removeChild(this.$root.$el)
},
If you just need to re-render the component entirely you could bind a changing key value to the component <MyComponent v-bind:key="some.changing.falue.from.a.viewmodel"/>
So as the key value changes Vue will destroy and re-render your component.
Taken from here

Aurelia set element on ViewModel

How would you add a component to a View from the ViewModel. For example, I have the following:
I have a service injected into a component. Then from the component I fetch data and when I get the response I set the data property to the fetched data. After this I would like to mount the component to the View with the fetched data as a bindable.
this.service.get()
.then(response => response.json())
.then(data =>{
this.data = data.results
//Mount element to View here: <component data.bind="data"></component>
})
Im asking this question because if I set the value when fetched and on the View to this:
<component data.bind="data"></component>
It passes an empty object. I have tried using the service on the canActivate and activate methods.
Component:
export class Component{
#bindable data
bind(){
console.log(this.data)
}
}
I copied your code in to a gist and ran it on gist.run here: https://gist.run/?id=04907ff8d8b6d8b4aee625669d8571a3
It runs as expected for me. I even updated it to set the data inside a promise.
Now, if you want to be notified when the data property changes, you'll need to implement a function called ${propertyName}Changed(newValue, oldValue) so in this case, dataChanged(newValue, oldValue). I created a separate gist to show how you might want to change your code: https://gist.run/?id=34a01ca3f600470691d5b91c9131f33b
You'll notice in my code I didn't use the newValue and oldValue parameters. I did this on purpose to let you know that Aurelia still sets the property value. The callback is just there to let your code do stuff when the property value changes.
The "data" field being bound to is a field on the ViewModel using your component, not a field in your component.