When the name of a router link is dynamic how should we name the link? - vuejs2

I have a list of items in navbar that will be rendered. Each item should have a link related to its name. Because I don't want to hard code the links I don't know how to name the links.
<b-nav-item-dropdown no-caret class="mr-2">
<!-- Using 'button-content' slot -->
<template #button-content>
<div><b-icon icon="person-fill"></b-icon> {{ userItems[0] }}</div>
</template>
<b-dropdown-item
v-for="(userItem, index) in userItems[1]"
:key="index"
:to="userItem"
>
{{ userItem }}
</b-dropdown-item>
</b-nav-item-dropdown>
:to="{name: userItem }" doesn't work either.

I think your code should be:
<b-dropdown-item
v-for="(userItem, index) in userItems[1]"
:key="index"
>
<router-link to="your_path_or_route_name_here">
</b-dropdown-item>

I tried to reproduce your issue but since I had no idea about your data I created my own userItems. I created a code snippet for you to better understand the implementation.
new Vue({
el: '#app',
data() {
return {
userItems: [{
name: "Link 1",
path: "/link1"
},
{
name: "Link 2",
path: "/link2"
},
{
name: "Link 3",
path: "/link3"
}
],
}
},
})
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.22.0/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-nav-item-dropdown no-caret class="mr-2">
<!-- Using 'button-content' slot -->
<template #button-content>
<div>
Dropdown
</div>
</template>
<b-dropdown-item v-for="(userItem, index) in userItems" :key="index" :to="userItem.path">
{{ userItem.name }}
</b-dropdown-item>
</b-nav-item-dropdown>
</div>

Related

How can I use a sidenavbar toggle function in another header component in Vue3

Im using Vue3 in Laravel 9 with Inertia.js and I´m trying to create a Sidenavbar with a headerbar.
I would like to toggle the Sidenavbar with a "Menu" Button in the Header Component.
But I have no idea how can i use the toggle function for my Sidenavbar in my headerbar.
The Toggle function in the Sidenavbar is working fine.
Screenshot with Header and Sidebar
Layout/App.vue
<template>
<Header />
<div class="app">
<Nav />
<slot />
</div>
</template>
<script>
import Nav from "./Nav";
import Header from "./header.vue";
export default {
components: { Nav, Header },
};
</script>
Sidenavbar Nav.vue
<template>
<aside :class="`${is_expanded ? 'is-expanded' : ''}`">
<h3>Menu</h3>
<div class="menu">
<router-link to="/" class="button">
<span class="material-symbols-rounded">home</span>
<span class="text">Home</span>
</router-link>
<router-link to="/about" class="button">
<span class="material-symbols-rounded">description</span>
<span class="text">About</span>
</router-link>
<router-link to="/team" class="button">
<span class="material-symbols-rounded">group</span>
<span class="text">Team</span>
</router-link>
<router-link to="/contact" class="button">
<span class="material-symbols-outlined">admin_panel_settings</span>
<span class="text">Administration</span>
</router-link>
</div>
<div class="flex"></div>
<div class="menu">
<router-link to="/settings" class="button ">
<span class="material-symbols-rounded">settings</span>
<span class="text">Settings</span>
</router-link>
</div>
<div class="menu-toggle-wrap">
<button class="menu-toggle" #click="ToggleMenu">
<span class="material-symbols-outlined menu-icon">menu</span>
<span class="material-symbols-outlined arrow-back">arrow_back</span>
</button>
</div>
</aside>
</template>
<script >
import {ref} from 'vue'
export default {
data() {
return {
is_expanded: ref(localStorage.getItem("is_expanded") === "true"),
visible: false
};
},
methods: {
ToggleMenu() {
this.is_expanded = !this.is_expanded;
localStorage.setItem("is_expanded", this.is_expanded);
}
},
mounted() {
console.log(`The initial count is ${this.is_expanded}.`);
}
}
</script>
Header Header.vue
<template>
<div class=" header border-2">
<div class="menu-toggle-wrap">
<button class="menu-toggle" #click="">
<span class="material-symbols-outlined menu-icon">menu</span>
</button>
</div>
</div>
</template>
<script>
export default {
}
</script>
Here is my app.js file
import { createApp, h } from 'vue'
import { createInertiaApp } from '#inertiajs/inertia-vue3'
export const toggleMenu = new Vue();
createInertiaApp({
resolve: name => require(`./pages/${name}`),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})

How do I make dynamic routing work in Vue?

I got a project and when I use :to, my dynamic routes dont work..I also can't seem to pass params. The buttons supposed to be used as dynamic routes are declared in the v-for loop. I am using Quasar CLI / Vue3.
It'd be really awesome if some of you had an insight as to why this does not work. I get no errors, simply, when I hover over the button it shows no url as it normally would in a browser.
The view displaying items:
<template>
<div class="projects">
<div class="text-h3 project-title">
Favourite Projects <q-icon name="star" color="yellow" />
</div>
</div>
<div class="project-container">
<div class="q-pa-md project-card">
<q-card class="my-card single-projects no-shadow no-border-radius">
<q-img
src="https://res.cloudinary.com/practicaldev/image/fetch/s--9yBkqrjS--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nphrgz8yfnjylrwfr0yl.png"
>
<div class="absolute-bottom">
<div class="text-h6">
Damn good project
<q-icon name="star" color="yellow" />
</div>
<div class="text-subtitle2">by Big Boi</div>
</div>
</q-img>
<q-card-actions class="project-btns">
<q-btn
unelevated
size="md"
class="open-btn no-border-radius dropdown-btn"
>Open</q-btn
>
<q-btn
flat
no-caps
unelevated
size="md"
class="delete-btn no-border-radius"
color="red"
#click="confirm = true"
>Delete</q-btn
>
<q-dialog v-model="confirm" persistent class="dialog no-shadow">
<q-card>
<q-card-section class="row items-center">
<span class="q-ml-sm"
>Are you sure you want to delete this project?</span
>
</q-card-section>
<q-card-actions align="center">
<q-btn
flat
no-caps
label="Cancel"
color="black"
class="no-border-radius"
v-close-popup
/>
<q-btn
flat
no-caps
label="Delete"
color="red"
class="no-border-radius"
v-close-popup
/>
</q-card-actions>
</q-card>
</q-dialog>
</q-card-actions>
</q-card>
</div>
</div>
<div class="projects">
<div class="text-h3 project-title">All Projects</div>
</div>
<div v-for="item in items" :key="item.project" class="project-container">
<div class="q-pa-md project-card">
<q-card class="my-card single-projects no-shadow no-border-radius">
<q-img
src="https://res.cloudinary.com/practicaldev/image/fetch/s--9yBkqrjS--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nphrgz8yfnjylrwfr0yl.png"
>
<div class="absolute-bottom">
<div class="text-h6">{{ item.project }}</div>
<div class="text-subtitle2">by {{ item.author }}</div>
</div>
</q-img>
<q-card-actions class="project-btns">
<q-btn
:to="{
name: 'project',
params: {
project: item.project,
},
}"
unelevated
size="md"
class="open-btn no-border-radius dropdown-btn"
>Open
</q-btn>
<q-btn
flat
no-caps
unelevated
size="md"
class="delete-btn no-border-radius"
color="red"
#click="confirm = true"
>Delete</q-btn
>
<q-dialog v-model="confirm" persistent class="dialog no-shadow">
<q-card>
<q-card-section class="row items-center">
<span class="q-ml-sm"
>Are you sure you want to delete this project?</span
>
</q-card-section>
<q-card-actions align="center">
<q-btn
flat
no-caps
label="Cancel"
color="black"
class="no-border-radius"
v-close-popup
/>
<q-btn
flat
no-caps
label="Delete"
color="red"
class="no-border-radius"
v-close-popup
/>
</q-card-actions>
</q-card>
</q-dialog>
</q-card-actions>
</q-card>
</div>
</div>
</template>
<script lang="ts">
import { ref } from 'vue';
export default {
name: 'myProjects',
setup() {
return {
confirm: ref(false),
items: [
{ project: 'good project', id: '302a49g8Aa43', author: 'Josh' },
{ project: 'okay fine', id: '65at9g847a11', author: 'Tray' },
{ project: 'let me see', id: '538s3fg4782f', author: 'Martin' },
],
};
},
};
</script>
This is also my router where I do the routing:
{
path: '/project/:id',
props: true,
component: () => import('layouts/SingleProLayout.vue'),
children: [{ path: '', component: () => import('pages/Project.vue') }],
},
Try wrapping the q-btn inside a router-link https://router.vuejs.org/api/

Add a button in every row to a b-table using template

I am trying to add a button to every column of my table by using a Vuejs template and I get the Actions column but the button does not appear. I think I am missing something
<template>
<div id="menu">
<br>
<b-table
:items="items"
:fields="fields">
<template slot="actions" slot-scope="props">
<span>
<b-btn>Edit</b-btn>
</span>
</template>
</b-table>
</div>
</template>
and
export default {
data() {
return {
items: [],
fields: [
"name",
"days",
"actions"
]
};
},
Try this:
new Vue({
el: "#menu",
data: () => ({
items: [{name:'name', days:'days'}],
fields: ["name", "days", "actions"]
}),
methods: {
editItem(item) { console.log(item); }
}
});
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-vue/2.18.1/bootstrap-vue.min.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-vue/2.18.1/bootstrap-vue.min.js"></script>
<div id="menu">
<b-table :items="items" :fields="fields">
<template v-slot:cell(actions)="{ item }">
<span><b-btn #click="editItem(item)">Edit</b-btn></span>
</template>
</b-table>
</div>

calling a method on the root from a component, what is wrong with my code?

I have a component for my bootstrap modal. The modal has a button is labeled "Got It",which I am trying to call a method found on the root instance. It is not working--I cannot tell what I am missing. I have added a click handler and emit the click, but cannot trigger the clear function? Please advise what is wrong- thanks
Vue.component('modal', {
template: '#modal-template',
props:{
bgClass:{
type:String,
default:'default'
},
},
methods: {
clickHandler () {
this.$emit('click');
}
}
})
new Vue({
el: "#app",
data: function data() {
return{
showModalZ:false
}
},
methods: {
clear: function(){
alert("checkme");
}
}
})
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="vm-modal-mask">
<div class="vm-modal-wrapper">
<div class="vm-modal-container">
<div class="vm-modal-header">
<slot name="header">
default header
</slot>
</div>
<div :class="bgClass" class="vm-modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="vm-modal-footer">
<slot name="footer">
<button class="modal-default-button btn btn-primary" #click="clickHandler(),clear()">
Got It!
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<div id="app">
<h5>hello <i style="font-size:20px;cursor:pointer;" aria-hidden="true" class="fa fa-info-circle" v-on:click="showModalZ=true"></i></h5>
<modal v-if="showModalZ" #close="showModalZ = false">
<h5 slot="header"><strong>input goes here</strong></h5> <hr>
<div>
test
</div>
</modal>
</div>
simply use this.$parent.$root.methodname()
e.g this.$parent.$root.clear();
Vue.component('modal', {
template: '#modal-template',
props: {
bgClass: {
type: String,
default: 'default'
},
},
methods: {
clickHandler() {
this.$parent.$root.clear();
}
}
})
new Vue({
el: "#app",
data: function data() {
return {
showModalZ: false
}
},
methods: {
clear: function () {
alert("checkme");
}
}
})
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="vm-modal-mask">
<div class="vm-modal-wrapper">
<div class="vm-modal-container">
<div class="vm-modal-header">
<slot name="header">
default header
</slot>
</div>
<div :class="bgClass" class="vm-modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="vm-modal-footer">
<slot name="footer">
<button class="modal-default-button btn btn-primary" #click="clickHandler()">
Got It!
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<div id="app">
<h5>hello <i style="font-size:20px;cursor:pointer;" aria-hidden="true" class="fa fa-info-circle" v-on:click="showModalZ=true"></i></h5>
<modal v-if="showModalZ" #close="showModalZ = false">
<h5 slot="header"><strong>input goes here</strong></h5> <hr>
<div>
test
</div>
</modal>
</div>
You need to emit 'close' event from model component clickHandler function and capture it on parent with #close
Working example:
Vue.component('modal', {
template: '#modal-template',
props: {
bgClass: {
type: String,
default: 'default'
}
},
methods: {
clickHandler() {
this.$emit('close');
}
}
})
new Vue({
el: "#app",
data: function data() {
return {
showModalZ: false
}
},
methods: {
clear: function() {
alert("checkme");
}
}
})
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="vm-modal-mask">
<div class="vm-modal-wrapper">
<div class="vm-modal-container">
<div class="vm-modal-header">
<slot name="header">
default header
</slot>
</div>
<div :class="bgClass" class="vm-modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="vm-modal-footer">
<slot name="footer">
<button class="modal-default-button btn btn-primary" #click="clickHandler">
Got It!
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<div id="app">
<h5>hello <i style="font-size:20px;cursor:pointer;" aria-hidden="true" class="fa fa-info-circle" v-on:click="showModalZ=true"></i></h5>
<modal v-if="showModalZ" #close="showModalZ = false">
<h5 slot="header"><strong>input goes here</strong></h5>
<hr>
<div>test</div>
</modal>
</div>

Vue Js How to calculate the value on the table and display the sum on the footer

I wanted to create simple invoice using bootstrap table and Vue Js.
Basically, What i wanted is shown in the image below:
I have tried as in the code below, but i am confused on two things,
How should i
1) Calculate the total cost and show that as the footer summary.
2) Multiply rate and qnty and display on the corresponding input box on cost.
new Vue({
el: '#app',
methods: {
addService() {
this.model.services.push({});
}
},
data: {
model: {
services: []
},
fields: [{
key: "rate",
label: "Rate"
},
{
key: "qnty",
label: "Qnty"
},
{
key: "cost",
label: "Cost"
}
]
}
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.css" />
<script src="https://unpkg.com/vue"></script>
<script src="//unpkg.com/babel-polyfill#latest/dist/polyfill.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.js"></script>
<div id="app">
<b-card header-tag="header" footer-tag="footer">
<template slot="header" class="mb-0">
<button type="button" class="btn btn-primary btn-sm" #click.prevent="addService">
<icons :icon="['fas', 'plus']" /> Add Items/Service</button>
</template>
<b-card-body>
<b-table responsive bordered striped hover caption-top :fields="fields" :items="model.services" foot-clone>
<template slot="rate" slot-scope="data">
<b-form-input size="sm" class="form-control" v-model="data.item.rate" :name="`rate_${data.index}`" type="text" />
</template>
<template slot="qnty" slot-scope="data">
<b-form-input size="sm" class="form-control" v-model="data.item.qnty" :name="`qnty_${data.index}`" type="text" />
</template>
<template slot="cost" slot-scope="data">
<b-form-input size="sm" class="form-control" v-model="data.item.cost" :name="`cost_${data.index}`" type="text" />
</template>
</b-table>
</b-card-body>
</b-card>
</div>
The way i wanted is easily achieved by using normal td and tr, with computed function.
But i am confused with how to implement using Bootstrap-vue.
Please help!
Here's a quick way, that calculates the item cost in place
<b-form-input :value="(data.item.rate * data.item.qnty) || 0" type="text" />
Improvements can be made here to update the item total in the item, by using a watch t update the data.
the total, however is done using a computed value that uses reduce to find the total
computed: {
total: function() {
return this.model.services.reduce(function(a, c){return a + Number((c.rate*c.qnty) || 0)}, 0)
}
},
here is the complete code:
Vue.config.productionTip = false
Vue.component('icons', {
template: '<a><slot></slot></a>'
})
new Vue({
el: '#app',
methods: {
addService() {
this.model.services.push({});
}
},
computed: {
total: function() {
return this.model.services.reduce(function(a, c){return a + Number((c.rate*c.qnty) || 0)}, 0)
}
},
data: {
model: {
services: []
},
fields: [{
key: "rate",
label: "Rate"
},
{
key: "qnty",
label: "Qnty"
},
{
key: "cost",
label: "Cost"
}
]
}
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.css" />
<script src="https://unpkg.com/vue"></script>
<script src="//unpkg.com/babel-polyfill#latest/dist/polyfill.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.js"></script>
<div id="app">
<b-card header-tag="header" footer-tag="footer">
<template slot="header" class="mb-0">
<button type="button" class="btn btn-primary btn-sm" #click.prevent="addService">
<icons :icon="['fas', 'plus']" /> Add Items/Service</button>
</template>
<b-card-body>
<b-table responsive bordered striped hover caption-top :fields="fields" :items="model.services" foot-clone>
<template slot="rate" slot-scope="data">
<b-form-input size="sm" class="form-control" v-model="data.item.rate" :name="`rate_${data.index}`" type="text" />
</template>
<template slot="qnty" slot-scope="data">
<b-form-input size="sm" class="form-control" v-model="data.item.qnty" :name="`qnty_${data.index}`" type="text" />
</template>
<template slot="cost" slot-scope="data">
<b-form-input size="sm" class="form-control" :value="(data.item.rate * data.item.qnty) || 0" :name="`cost_${data.index}`" type="text" />
</template>
<template slot="bottom-row" slot-scope="data">
<td/><td>Total</td>
<td>{{total}}</td>
</template>
</b-table>
</b-card-body>
</b-card>
</div>