I have the following HTML
<div id="app">
<v-app id="inspire">
<v-treeview :items="items"></v-treeview>
</v-app>
</div>
and the following Javascript:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: [
{
id: 1,
name: 'Applications :',
children: [
{ id: 2, name: 'Calendar : app' },
],
},
{
id: 15,
name: 'Downloads :',
children: [
{ id: 16, name: 'October : pdf' },
],
}
],
}),
})
Let's say that I want to make the font-size of the Downloads label bigger or make it bold.
Is this possible with Vuetify and it's v-treeview? If so, how? There does not appear to be a way to control the styling of the labels.
Everything can be controlled in Vuetify. It's easier with some things and harder with others:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: [{
id: 1,
name: 'Applications :',
children: [{
id: 2,
name: 'Calendar : app'
}, ],
},
{
id: 15,
name: 'Downloads :',
children: [{
id: 16,
name: 'October : pdf'
}, ],
}
],
}),
})
.large {
font-size: 20px;
font-weight: 700;
}
<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#5.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.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<v-app id="inspire">
<v-treeview :items="items">
<template v-slot:label="{ item }">
<span
:class="{ large: !!(item.id === 15) }"
>
{{ item.name }}
</span>
</template>
</v-treeview>
</v-app>
</div>
Look at the API description on Vuetify's component pages, and look for slots - if a component has the slot you look for, then you can work with it quite easily. If not, then you may have to tweak classes or even the components.
v-treeview's documentation: https://vuetifyjs.com/en/components/treeview/
VTreeview has a slot called label. You can "invoke" that slot by:
<v-treeview :items="items">
<template v-slot:label="{ item, leaf, selected, indeterminate, active, open }">
<!-- your code comes here --->
</template>
</v-treeview>
You can pass in item, leaf, selected, indetermintae, active or open props, that you can use in the scope of the <template></template>. In my snippet, we only needed the item, that's why I only passed that down.
My snippet only works, if you have an item with id: 15 - but you can put any logic there: calling methods, computed properties, etc.
For more information you can look in Vue scoped slots and destructuring slot props.
You must to use the slot label. Try something like this:
<v-treeview :items="items">
<template v-slot:label="{ item }">
<span style="font-weight: bold">{{ item.name }}</span>
</template>
</v-treeview>
Related
In a b-table, each cell in a column should have different text color. Not the background of the cell, but the actual text color. I am able to change the text color of the column header, but not the individual cell texts.
The b-table code:
<b-card title="Total">
<b-table sticky-header="600px" hover :items="total" :fields="groupByFields"></b-table>
</b-card>
The fields where the column header color change is:
groupByFields: [
{
key: 'name',
sortable: true,
},
{
label: 'Total',
key: 'count',
},
{
key: 'interested',
thStyle: { color: '#3eef33' },
sortByFormatted: false,
formatter: (value) => {
const res = value;
return (`($${res})`);
},
},
],
The thStyle color attribute changes the header text color, but not the text of values in the cells of that column. How would I match that color to the cell text (not background) of that column too?
Here's an example, using the #cell() slot:
new Vue({
el: '#app',
data: () => ({
items: [],
fields: [
'id',
{ key: 'title', style: { fontStyle: 'italic' } },
{ key: 'price', style: { color: 'red', textAlign: 'right' } }
]
}),
mounted() {
fetch('https://dummyjson.com/products')
.then(_ => _.json())
.then(_ => this.items = _.products);
}
})
<link href="https://unpkg.com/bootstrap#4.6.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.22.0/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://unpkg.com/babel-polyfill/dist/polyfill.min.js"></script>
<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.js"></script>
<div id="app">
<b-table :items="items" :fields="fields">
<template #cell()="{field, value}">
<div :style="field.style" v-text="value" />
</template>
</b-table>
</div>
If you only need to style a few columns, you might want to use appropriate #cell({key}) slots.
Documentation here.
Probably the most common technique is to add classes to cells. It provides granular control over the applied styling, without sacrificing flexibility.
I have a BootstrapVue table which looks like this;
When you hover your mouse on the First Name column, the tooltip Tooltip for First name will appear. The checkboxes at the top will cause the corresponding table columns to appear/disappear.
Here's the description of the bug I encounter.
I uncheck First Name checkbox. Column First Name disappears. Now, I recheck the First Name checkbox. Column First Name reappears again. This is fine. However, the tooltip no longer works when I hover my mouse on the First Name column.
Here's the complete code in a single HTML file.
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.2.2/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.2.2/dist/bootstrap-vue.min.js"></script>
<div id='app'>
<b-checkbox
:disabled="visibleFields.length == 1 && field.visible"
v-for="field in showFields"
:key="field.key"
v-model="field.visible"
inline
>
{{ field.label }}
</b-checkbox>
<b-table :items="items" :fields="visibleFields" bordered>
</b-table>
<b-tooltip target="HeaderFirst" triggers="hover" container="HeaderFirst">
Tooltip for First name<br>
</b-tooltip>
</div>
<script>
new Vue({
el: '#app',
computed: {
visibleFields() {
return this.fields.filter(field => field.visible)
},
showFields() {
return this.fields.filter(field => field.key.includes('first') || field.key.includes('last'))
}
},
data: dataInit,
})
function dataInit() {
let init_data = {};
init_data.fields = [
{ key: 'id', label: 'ID', visible: true },
{ key: 'first', label: 'First Name', visible: true,
thAttr: {
id: "HeaderFirst"
},
},
{ key: 'last', label: 'Last Name', visible: true },
{ key: 'age', label: 'Age', visible: true },
];
init_data.items = [
{ id: 1, first: 'Mike', last: 'Kristensen', age: 16 },
{ id: 2, first: 'Peter', last: 'Madsen', age: 52 },
{ id: 3, first: 'Mads', last: 'Mikkelsen', age: 76 },
{ id: 4, first: 'Mikkel', last: 'Hansen', age: 34 },
];
return init_data;
}
</script>
I am using vue v2.6, BootstrapVue.
The <b-tooltip>'s target must exist in the DOM upon mounting. It does not dynamically attach a new tooltip to newly created elements in the DOM.
The first run of your code shows a tooltip because <b-table> initially contains the #HeaderFirst element. When you uncheck the First Name box, the existing elements in <b-table> are replaced with new elements via the computed property. The elements removed from the DOM include the one that <b-tooltip> initially attached a tooltip to, and no new tooltip is generated after <b-table> was updated.
Solution
One solution is to render <b-tooltip> only when the target element is visible:
Create a computed prop that determines whether the #HeaderFirst field is visible.
Conditionally render <b-tooltip> based on that computed prop.
new Vue({
computed: { 1️⃣
firstNameHeaderVisible() {
return this.fields.find(field => field.thAttr?.id === 'HeaderFirst')?.visible
}
},
⋮
})
2️⃣
<b-tooltip target="HeaderFirst" v-if="firstNameHeaderVisible">
demo
On disabled elements event hover is not working. You need to wrap element by other e.g. div where you set up tooltip and then it should work well
I made a vue.js bootstrap table for loading some data from local JSON files.
I'm trying to implement show/hide columns via checkboxes.
I think I've solved most of the problem, but the problem is when I hide a column and then press on that same checkbox again (to make column visible again) I lose the order of table (that column becomes last column) and so on.
For example if I hide "Timestamp" column which is first table header in my table and then press to show it again it is no longer on first place, instead it gets created on last place.
https://imgur.com/BaTfgci --> this is how app looks right now
https://codepen.io/frane_caleta/pen/KKPMKrL --> codepen of my code, you won't be able to load it without JSON file though
https://imgur.com/a/23jx0lZ --> JSON data example
First time asking question here, so feel free to ask me if you need some more information to solve the problem :)
<b-form-group label="Hide columns: ">
<b-form-checkbox-group id="checkbox-group-1" v-model="selected" :options="fields" name="flavour-1">
</b-form-checkbox-group>
</b-form-group>
//my table
<b-table id="myTable"
:small="small"
:bordered="bordered"
hover head-variant="dark"
stacked="md"
:items="cptItems"
:fields="selected"
:current-page="currentPage"
:per-page="perPage"
:filter="filter"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
#filtered="onFiltered"
:tbody-tr-class="rowClass"
v-if="selected.length > 0">
</b-table>
//Javascript file
function initializeVue() {
return new Vue({
el: '#app',
data() {
return {
items: data.logdatas,
selected: [],
fields: [{
text: 'Origin',
value: {
key: 'origin',
label: 'Origin',
sortable: true,
class: 'text-center',
index: 0
}
},
{
text: 'Timestamp',
value: {
key: 'timeStamp',
label: 'Timestamp',
sortable: true,
class: 'text-center',
index: 1
}
},
{
text: 'Level',
value: {
key: 'level',
label: 'Level',
sortable: true,
class: 'text-center',
index: 2
}
}, ...there are 4 more fields here like this...
//my method for creating those checkboxes
created() {
this.selected = this.fields.map(field => field.value);
}
the selected data is your culprit. b-checkbox-group :selection lists items in order of selection.
example2
b-table :fields lists columns in the order of the items.
better make a static fields-list and filter by selection.
// make this data or property
let columnNames = ["one", "two", "three", "infinity", "pi"];
// make this data
let selected = []
//make this computed // can be optimized
let activeFields = columNames.filter(name => selected.includes(name))
// more like this
export default {
data(){
return {
selected: [],
columnNames: ['name1', 'name2']
},
computed(){
activeColumns(){
return this.columnNames.filter(this.selected.includes) || []
}
}
const app = new Vue({
data(){
return {
currentPage: 0,
perPage: 10,
fields: ['age', 'first_name', 'last_name'],
//selected: [],
selected: ['age', 'first_name', 'last_name'],
items: [
{ age: 40, first_name: 'Dickerson', last_name: 'Macdonald' },
{ age: 21, first_name: 'Larsen', last_name: 'Shaw' },
{ age: 89, first_name: 'Geneva', last_name: 'Wilson' },
{ age: 38, first_name: 'Jami', last_name: 'Carney' }
]
}
},
computed: {
activeFields(){
return this.fields.filter(name => this.selected.includes(name))
}
}
}).$mount("#app");
<!-- Add this to <head> -->
<!-- Load required Bootstrap and BootstrapVue CSS -->
<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.min.css" />
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver" crossorigin="anonymous"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-form-group label="Hide columns: ">
<b-form-checkbox-group id="checkbox-group-1" v-model="selected" :options="fields" name="flavour-1">
</b-form-checkbox-group>
</b-form-group>
<b-table id="myTable"
:bordered="true"
hover head-variant="dark"
stacked="md"
:items="items"
:fields="selected"
:current-page="currentPage"
:per-page="perPage"
tbody-tr-class="row-class"
v-if="selected.length > 0">
</b-table>
<b-table id="myTable"
:bordered="true"
hover head-variant="dark"
stacked="md"
:items="items"
:fields="activeFields"
:current-page="currentPage"
:per-page="perPage"
tbody-tr-class="row-class"
v-if="selected.length > 0">
</b-table>
</div>
Vue.js has a built-in directive called v-for which is used to literate over list.
HTML code
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
Script code
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
Here, by using the v-for directive, the elements in items array are returned as variables named item. Here, the variables returned by this v-for directive, can be used in the html DOM. How do I create such a custom directive which returns a variable to the html DOM?
Note: I did search for v-for directives source code in the source code of vuejs, but could not find. Please help me to get this as I am very new to vuejs. Thank you.
Edit:
What I currently have?
There are 3 similar input groups for inputting 'First Name', 'Last Name' and 'Address' respectively. Each input field has label, state, disabled, value, and max properties which are stored in a inputOptions array.
<!-- HMTL -->
<b-input-group :prepend="inputOptions.firstName.label">
<b-form-input
:state="inputOptions.firstName.state"
v-model="inputOptions.firstName.value"
:disabled="inputOptions.firstName.disabled"
:maxlength="inputOptions.firstName.max"
></b-form-input>
</b-input-group>
<b-input-group :prepend="inputOptions.lastName.label">
<b-form-input
:state="inputOptions.lastName.state"
v-model="inputOptions.lastName.value"
:disabled="inputOptions.lastName.disabled"
:maxlength="inputOptions.lastName.max"
></b-form-input>
</b-input-group>
<b-input-group :prepend="inputOptions.address.label">
<b-form-input
:state="inputOptions.address.state"
v-model="inputOptions.address.value"
:disabled="inputOptions.address.disabled"
:maxlength="inputOptions.address.max"
></b-form-input>
</b-input-group>
//Script
inputOptions: {
firstName: {
label: 'First Name',
state: true,
value: 'Foo',
disabled: true,
max: 45
},
lastName: {
label: 'Last Name',
state: true,
value: 'Bar',
disabled: true,
max: 45
},
address: {
label: 'Address',
state: false,
value: 'Foo, Bar.',
disabled: true,
max: 255
},
}
What I needed to achieve
For each input-group field, it is needed to provide the property names one by one. Assume that I have created a vue directive called mydirective and code is simplified as follows.
<!-- HMTL -->
<b-input-group v-mydirective="inputOptions.firstName as myProperty" :prepend="myProperty.label">
<b-form-input
:state="myProperty.state"
v-model="myProperty.value"
:disabled="myProperty.disabled"
:maxlength="myProperty.max"
></b-form-input>
</b-input-group>
<b-input-group v-mydirective="inputOptions.lastName as myProperty" :prepend="myProperty.label">
<b-form-input
:state="myProperty.state"
v-model="myProperty.value"
:disabled="myProperty.disabled"
:maxlength="myProperty.max"
></b-form-input>
</b-input-group>
<b-input-group v-mydirective="inputOptions.address as myProperty" :prepend="myProperty.label">
<b-form-input
:state="myProperty.state"
v-model="myProperty.value"
:disabled="myProperty.disabled"
:maxlength="myProperty.max"
></b-form-input>
</b-input-group>
//Script
inputOptions: {
firstName: {
label: 'First Name',
state: true,
value: 'Foo',
disabled: true,
max: 45
},
lastName: {
label: 'Last Name',
state: true,
value: 'Bar',
disabled: true,
max: 45
},
address: {
label: 'Address',
state: false,
value: 'Foo, Bar.',
disabled: true,
max: 255
},
}
HTML
In your template, iterate over the multiple inputOptions using v-for like:
<div id="app">
<b-input-group v-for="option in inputOptions" :key="option.label" :option="option" />
</div>
SCRIPT
Create custom components for the group, input, and label, like:
Vue.component('b-label', {
props: ['label'],
template: '<div>{{ label }}</div>'
})
Vue.component('b-form-input', {
props: ['state', 'value', 'disabled', 'maxlength'],
template: '<input type="text" :value="value" />'
})
Vue.component('b-input-group', {
props: ['option'],
template:
`<div>
<b-label :label="option.label" />
<b-form-input
:state="option.state"
v-model="option.value"
:disabled="option.disabled"
:maxlength="option.max" />
</div>`
})
FIDDLE
Here is a demo on JSFiddle
This is a basic example of how to use components. Whatever transformations you need to do to the strings can be done in the associated components, via computed properties or methods. You can see a demo by clicking the link where I use a computed property to transform the labels into lowercase. That should be enough to get you going.
i'm making a list of items with vuejs v-for loop. I have some API data from server.
items: [
{
foo: 'something',
number: 60
},
{
foo: 'anything',
number: 15
},
{
foo: 'text',
number: 20,
}
]
Template
<div v-for="(item,index) in items" :key="index">
<div :class="{ active: ????}" #click="toggleActive">
{{ item.foo }}
{{ item.number }}
</div>
</div>
JS
methods: {
toggleActive() {
//
}
}
I need following: When i'm clicking on div add class active, if i have already active class - remove active class.( toggle ). Also i can select multiple items.
How can i do this? I don't have boolean variable in items array, and i shouldn't move item in a separate component
Here you go.
new Vue({
el: "#app",
data: {
items: [{
foo: 'something',
number: 60
},
{
foo: 'anything',
number: 15
},
{
foo: 'text',
number: 20,
}
]
},
methods: {
toggleActive(index) {
let item = this.items[index];
item.active = !item.active;
this.$set(this.items, index, item);
}
}
})
.active {
color: red;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<div v-for="(item,index) in items" :key="index">
<div :class="{ active: item.active}" #click="toggleActive(index)">
{{ item.foo }} {{ item.number }}
</div>
</div>
</div>
Here's a JS Fiddle:
https://jsfiddle.net/eywraw8t/250008/
App.vue
<template>
<div>
<div
v-for="(item, i ) in items"
:key="i"
:class="{ active: i === activeItem}"
>
// some looped items from data here
// button for active toggle
<button #click="selectItem(i)"> make item active </button>
</div>
</div>
</template>
Data and Methods
<script>
export default {
data() {
return {
activeItem: null,
};
},
methods: {
selectItem(i) {
this.activeItem = i;
},
},
};
</script>