How to conditionally add query parameter to route in Vue.js? - javascript

I am using vue-router to redirect to a new URL after clicking on a button. I would like the router to only add a query parameter into the URL if the query parameter is actually filled. So if it is null it should not add the parameter.
Right now this is not working as expected. Have a look at the following code snippet (choose each of the options and click the button).
(it seems you can't use routing on Stackoverflow so please also have a look at the snippet on JSFiddle: https://jsfiddle.net/okfyxtsj/28/)
Vue.use(VueRouter);
new Vue({
el: '#app',
router: new VueRouter({
mode: 'history',
}),
computed: {
currentRoute () {
return this.$route.fullPath
}
},
data () {
return {
some: this.$route.query.some || null
}
},
template: '<div><select v-model="some"><option :value="null">Option (value = null) which leaves empty parameter in URL</option><option value="someParameter">Option (value = someParameter) which shows parameter with value in URL</option><option :value="[]">Option (value = []) which removes parameter from URL</option></select><br><button #click="redirect">Click me</button><br><br><div>Current Path: {{ currentRoute }}</div></div>',
methods: {
redirect () {
this.$router.push({
path: '/search',
query: {
some: this.some || null
}
})
}
},
watch: {
'$route.query': {
handler(query) {
this.some = this.$route.query.hasOwnProperty('some') ? this.$route.query.some : null
},
},
},
watchQuery: ['some']
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app"></div>
When some is null the parameter will still be added to the URL. When some is an empty array it will not be added to the URL.
I don't want to use an empty array as default value since the value should always be a string.
So how can I make sure the query parameter is only added to the new route if it contains a value other than null?

Use a simple if-else or ternary construct. Also prefer computed property for some instead of watcher:
Vue.use(VueRouter);
new Vue({
el: '#app',
router: new VueRouter({
mode: 'history'
}),
computed: {
some() {
return this.$route.query.some || null;
}
},
data() {
return {};
},
methods: {
redirect() {
const routeConfig = this.some
? { path: '/search', query: { search: this.some } }
: { path: '/search' };
this.$router.push(routeConfig);
}
},
// Remaining config like template, watchers, etc.
});

Related

Why Vue can't watch the data change?

i want the function:createComparation work when tableRowName change,but acturely when tableRowName change , it didnt works,vue follows;
createComparation is another function which didnt define by vue but only by javascript
const selectedRight =Vue.createApp({
data(){
return {
tableRow:0,
tableRowName:[],
stockName:[],
rectWidth:40,
rectHeight:5,
}
},
watch: {
tableRowName(newtable,oldtable){
console.log(1)
createComparation()
},
immediate:true,
stockName(){
changeTip()
},
},
methods:{
}
}).mount('#selectedRight')
in case of tableRowName contain objects then you have to use
deep:true
watch: {
tableRowName(newtable,oldtable){
console.log(1)
createComparation()
},
immediate:true,
deep: true,
stockName(){
changeTip()
},
},
but i think you are updating the array without reactive manner, Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g.
vm.items.length = newLength
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // is NOT reactive
vm.items.length = 2 // is NOT reactive
I guess whatching array might be the issue. You can try this:
computed: {
rowNames() {
return this.tableRowName;
// if the line above doesn't work:
return this.tableRowName.join();
}
},
watch: {
rowNames(newtable,oldtable){
createComparation()
},
I think this is what you're looking for. You need to define the handler as an object for the property you're trying to watch and set immediate: true.
Vue.config.productionTip = false
Vue.config.devtools = false
new Vue({
el: "#app",
data() {
return {
tableRow: 0,
tableRowName: [],
stockName: [],
rectWidth: 40,
rectHeight: 5,
}
},
watch: {
tableRowName: {
handler(newtable) {
console.log('Calling createComparation function');
console.info(newtable);
},
immediate: true
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="tableRowName.push(Math.random())">Trigger change manually again</button>
</div>
The watch method definition is wrong. When you need to use immediate, you have to put you function body into handler property.
For example,
watch: {
tableRowName: {
handler: function() {
},
immediate: true
}
},

How make dynamic breadcrumbs in vue.js?

I would like to have a dynamic breadcrumbs based on where I clicked on a category but I get an error that says my variable is undefined: TypeError: Cannot read properties of undefined (reading 'homeMenu'). Yet in my getHomeCategory function, the console.log of homeCategory displays Perma'Thèque. I don't understand how to do it, thanks
Here is the code :
<script>
export default {
props: {
},
data: () => ({
homeMenu: "",
breadcrumbs: [
{
text: 'Accueil',
disabled: false,
href: '/',
},
{
text: this.homeMenu,
disabled: false,
href: "/" + this.homeMenu,
},
],
}),
computed: {
...mapGetters({
console: () => console,
homeCategory: 'home/getCategory',
})
},
methods: {
getHomeCategory () {
if (this.homeCategory === "Perma'Thèque") {
console.log(this.homeCategory)
return this.homeMenu = "permatheque"
} else {
return this.homeMenu = "null"
}
},
},
mounted() {
if (this.plantActive) this.loading = false;
this.getHomeCategory()
}
}
</script>
data() is declared here as an arrow function, so this refers to the outer scope, not the Vue component instance, but even as a regular function here, this.homeMenu won't yet exist.
It seems that you actually want breadcrumbs to be reactive to homeMenu, so you should move breadcrumbs to a computed prop:
export default {
data: () => ({
homeMenu: '',
}),
computed: {
breadcrumbs() {
return [
{
text: 'Accueil',
disabled: false,
href: '/',
},
{
text: this.homeMenu,
disabled: false,
href: '/' + this.homeMenu,
},
]
}
}
}
demo
I used Element Plus UI and my mind was blown. Check out my blog and the codes. Element Plus is a free library that is great for Vue JS. They have very nice UI for breadcrumb and can be implemented with v-for loop.
https://medium.com/#samchowdhury/create-a-breadcrumb-with-vue-js-and-element-plus-ui-f3e2fde50a3e

Check resolver existance by Router event in Angular

Is it possible to know if route has resolvers or not with router.events?
I tried to find it with:
this.router.events.subscribe(e => {
console.log(e);
})
But it seems that there is no information about resolvers in router events. I need this for progress bar. Maybe ActivatedRoute can be useful in this case? But where exactly should i look? activateRoute.snapshot.data is always empty object
I also tried:
private isRouteHaveResolvers() {
let firstChild = this.activatedRoute.firstChild;
while (firstChild && firstChild.firstChild) {
firstChild = firstChild.firstChild;
}
return firstChild && firstChild.routeConfig && !!Object.keys(firstChild.routeConfig.resolve).length;
}
But it doesnt work properly. For example for this case:
{
path: 'edit',
component: EditComponent,
resolve: {
data: resolverData
},
children: [{
path: 'activity/:activityId',
component: ModalComponent,
outlet: 'modal',
}],
}
For this route activity/:activityId it return true

How to fetch data from server in vue js?

I am trying to fetch data from the server using Vue + Vuex + Vue resource.On button click I want to hit Http request and show in list format .I tried like that.Here is my code
https://plnkr.co/edit/EAaEekLtoiGPvxkmAtrt?p=preview
// Code goes here
var store = new Vuex.Store({
state: {
Item: []
},
mutations: {
getItems: function (state) {
}
},
actions: {
fetchData:function (context) {
this.$http.get('/data.json', function(v1users)
{
// this.$set('v1_user',v1users);
});
}
}
})
var httprequest = Vue.extend({
"template": '#http_template',
data: function () {
return {
items: store.state.Item
}
},
methods: {
fetchData: function () {
store.dispatch('fetchData')
},
}
})
Vue.component('httprequest', httprequest);
var app = new Vue({
el: '#App',
data: {},
})
;
any udpdate?
Try using Vue.http.get instead of this.$http.get.
Vuex doesn't have access to $http directly from instance.

Is it possible to trigger a function upon a Vue data element change?

My API provides me a hash which I receive as part of an AJAX call. The content of the AJAX response (which includes the hash) is updating data components in my Vue instance (so that the DOM is modified, per usual Vue usage).
I was wondering if it is possible to trigger (run) a function upon the change of a specific data element. Reactivity in Depth does not mention this and for me (please correct me if this is wrong) computedand methods are a way to indirectly provide new computed elements for the DOM (in other words, they do not start because a specific element was modified but are rather synchronisation methods between data and other variables provided to the DOM).
I was hoping for something along the lines of (this is non-working, incorrect pseudo-code, I just add it to put in context of a Vue instance):
var vm = new Vue({
el: '#root',
data: {
hash: null
},
functions_to_trigger_upon_an_element_change: {
hash: function () {
location.reload()
}
}
})
The idea above would be to have location.reload() run when the value of hash changes.
Is there such a mechanism in Vue?
If there is not, I will keep the state independently of Vue and act accordingly upon its change but it would be nice to reuse the Vue watch properties to do that.
You can use a watch, like the following example:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
About your case, here is the example about how it could be implemented.
var vm = new Vue({
el: '#demo',
data: {
hash: 'Foo'
},
watch: {
hash: function (val) {
// when the hash prop changes, this function will be fired.
location.reload()
}
}
})
I hope I understood your question right.
I think this should work
var vm = new Vue({
el: '#root',
data: {
hash: null
},
watch: {
hash: function (val) {
functions_to_trigger_upon_an_element_change()
}
},
methods: {
functions_to_trigger_upon_an_element_change() {
// You code
}
}
})
You should use the this. in the example above
var vm = new Vue({
el: '#root',
data: {
hash: null
},
watch: {
hash: function (val) {
this.functions_to_trigger_upon_an_element_change()
}
},
methods: {
functions_to_trigger_upon_an_element_change() {
// You code
}
}
})

Categories