How to customize the text on empty cell value using Bootstrap-Vue? - vue.js

What I want to achieve is put "-" on every empty cell value. Like this (see the "Name" row):
How do I do that? Thanks

You can use add a formatter if you use the fields prop.
Here you can create a method which either returns your name if there is one, or - if there's none.
new Vue({
el: '#app',
data() {
return {
fields: [
{ key: "name", formatter: 'formatName' },
{ key: "age" }
],
items: [
{ age: 40, name: 'Dickerson Macdonald' },
{ age: 21, name: '' },
{ age: 89, name: 'Geneva Wilson' },
{ age: 38, name: 'Jami Carney'}
]
}
},
methods: {
formatName(value) {
return value || '-'
}
}
})
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.css" />
<script src="https://unpkg.com/vue#2.6.2/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-table :items="items" :fields="fields"></b-table>
</div>
Alternatively, you can use slots to create the logic in your template, or maybe render something else if there's no name. But if it's simply displaying a -, I'd stick with a formatter.
new Vue({
el: '#app',
data() {
return {
fields: [
{ key: "name" },
{ key: "age" }
],
items: [
{ age: 40, name: 'Dickerson Macdonald' },
{ age: 21, name: '' },
{ age: 89, name: 'Geneva Wilson' },
{ age: 38, name: 'Jami Carney'}
]
}
}
})
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.css" />
<script src="https://unpkg.com/vue#2.6.2/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-table :items="items" :fields="fields">
<template #cell(name)="{ value }">
{{ value || '-' }}
</template>
</b-table>
</div>

Related

How can i link b-table(bootstrap-vue) elements?

...
<b-table
class="table table-bordered"
id="my-table"
striped hover
:items="items"
:per-page="perPage"
...
></b-table>
items: [
{ id : 1, name : "Taylor", status: "passive" },
{ id : 2, name : "Tom", status: "passive" },
{ id : 3, name : "Arthur", status: "passive" },
...
İ want name or more details when i click it will transfer to new page. How can i do that ?
You can use slots to customize your b-table. I prepared a code snippet to show you how you can add a detail button in your table and redirect the user to a new page after clicking on it.
new Vue({
el: '#app',
data() {
return {
fields: ['id', 'name', 'status', 'details'],
items: [{
id: 1,
name: "Taylor",
status: "passive"
},
{
id: 2,
name: "Tom",
status: "passive"
},
{
id: 3,
name: "Arthur",
status: "passive"
},
]
}
},
methods: {
},
mounted() {},
})
<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-table bordered id="my-table" striped hover :items="items" :fields="fields">
<template #cell(details)="row">
<b-link :to="`/items/${row.item.id}`">Details</b-link>
</template>
</b-table>
</div>

Vue JS Roles & Permission in a table grid using checkboxes

I would like to check permissions of a role using checkbox in vue. For example if an admin can create, view, delete a checkbox will be selected, if not checkbox will not be selected. So far i have the table created with proper roles and permissions that below to each role but don't know how to check checkbox based on permission in role.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
permissions: [
{
id: 1,
name: "view posts"
},
{
id: 2,
name: "create posts"
},
{
id: 3,
"name": "edit posts"
},
{
id: 4,
name: "delete posts"
}
],
roles: [
{
id: 1,
name: "admin",
description: "Full admin access to all the areas of the blog.",
permissions: [
{
id: 1,
name: "view posts",
},
{
id: 2,
name: "create posts",
},
{
id: 3,
name: "edit posts",
},
{
id: 4,
name: "delete posts",
}
]
},
{
id: 2,
name: "executive",
description: "Limited access to critical areas of the blog",
permissions: [
{
id: 1,
name: "view posts",
},
{
id: 2,
name: "create posts",
}
]
},
{
id: 3,
name: "user",
description: "Basic view access to some areas of the blog",
permissions: [
{
id: 1,
name: "view posts",
}
]
}
]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.js"></script>
<div id="app">
<template>
<div>
<div id='permissionsTable'>
<v-row class='headerRow'>
<v-col cols='3'>Permissions</v-col>
<v-col v-for="role in roles" v-bind:key="role.id">{{role.name}}</v-col>
</v-row>
<v-row v-for="permission in permissions" v-bind:key="permission.id" class="bodyRow">
<v-col cols='3'>{{permission.name}}</v-col>
<v-col v-for="(role, index) in roles" v-bind:key="role.name">
{{roles[index].permissions}}
<v-checkbox :input-value="roles[index].permissions.includes(permission.id)" #change="onItemClick($event,role.name,permission.id)">
</v-checkbox>
</v-col>
</v-row>
</div>
</div>
</template>
</div>
Let me know if this help.
new Vue({
el: "#app",
vuetify: new Vuetify(),
methods: {
onItemClick(e, role, permissionId) {
const index = this.roles.findIndex((r) => r.name === role);
const found=this.roles[index].permissions.find(perm=> perm.id === permissionId)
if (
found
) {
this.roles[index].permissions.splice(
this.roles[index].permissions.findIndex(perm=>perm.id===permissionId),
1
);
} else {
this.roles[index].permissions.push(this._permissions[permissionId]);
}
}
},
computed: {
_permissions() {
return this.permissions.reduce((acc, curr) => {
const id = curr.id;
acc[id] = curr;
return acc;
}, {});
},
_roles() {
return this.roles.reduce((acc, curr) => {
const id = curr.id;
acc[id] = curr;
return acc;
}, {});
}
},
data() {
return {
permissions: [
{
id: 1,
name: "view posts"
},
{
id: 2,
name: "create posts"
},
{
id: 3,
name: "edit posts"
},
{
id: 4,
name: "delete posts"
}
],
roles: [
{
id: 1,
name: "admin",
description: "Full admin access to all the areas of the blog.",
permissions: [
{
id: 1,
name: "view posts"
},
{
id: 2,
name: "create posts"
},
{
id: 3,
name: "edit posts"
},
{
id: 4,
name: "delete posts"
}
]
},
{
id: 2,
name: "executive",
description: "Limited access to critical areas of the blog",
permissions: [
{
id: 1,
name: "view posts"
},
{
id: 2,
name: "create posts"
}
]
},
{
id: 3,
name: "user",
description: "Basic view access to some areas of the blog",
permissions: [
{
id: 1,
name: "view posts"
}
]
}
]
};
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.js"></script>
<div id="app">
<template>
<div>
<div id='permissionsTable'>
<v-row class='headerRow'>
<v-col cols='3'>Permissions</v-col>
<v-col v-for="role in roles" v-bind:key="role.id">{{role.name}}</v-col>
</v-row>
<v-row v-for="permission in permissions" v-bind:key="permission.id" class="bodyRow">
<v-col cols='3'>{{permission.name}}</v-col>
<v-col v-for="(role, index) in roles" v-bind:key="role.name">
{{roles[index].permissions}}
<v-checkbox :input-value="_roles[role.id].permissions.find(perm=>perm.id===permission.id)" #change="onItemClick($event,role.name,permission.id)">
</v-checkbox>
</v-col>
</v-row>
</div>
</div>
</template>
</div>
v-checkbox has a v-model prop that you can use to pass Boolean and select or deselect it accordingly ! try adding that Boolean in your roles array and use it inside the v-for. you can also check your condition inside v-for on v-model like :v-model="role.permissions.includes(1)" but it's up to you to use the one that suit your case best.

How to use href in Vue and Quill

I am using the Quill editor in Vue.js and it's working great. I have images, etc.
But...the link isn't working. I tried both the "snow" and "bubble" themes.
I type the text, highlight it and then click on the "link". I get the dialog to set the link, but then the link isn't there.
It's working in the JavaScript version, but not the Vue.
Below is my code.
Vue.component('editor', {
template: '<div ref="editor"></div>',
props: {
value: {
type: String,
default: ''
}
},
data: function() {
return {
editor: null
};
},
mounted: function() {
this.editor = new Quill(this.$refs.editor, {
modules: {
toolbar: [
[{ header: [1, 2, 3, 4, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block', 'link']
]
},
//theme: 'bubble',
theme: 'snow',
formats: ['bold', 'underline', 'header', 'italic', 'link'],
placeholder: "Type something in here!"
});
this.editor.root.innerHTML = this.value;
this.editor.on('text-change', () => this.update());
},
methods: {
update: function() {
this.$emit('input', this.editor.getText() ? this.editor.root.innerHTML : '');
}
}
})
new Vue({
el: '#root',
data: {
//model: 'Testing an editor'
model: '',
isShowing: true
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<link href="https://cdn.quilljs.com/1.3.4/quill.snow.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://cdn.quilljs.com/1.3.4/quill.core.css" rel="stylesheet"/>
<!DOCTYPE html>
<html>
<head>
<title>Trying to use the Quill Editor in Vue</title>
</head>
<body>
<div id="root">
<div v-if="isShowing">
<editor v-model="model"></editor>
</div>
<p>I need the v-html directive: <span v-html="model"></span></p>
<p>Raw data: <pre>{{ model }}</pre></p>
<button #click="isShowing = !isShowing">Toggle</button>
</div>
</script>
</body>
</html>
Any help is greatly appreciated.
Thanks, D
I had to place a 'link' into the "formats" as well:
formats: ['bold', 'underline', 'header', 'italic', 'link'],
I updated my code snippet with the correct answer in case anyone else is having this problem.
Thanks!

How to set an attribute on a v-select option?

Just starting with Vue and need some advice on best practices.
What I'm trying to achieve: set makeId equal to the makes option id, based on what option is selected. So, for example, when I select "bmw" from the dropdown, I want makeId to equal 2.
Without Vuetify, I cloud set a data attribute to each option during the v-for loop, and then #change just grab that attribute and assign the value to the makeid.
How can I achieve what I'm trying to do with Vuetify?
<v-select v-model="car.make" :items="makes" item-value="name" item-text="name"> </v-select>
data: function() {
return {
car: { make: "", makeId: "" },
makes: [{ name: "audi", id: "1" }, { name: "bmw", id: "2" }]
};
}
UPDATED:
you can bind the id as the item-value and on the v-model you need to assign car.madeIdinstead of car.make if you need a single value:
<v-select v-model="car.makeId" :items="makes" item-value="id" item-text="name"> </v-select>
Or you can use an extra method for object binding :
here is a fork for it: codepen
The main difficulty here is that you've got two different formats for your objects. Having to map between id/name and make/makeId complicates things.
This would be easy without the property mapping, you could just set return-object on the v-select.
Assuming that isn't possible, one alternative would be to have car as a computed property based on the selected value to perform the property renaming. This would look like this:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
selectedCar: null,
makes: [{name: 'audi', id: '1'}, {name: 'bmw', id: '2'}]
}
},
computed: {
car () {
const selectedCar = this.selectedCar
if (selectedCar) {
return {
make: selectedCar.name,
makeId: selectedCar.id
}
}
}
}
})
#app {
padding: 10px;
}
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://unpkg.com/mdi#2.2.43/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://unpkg.com/vuetify#2.0.5/dist/vuetify.min.css" rel="stylesheet">
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.0.5/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<p>{{ car }}</p>
<v-select v-model="selectedCar" :items="makes" item-value="name" item-text="name" return-object> </v-select>
</v-app>
</div>
We could instead flip around the relationship between car and selectedCar so that car is in data and selectedCar is the computed property. For that we'd need to implement a getter and a setter:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
car: {make: '', makeId: ''},
makes: [{name: 'audi', id: '1'}, {name: 'bmw', id: '2'}]
}
},
computed: {
selectedCar: {
get () {
return this.makes.find(make => make.id === this.car.makeId)
},
set (selectedCar) {
this.car = {
make: selectedCar.name,
makeId: selectedCar.id
}
}
}
}
})
#app {
padding: 10px;
}
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://unpkg.com/mdi#2.2.43/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://unpkg.com/vuetify#2.0.5/dist/vuetify.min.css" rel="stylesheet">
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.0.5/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<p>{{ car }}</p>
<v-select v-model="selectedCar" :items="makes" item-value="name" item-text="name" return-object> </v-select>
</v-app>
</div>
A third alternative is to ditch v-model altogether and just use the :value/#input pair directly:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
car: {make: '', makeId: ''},
makes: [{name: 'audi', id: '1'}, {name: 'bmw', id: '2'}]
}
},
methods: {
onInput (id) {
const make = this.makes.find(make => make.id === id)
this.car = {
make: make.name,
makeId: make.id
}
}
}
})
#app {
padding: 10px;
}
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://unpkg.com/mdi#2.2.43/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://unpkg.com/vuetify#2.0.5/dist/vuetify.min.css" rel="stylesheet">
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.0.5/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<p>{{ car }}</p>
<v-select :value="car.makeId" :items="makes" item-value="id" item-text="name" #input="onInput"> </v-select>
</v-app>
</div>

Vue js 2 hide shared component

<template>
<div id="app" class="phone-viewport">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<router-view></router-view>
<bottomBar v-bind:visibles='show' ></bottomBar>
</div>
</template>
<script>
export default {
name: '',
show: '',
data () {
return {
visibles: [
{name: 'Football', show: true},
{name: 'Basketball', show: true},
{name: 'Hockey', show: true},
{name: 'VolleyBall', show: false},
{name: 'Baseball', show: false},
]
}
}
}
</script>
I'm looking to hide the bottomBar just on VolleyBall and Beisbol .
But I always have this error "Property or method "show" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
"
<script>
export default {
name: 'app',
data () {
return {}
},
computed: {
hideBottom: function () {
if (this.$router.path === '/baseball' || this.$router.path === '/volleyball') return false
else { return true }
}
}
}
Baseball
You are calling method show which does not exist, that's why you are getting that error.
As I understand your question, you want to hide that component on particular routes?
If so, You need to create computed variable which will determine if it should be shown or not. e.g.:
computed: {
toShowOrNotToShow: function () {
if(this.$router.path === '/baseball' || this.$router.path === '/volleyball') return false;
else
return true;
}
}
Just use it: <bottomBar v-if='toShowOrNotToShow' ></bottomBar>