The code for a Vue.js treeview looks like this:
HTML:
<!-- item template -->
<script type="text/x-template" id="item-template">
<li>
<div
:class="{bold: isFolder}"
v-on:click="toggle"
v-on:dblclick="changeType">
{{model.name}}
<span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="model in model.children"
:model="model">
</item>
<li class="add" v-on:click="addChild">+</li>
</ul>
</li>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<item
class="item"
:model="treeData">
</item>
</ul>
Script:
// demo data
var data = {
name: 'My Tree',
children: [
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
},
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
}
]
}
]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object
},
data: function () {
return {
open: false
}
},
computed: {
isFolder: function () {
return this.model.children &&
this.model.children.length
}
},
methods: {
toggle: function () {
if (this.isFolder) {
this.open = !this.open
}
},
changeType: function () {
if (!this.isFolder) {
Vue.set(this.model, 'children', [])
this.addChild()
this.open = true
}
},
addChild: function () {
this.model.children.push({
name: 'new stuff'
})
}
}
})
// boot up the demo
var demo = new Vue({
el: '#demo',
data: {
treeData: data
}
})
Is there any way I can add Bootstrap styling to this, to make the treeview look something like the first example below:
I have very little frontend experience and don't really understand where to put the CSS here. I don't really understand the part of the code where it's mixed script and cshtml (inside <script type="text/x-template" id="item-template">).
To add bootstrap to your page just include their source files:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
As far as those specific styles, I'm not going to fully setup your UI, that isn't what stack overflow is for. You can follow along with the instructions on this github which should get you close:
https://github.com/jonmiles/bootstrap-treeview
Related
I'm wondering if there is a way to hide a whole row/item in a vuetify data-table. I've read threads about hiding columns but not data-table items.
As per my understanding, You want to hide the specific rows from the <v-data-table>. If Yes, you can achieve that by using v-slot and manipulate the template.
Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{
text: 'Dessert',
value: 'name'
}
],
items: [
{
name: 'Frozen Yogurt',
show: true
},
{
name: 'Ice cream sandwich',
show: false
},
{
name: 'Eclair',
show: true
},
{
name: 'Cupcake',
show: false
}
]
}
},
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.css"/>
<link rel="stylesheet" href="https://unpkg.com/#mdi/font#6.x/css/materialdesignicons.min.css"/>
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="items"
class="elevation-1"
>
<template v-slot:item="props">
<template v-if="props.item.show">
<tr>{{ props.item.name }}</tr>
</template>
</template>
</v-data-table>
</v-app>
</div>
I think passing an empty array to your :items would fix your problem. or you can do this one :items="defaultVales || desserts".
In my opinion, the best way to handle this is to add a show property to your objects and use a computed property to hide and show items
Working example
Here it will hide column on click
new Vue({
el: '#app',
vuetify: new Vuetify(),
computed:{
showItems(){
return this.desserts.filter(x => x.show)
}
},
data() {
return {
headers: [
{ text: 'Name', value: 'name' },
{ text: 'Score', value: 'score' },
],
desserts: [{
name: "Frozen",
score: 66,
show: true,
},
{
name: "Tom",
score: 100,
show: true,
},
{
name: "Eclair",
score: 100,
show: true,
},
{
name: "Frozen",
score: 89,
show: true,
},
]
}
},
methods: {
hideColumn(col){
col.show = false
}
}
})
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/vuetify#2.3.4/dist/vuetify.min.css'>
<script src='https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js'></script>
<script src='https://cdn.jsdelivr.net/npm/vuetify#2.3.4/dist/vuetify.min.js'></script>
<div id="app">
<v-data-table
:items="showItems"
:headers="headers"
#click:row="hideColumn"
>
</v-data-table>
</div>
I have a vuejs method that appends data on a screen. My issue is, I want to append all of the items found in the array to the screen using v-for instead of just one that is filtered by an index?
new Vue({
el: "#app",
data: () => ({
chocs:[{"title":'a man tale'}, {"title":'a boy tale'},{"title":'a mermaid tale'},{"title":'a dog tale'}]
}),
methods: {
handleTileClick: function(){
$("#fox").append(`<div id="popover-dialog">data here: ${this.chocs.title}</div>`
);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick()">Click Me</button>
<div id="fox" v-for="choc in chocs"></div>
</div>
Check the below code
var app = new Vue({
el: '#app',
name: "App",
data: () => ({
showList: false,
chocs: [
{ title: "a man tale" },
{ title: "a boy tale" },
{ title: "a mermaid tale" },
{ title: "a dog tale" },
],
}),
methods: {
handleTileClick: function () {
this.showList = true;
},
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick">Click Me</button>
<div id="fox" v-if="showList">
<div id="list-item" v-for="(choc, index) in chocs" :key="index">{{ choc.title }}</div>
</div>
</div>
You can first hide the elements and show them after click on the click Me button:
Live Demo
<div id="fox" v-if="isShowing">
<div id="popover-dialog" v-for="choc in chocs" :key="choc.title">
data here: {{ choc.title }}
</div>
</div>
data and methods as:
export default {
name: "App",
data: () => ({
isShowing: false,
chocs: [
{ title: "a man tale" },
{ title: "a boy tale" },
{ title: "a mermaid tale" },
{ title: "a dog tale" },
],
}),
methods: {
handleTileClick: function () {
this.isShowing = true;
},
},
};
I want to add checkboxes to Vuejs Treeview. So I added a checkbox to the template as this code:
<script type="text/x-template" id="item-template">
<li>
<input type="checkbox" id="checkbox">
<span
:class="{bold: isFolder}"
#click="toggle"
#dblclick="changeType">
{{ model.name }}
<span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
</span>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="(model, index) in model.children"
:key="index"
:model="model">
</item>
</ul>
</li>
</script>
But I don't know how to link those checkboxes to a model like this example. Please help! Thank you very much!
I think the simplest way to do that is by using VueX.
The store has a common variable for all checkBoxes accessible from everywhere.
When you click on a checkbox, it update the store.
https://jsfiddle.net/u91mxc58/14/
const store = new Vuex.Store({
state: {
checkBoxes:[],
},
mutations: {
updateCheckBoxes(state, value) {
state.checkBoxes = value;
}
}
})
// demo data
var data = {
name: 'My Tree',
children: [
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
},
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
}
]
}
]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object,
},
data: function () {
return {
open: false
}
},
computed: {
isFolder: function () {
return this.model.children &&
this.model.children.length
},
checkBoxes: {
// accesseur
get: function () {
return store.state.checkBoxes;
},
// mutateur
set: function (newValue) {
store.commit('updateCheckBoxes', newValue);
}
}
},
methods: {
toggle: function () {
if (this.isFolder) {
this.open = !this.open
}
},
changeType: function () {
if (!this.isFolder) {
Vue.set(this.model, 'children', [])
this.addChild()
this.open = true
}
},
addChild: function () {
this.model.children.push({
name: 'new stuff'
})
}
}
})
// boot up the demo
var demo = new Vue({
el: '#demo',
data: function() {
return {
treeData: data
};
},
computed: {
checkBoxes() {
return store.state.checkBoxes;
}
}
})
body {
font-family: Menlo, Consolas, monospace;
color: #444;
}
.item {
cursor: pointer;
}
.bold {
font-weight: bold;
}
ul {
padding-left: 1em;
line-height: 1.5em;
list-style-type: dot;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<!-- item template -->
<script type="text/x-template" id="item-template">
<li>
<input v-model="checkBoxes" type="checkbox" :value="model.name" id="checkbox">
<span
:class="{bold: isFolder}"
#click="toggle"
#dblclick="changeType">
{{ model.name }}
<span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
</span>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="(model, index) in model.children"
:key="index"
:model="model">
</item>
<li class="add" #click="addChild">+</li>
</ul>
</li>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<div>{{ checkBoxes }}</div>
<item
class="item"
:model="treeData">
</item>
</ul>
I've create a new directive to use the jQuery Plug-In Select2 with vue.js as written down on the vue.js example page.
But I don't want to just output the value of the selected option. To store the selections I try to bind my custom method create to the #change event.
Inside the directive, the Select2 will trigger the change event for the select input field while it updates, but nevertheless it still doesn't call my custom method.
Is there some hidden magic? I've tried to read the source code of vue.js but can't find something that puts me in the right direction.
Vue.directive('select', {
twoWay: true,
priority: 1000,
params: ['options'],
bind: function() {
var self = this;
$(this.el)
.select2({
data: this.params.options
})
.on('change', function() {
self.set(this.value);
});
},
update: function(value) {
$(this.el).val(value).trigger('change');
},
unbind: function() {
$(this.el).off().select2('destroy');
}
});
var vm = new Vue({
el: '#items',
data: {
items: [],
new_item: '',
options: [{
id: 1,
text: 'First'
}, {
id: 2,
text: 'Second'
}, {
id: 3,
text: 'Third'
}, {
id: 4,
text: 'Fourth'
}, {
id: 5,
text: 'Fifth'
}]
},
methods: {
create: function() {
var self = this,
label = '';
this.options.map(function(item) {
if (self.new_item == item.id)
label = item.text;
});
var obj = {
id: self.new_item,
name: label
};
this.items.push(obj);
this.new_item = '';
}
}
});
select {
min-width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/vue/1.0.24/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<div id="items">
<ul>
<li v-for="item in items">{{ item.id }} – {{ item.name }}</li>
</ul>
<select v-select="new_item" #change="create" :options="options">
<option value="0">--Select--</option>
</select>
</div>
Maybe you can add watcher to your new_item variable like this. So you can do something when new_item value change.
I myself still searching how to trigger #change after select2 change method, but no clue til now.
Vue.directive('select', {
twoWay: true,
priority: 1000,
params: ['options'],
bind: function() {
var self = this;
$(this.el)
.select2({
data: this.params.options
})
.on('change', function() {
self.set(this.value);
});
},
update: function(value) {
$(this.el).val(value).trigger('change');
},
unbind: function() {
$(this.el).off().select2('destroy');
}
});
var vm = new Vue({
el: '#items',
data: {
items: [],
new_item: '',
options: [{
id: 1,
text: 'First'
}, {
id: 2,
text: 'Second'
}, {
id: 3,
text: 'Third'
}, {
id: 4,
text: 'Fourth'
}, {
id: 5,
text: 'Fifth'
}]
},
methods: {
create: function() {
var self = this,
label = '';
this.options.map(function(item) {
if (self.new_item == item.id)
label = item.text;
});
var obj = {
id: self.new_item,
name: label
};
this.items.push(obj);
this.new_item = '';
}
},
watch:{
new_item:function(){
alert(this.new_item);
}
}
});
select {
min-width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/vue/1.0.24/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<div id="items">
<ul>
<li v-for="item in items">{{ item.id }} – {{ item.name }}</li>
</ul>
<select v-select="new_item" #change="create" :options="options">
<option value="0">--Select--</option>
</select>
</div>
I am need to take acces to the model fields from the template of the item of a listview. Basically I need to replace the first name with the "valueToAccess" from viewModel. Some Body can help me here.
<div id="app"></div>
<script type="text/x-kendo-template" id="item-template">
#= name #
</script>
<script type="text/x-kendo-template" id="view-template">
<div data-role="listview"
data-bind="source: items"
data-template="item-template">
</div>
</script>
<script>
var viewModel = {
items: new kendo.data.DataSource({
data: [{ name: "item1" }, { name: "item2" }]
}),
valueToAccess: "index",
remove: function(e){
this.items.remove(e.data);
}
};
viewModel.items = new kendo.data.DataSource({
data: [{ name: "item1" }, { name: "item2" }]
});
var view = new kendo.View('view-template', { model: viewModel });
view.render("#app");
</script>
<div id="app"></div>
You can do it by using a dependent property.
<script type="text/x-kendo-template" id="item-template">
<a data-bind="attr: { href: href}, text: name"></a>
</script>
<script>
var viewModel = {
items: new kendo.data.DataSource({
data: [{ name: "item1" }, { name: "item2" }]
}),
valueToAccess: "index",
href: function(item) {
return this.get("valueToAccess") + "/" + item.name;
},
remove: function(e){
this.items.remove(e.data);
}
};
</script>
Here is a live demo: http://jsbin.com/naxiy/1/edit