vue-router same route with different param - vue.js

I am on the /entries/12 route. On the same component I would like to push /entries/13 when user clicks the next button.
Code is like :
//e is the next page number.
this.$router.push({ name: 'Entries', params: { pageNum: e }});
I get below error:
If i try different route that works.
Whole code:
<template>
<div class="entries">
<generic-entries #clicked="clicked" ></generic-entries>
</div>
</template>
<script>
import GenericEntriesComp from '#/components/GenericEntriesComp';
export default{
name: 'entries-comp',
components: {genericEntries: GenericEntriesComp},
mounted(){
var params = {id : this.$route.params.pageNum}
this.$store.dispatch("getEntries",params);
},
methods: {
clicked(e){
this.$router.push({ name: 'Entries', params: { pageNum: e.toString() }});
},
loadData(){
var params = {pageNum : this.$route.params.pageNum}
this.$store.dispatch("getEntries", params)
}
},
computed: {
items(){
return this.$store.state.entries
},
},
watch: {
'$route': 'loadData'
}
}
</script>
Btw the error comes from :
Vue.config.errorHandler = function (err, vm, info) {
console.error(err);
}

I solved my problem with :key. This way, I guarantee that all router-view content will be re-rendered whenever there is a $route change.
<router-view :key="$route.fullPath" #showLoading="showLoading"></router-view>

Found the answer.
Seems vue-router works as expected. In my case there were another problem.
If I have below code also in generic component I beleive it loops and produce an error.
watch: {
'$route': function(){
this.loadData();
}
}
In my case I removed the watcher from the generic component and it worked.

If you have decided to change the route parameter programmatically, then you should use replace instead of push as like below:
//e is the next page number.
this.$router.replace({ name: 'Entries', params: { pageNum: e }});

Related

How do I access programmatically created refs in vue.js?

I would like to access refs in a vue.js component, where the ref itself is created dynamically like so:
<style>
</style>
<template>
<div>
<lmap class="map" v-for="m in [1, 2, 3]" :ref="'map' + m"></lmap>
</div>
</template>
<script>
module.exports = {
components: {
lmap: httpVueLoader('components/base/map.vue'),
},
mounted: function(){
console.log('all refs', this.$refs);
// prints an object with 3 keys: map1, map2, map3
console.log('all ref keys', Object.keys(this.$refs));
// would expect ["map1", "map2", "map3"], prints an empty array instead
Vue.nextTick().then(() => {
console.log('map1', this.$refs["map1"]);
// would expect a DOM element, instead prints undefined
})
},
destroyed: function(){
},
methods: {
},
}
</script>
However this seems not to work (see above in the comments), and I can't figure why.
I think the problem is that you are importing the component asynchronously, with httpVueLoader, which then downloads and imports the component only when the component is rendered from the dom, therefore, the component has not yet been imported into the nextTick callback.
I suggest you put a loaded event in the map.vue component, maybe in mounted lifecycle , which will be listened to in the father, example #loaded = "showRefs"
surely when the showRefs(){ } method is invoked, you will have your refs populated ;)
Try using a template string e.g
`map${m}`
You have to wait until components have been rendered / updated. This works:
module.exports = {
data: function () {
return {
};
},
components: {
lmap: httpVueLoader('components/base/map.vue'),
},
mounted: function(){
},
destroyed: function(){
},
updated: function(){
Vue.nextTick().then(() => {
console.log('all ref keys', Object.keys(this.$refs));
console.log('map1', this.$refs['map1'][0].$el);
})
},
methods: {
},
}

Vue watch page url changes

I'm trying to watch page url. I don't use Vue Router.
My final goal is to set page url as input value:
<template>
<div>
<input v-model="pageUrl">
</div>
</template>
<script>
export default {
data() {
return {
pageUrl: window.location.href,
link: ''
}
},
watch: {
pageUrl: function() {
this.link = window.location.href
}
}
}
</script>
The example above doesn't work somewhy.
I've also tried
watch: {
'window.location.href': function() {
this.link = window.location.href
}
},
Input value is being set only once on component render.
What can be wrong?
well, that is exactly the reason you want to use vue-router!
vue can only detect changes in reactive properties: https://v2.vuejs.org/v2/guide/reactivity.html
if you want to react to changes in the url, you have 2 ways:
https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event or
https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event
i would rather use vue-router or a similar plugin.

VueJS router-link doesn't update component content

Category component
<ul v-else>
<li
v-for="cat in getCategories">
<router-link :to="{ name: 'ProductsCategory', params: {category_name: cat.name}}">{{ cat.name }}</router-link>
</li>
</ul>
This works fine and redirect fine to the correct link.
Problem is
When it redirect it doesn't call again the state while i am using vuex.
Component script
computed: {
getLoading () {
return this.$store.state.companyInfo.loading;
},
getCompanyBasicInfo () {
return this.$store.state.companyInfo.companyBasicInfo;
},
getCategories () {
return this.$store.state.categories.categoriesName;
},
getCategoriesLoading () {
return this.$store.state.categories.loadingState;
},
getCataegoryProducts () {
return this.$store.state.products.getCategoryProducts;
},
},
created() {
this.$store.dispatch('getCategories', this.$route.params);
this.$store.dispatch('getCategoryProductsAction', this.$route.params);
this.$store.dispatch('getCompanyBasicInfo', this.$route.params);
}
It should call getCategoryProductsAction which call my API and filter due to the router-link params.
This may be normal, because this component is not destroyed, but the $route parameters have changed.
So you can watch the $route for params.category_name changed
watch: {
// when redirect to new category_name, this will be callback
'$route': (new, old) => {
if (new.params.category_name !== old.params.category_name) {
// reload data, same with created()
}
}
}
see more: https://router.vuejs.org/guide/advanced/data-fetching.html#fetching-after-navigation
I would prefer to use the watch lifecycle in Vue.js.
Basically what is does is watching your route and when it changes you can tell it to run a function.
example:
watch: {
// call again the method if the route changes
'$route': 'initService'
}

How To run a function in Vuejs after the component in created?

I have created a component which has a function which makes external API calls and then fills an array. I used created() life hook to run the function for the 1st time. I am passing a variable from the parent component into this component and then based upon this variable change I want the function to run again.
How do I achieve this.
Attaching my code below
<template>
<div>
<p>{{ data_to_show_on_mainpage }}</p>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'GetCategoryItemsAndDisplayOne',
props: ['categoriesfordisplay','ismainpage', 'catalogselected'],
data(){
return {
IsMainPage_1 : "",
data_to_show_on_mainpage : [],
}
},
watch: {
catalogselected: function(){
this.GetItemsToShowonMainPage()
}
},
methods:{
changevalue(){
console.log("i am reducing it to emplty after change of catalog")
this.IsMainPage_1 = this.catalogselected
this.data_to_show_on_mainpage = []
},
CatlogService(catlog_name,category,gender,mainpage){
let url = "http://localhost:5000/xyz/" + (this.catalogselected).replace(/'/g,"%27") +"/api/"+ (gender) + "/catalogvis/" + (category) +"/items"
console.log(encodeURI(url))
axios.get(encodeURI(url)).then((resp)=>{
this.data_to_show_on_mainpage.push(resp.data.response.Results.results[0])
})
.catch(err => {
console.log("we got an error the url is " + url)
console.log(err);
})
},
GetItemsToShowonMainPage(){
this.changevalue()
if(this.categoriesfordisplay.men_for_display.length>0){
for(let i =0;i<this.categoriesfordisplay.men_for_display.length;i++){
let category = this.categoriesfordisplay.men_for_display[i].replace(/"/g,"%27");
this.CatlogService(this.catalogselected,category,'men',this.ismainpage)
}
}
if(this.categoriesfordisplay.women_for_display.length>0){
for(let i = 0;i<this.categoriesfordisplay.women_for_display.length;i++){
let category = this.categoriesfordisplay.women_for_display[i].replace(/"/g,"");
this.CatlogService(this.catalogselected,category,'women',this.ismainpage)
}
}
},
},
created(){
this.GetItemsToShowonMainPage()
}
}
</script>
<style>
</style>
How Do i trigger the GetItemsToShowonMainPage() function whenever the catalogselected varaible is changed.
It looks fine.
As #a-lau says, make sure the parent is updating the catalogselected prop
Btw, you can write your watcher this way and remove completely the created hook:
watch: {
catalogselected: {
handler: "GetItemsToShowonMainPage",
immediate: true
}
}
If you still have issues you might want to write a minimal reproduction on https://codesandbox.io/s/vue

Vue 2 make a div Clickable and image

I am playing around with Vue 2, and I want to make a whole div clickable.
This div have a link, image and text.
I used router-link for links in header and other links but when I try to use something else the page keeps refreshing.
Can someone please help me get over this somehow..
Cheers!
Add click event to you <div> that you want to be clickable as below:
<div #click="clickMethod"></div>
Now in your methods property add rhe clickMethod callback that you want to fire when clicked like below
methods: {
clickMethod() {
//add code that you wish to happen on click
}
}:
For anyone who is stuck here like I did on how to make a Div Clickable
<div #click="clickeMethod">
<p> Some Text Here </p>
</div>
script:
<script>
export default {
name: 'headers',
data() {
return {
};
},
methods: {
clickMethod() {
this.$router.push('home');
},
},
};
</script>
This Event will make a div Clickable.
Hope I helped someone :) and thnx to #user7814783
For those wondering how router.push method works, below are various ways you can use the method:
// literal string path
router.push('home')
// object
router.push({ path: 'home' })
// named route
router.push({ name: 'user', params: { userId: '123' } })
// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
For me this implementation worked best:
<script>
export default {
name: 'home',
data() {
return {
};
},
methods: {
clickMethod() {
this.$router.push({ path: 'home' });
},
},
};
</script>