Vuejs get current route name and display on the menu - vue.js

I'm using the vue-menu component, and using it to toggle between different routes. After I switch to another route I want to display the current route name on the dropdown header like so:
I've tried using the life-cycle methods such as beforeCreate , created, mounted... etc but none of them are being called. How can I achieve the desired result?

You should use the "watch"
data() {
return {
routeName: null,
};
},
watch: {
'$route': 'currentRoute'
},
methods: {
currentRoute() {
this.$nextTick(() => {
this.routeName = this.$route.name
});
}
},

<script>
export default {
computed:{
routeName(){
return this.$route.name
},
}
};
</script>
<template>
<p>Current Route is {{$route.name}}</p>
</template>
-------------------OR--------------
<script>
export default {
computed:{
routePath(){
return this.$route.path
},
}
};
</script>
<template>
<p>Current Route is {{$route.path}}</p>
</template>
This answer is for vue2.
Also, created lifecycle can also be used by directly returning the route example below
created() {
return this.$route.name
},

Related

Passing the result of a Fetch function to Parent Prop

I'm aware there is many questions about passing between Child to Parent Components, however, all the questions and guides I've seen use a Form Input to display how the $emit function works, and I have had no success in translating this to the result of an API call.
My question is, how do I refactor this code to pass the 'data' upwards into my parent components 'TranslatedText' Prop? It confuses me as I have no input, just the data response. Any tips appreciated.
ParentComponent.vue
<template>
<translation-button v-model="translatedText" />
</template>
props: {
translatedText: '',
},
ChildComponent.Vue
<template>
<b-button type="is-primary" #click="loadTranslations()">Übersetzen</b-button>
</template>
<script>
export default {
name: "TranslationButton",
props: {
TranslatedText: ''
},
methods: {
loadTranslations() {
fetch('http://localhost:3000/ccenter/cc_apis')
.then(function(response) {
return response.text();
})
.then(function(data) {
console.log(data);
})
.finally(() => {
this.$emit('loadTranslations', this.TranslatedText);
console.log('event is a success');
});
}
}
}
</script>
there are several ways to communicate between parent and child.
if you want to pass data from child to parent, you need to use $emit like the below code
child:
<template>
<b-button type="is-primary" #click="loadTranslations()">Übersetzen</b-button>
</template>
<script>
export default {
name: "TranslationButton",
props: {
TranslatedText: ''
},
methods: {
loadTranslations() {
fetch('http://localhost:3000/ccenter/cc_apis')
.then(function(response) {
return response.text();
})
.then(function(data) {
console.log(data);
})
.finally((payload) => { // change added
this.$emit('changeTitle','payload ') // change added
console.log('event is a success');
});
}
}
}
</script>
parent:
<template>
<translation-button #changeTitle="ChangeT" />
</template>
methods:{
ChangeT(title)
{
console.log(title)
},
}
this page is a simple example related to your problem

Why action of Vuex returns a promise<pending>?

I have an action in Vuex actions which commit a mutation that it take a payload from the component, that is a number of the index for returning an object, it works fine on Vuex js file meaning that shows the selected item on the console, as I said it gets index from the payload,
but on the component, it gives me Promise <Pending>, why that's happening? for now, I do not use any API for my Nuxt/Vue app, but I will, and for now, I just want to know why this is happening and what is the best solution for solving this
Here my Vuex codes:
export const state = () => ({
articles: [
{
uid: 0,
img: 'https://raw.githubusercontent.com/muhammederdem/mini-player/master/img/1.jpg',
link: '/articles/1',
},
{
uid: 1,
img: 'https://raw.githubusercontent.com/muhammederdem/mini-player/master/img/2.jpg',
link: '/articles/2',
},
],
})
export const getters = {
getArticles(state) {
return state.articles
},
}
export const mutations = {
getSpeceficArticle(state, payload) {
return state.articles[payload]
},
}
export const actions = {
getSpeceficArticle({ commit }, payload) {
commit('getSpeceficArticle', payload)
},
}
and here my component codes:
<template>
<div class="article">
{{ getSpeceficArticle() }}
<div class="article__banner">
<img src="" alt="" />
</div>
<div class="article__text">
<p></p>
</div>
</div>
</template>
<script>
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
// computed: {},
methods: {
async getSpeceficArticle() {
return await this.$store.dispatch('articles/getSpeceficArticle', 0)
},
},
}
</script>
actions are used to update the state they are like mutations but the main difference between them is that actions can include some asynchronous tasks, if you want to get a specific article at given index you should use a getter named getArticleByIndex :
export const getters = {
getArticles(state) {
return state.articles
},
getArticleByIndex:: (state) => (index) => {
return state.articles[index]
}
}
then define a computed property called articleByIndex :
<script>
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
computed: {
articleByIndex(){
return this.$store.getters.articles.getArticleByIndex(0)
}
},
methods: {
},
}
</script>
#Mohammad if you find yourself using a lot of getters/actions etc from Vuex and they're starting to get a little wordy, you can bring in mapGetters from Vuex and rename your calls to something a little more convenient. So your script would become,
<script>
import { mapGetters } from 'vuex'
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
computed: {
articleByIndex(){
return this.getArticleByIndex(0)
}
},
methods: {
...mapGetters({
getArticleByIndex: 'articles/getArticleByIndex',
})
},
}
</script>
You can add ...mapGetters, ...mapActions to your computed section also.
since there is no web service call in vuex action, try to remove async and await keywords from the component.
Later when you add a webservice call than you can wrap action body in new Promise with resolve and reject and then you can use async and await in component. let me know if this works for you.

vue.js 2 single file component with dynamic template

I need a single file component to load its template via AJAX.
I search a while for a solution and found some hints about dynamic components.
I crafted a combination of a parent component which imports a child component and renders the child with a dynamic template.
Child component is this:
<template>
<div>placeholder</div>
</template>
<script>
import SomeOtherComponent from './some-other-component.vue';
export default {
name: 'child-component',
components: {
'some-other-component': SomeOtherComponent,
},
};
</script>
Parent component is this
<template>
<component v-if='componentTemplate' :is="dynamicComponent && {template: componentTemplate}"></component>
</template>
<script>
import Axios from 'axios';
import ChildComponent from './child-component.vue';
export default {
name: 'parent-component',
components: {
'child-component': ChildComponent,
},
data() {
return {
dynamicComponent: 'child-component',
componentTemplate: null,
};
},
created() {
const self = this;
this.fetchTemplate().done((htmlCode) => {
self.componentTemplate = htmlCode;
}).fail((error) => {
self.componentTemplate = '<div>error</div>';
});
},
methods: {
fetchTemplate() {
const formLoaded = $.Deferred();
const url = '/get-dynamic-template';
Axios.get(url).then((response) => {
formLoaded.resolve(response.data);
}).catch((error) => {
formLoaded.reject(error);
}).then(() => {
formLoaded.reject();
});
return formLoaded;
},
},
};
</script>
The dynamic template code fetched is this:
<div>
<h1>My dynamic template</h1>
<some-other-component></some-other-component>
</div>
In general the component gets its template as expected and binds to it.
But when there are other components used in this dynamic template (some-other-component) they are not recognized, even if they are correctly registered inside the child component and of course correctly named as 'some-other-component'.
I get this error: [Vue warn]: Unknown custom element: some-other-component - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Do I miss something or is it some kind of issue/bug?
I answer my question myself, because I found an alternative solution after reading a little bit further here https://forum.vuejs.org/t/load-html-code-that-uses-some-vue-js-code-in-it-via-ajax-request/25006/3.
The problem in my code seems to be this logical expression :is="dynamicComponent && {template: componentTemplate}". I found this approach somewhere in the internet.
The original poster propably assumed that this causes the component "dynamicComponent" to be merged with {template: componentTemplate} which should override the template option only, leaving other component options as defined in the imported child-component.vue.
But it seems not to work as expected since && is a boolean operator and not a "object merge" operator. Please somebody prove me wrong, I am not a JavaScript expert after all.
Anyway the following approach works fine:
<template>
<component v-if='componentTemplate' :is="childComponent"></component>
</template>
<script>
import Axios from 'axios';
import SomeOtherComponent from "./some-other-component.vue";
export default {
name: 'parent-component',
components: {
'some-other-component': SomeOtherComponent,
},
data() {
return {
componentTemplate: null,
};
},
computed: {
childComponent() {
return {
template: this.componentTemplate,
components: this.$options.components,
};
},
},
created() {
const self = this;
this.fetchTemplate().done((htmlCode) => {
self.componentTemplate = htmlCode;
}).fail((error) => {
self.componentTemplate = '<div>error</div>';
});
},
methods: {
fetchTemplate() {
const formLoaded = $.Deferred();
const url = '/get-dynamic-template';
Axios.get(url).then((response) => {
formLoaded.resolve(response.data);
}).catch((error) => {
formLoaded.reject(error);
}).then(() => {
formLoaded.reject();
});
return formLoaded;
},
},
};
</script>

How make json data available for my Vue dynamic routes

I have a List component where I fetch my date from db/blogs.json:
created() {
fetch('http://localhost:3000/blogs')
.then(response => {
return response.json();
})
.then(data => {
this.blogs = data;
})
},
In my BlogDetail.vue I have:
<script>
export default {
data: () => {
return {
blogId:this.$route.params.id
}
},
computed: {
blog() {
return this.blogs.find(
blog => blog.id === this.blogId
)
}
}
}
</script>
But how do I get the blogs data in this component, which I fetched in the List component?
Because now in the <template> section of my BlogDetail.vue I cannot access e.g. {{ blog.name }}
Update:
I try passing blogs with props:
Now I am accepting a prop in BlogDetails.vue:
props: {
blogs: {
type: Array
}
},
But from where (which component), I have to registering the prop like :blogs="blogs"?
Update 2:
This is what I have so far, link to the sandbox
Here is the working sandbox.
Firstly you need to import JSON data from your JSON file correctly. As:
<script>
import ListItem from "./ListItem";
import Blogs from "../../public/db/blogs.json";
export default {
name: "List",
components: {
ListItem
},
data() {
return {
blogs: Blogs.experiences
};
},
created() {}
};
</script>
Have to send props in the router-link as :
<router-link
:to="{ name: 'BlogDetails', params: { id: blog.id,blog:blog }}">More information
</router-link>
You can send props to the child component in the tag name, in your case:
//LIST component(PARENT)
<tamplate>
<BlogDetail :blogs="blogs"></BlogDetail> //CHILD component
</template>

Watch $route.params.id does not trigger re-render of Vue component

I have a Post component which displays user posts. The URL/Route to get to a post is like:
http://localhost:8080/123-todays-bike-ride with 123 being the PostID param in the route.
In my Post.vue component I have the following code:
<template>
<div>
<h1>{{Post.PostTitle}}</h1>
<p>{{Post.Content}}</p>
</div>
</template>
<script>
export default {
name: "Post",
watch:{
'$route.params.PostID': function() {
this.getPost(); // does not seem to be triggered?
}
},
computed:
{
Post() {
return this.$store.getters.getPost
}
},
serverPrefetch() {
return this.getPost(); // to do with SSR
},
mounted() {
if (this.Post == null || !this.Post.length) {
this.getPost();
}
},
methods: {
getPost() {
return this.$store.dispatch('loadPost', {PostID: this.$route.params.PostID})
}
}
}
</script>
The problem is that even if I navigate from http://localhost:8080/123-todays-bike-ride to say http://localhost:8080/999-swimming then the URL in the browser address bar changes but the content of the Post view does not change – it remains with the same content as the 123-todays-bike-ride post.
Clearly the watch: { '$route.params.PostID'... bit is not working, but why and how to solve it?
You can try and make it watch deep:
watch: {
"$route.params.PostID": {
handler: function(value) {
console.log(value);
},
deep: true,
immediate: true,
},
},
Also another way of doing this by re-rendering a component without using watch:
by adding :key="$route.params.PostID" to the Post component like:
inside ParentComponent.vue
<template>
<Post :key="$route.params.PostID" />
</template>