Skip to content

Instantly share code, notes, and snippets.

@oskude
Created April 23, 2018 04:54
Show Gist options
  • Save oskude/bc2b3205051d526820dc918b119c5434 to your computer and use it in GitHub Desktop.
Save oskude/bc2b3205051d526820dc918b119c5434 to your computer and use it in GitHub Desktop.
vue.js tree-list form component experiment 2
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>vue.js tree-list form component experiment 2</title>
<script src="vue.js"></script>
</head>
<body>
<div style="display:flex">
<pre style="padding-right:3em">
foo
├─ foo-1
│ ├─ foo-1-1
│ └─ foo-1-2
├─ foo-2
│ ├─ foo-2-1
│ └─ foo-2-2
bar
├─ bar-1
│ ├─ bar-1-1
│ └─ bar-1-2
└─ bar-2
├─ bar-2-1
└─ bar-2-2
</pre>
<pre>
1: { id: 1, name: "foo", path: [] },
2: { id: 2, name: "foo-1", path: [1] },
3: { id: 3, name: "foo-1-1", path: [1,2] },
4: { id: 4, name: "foo-1-2", path: [1,2] },
5: { id: 5, name: "foo-2", path: [1] },
6: { id: 6, name: "foo-2-1", path: [1,5] },
7: { id: 7, name: "foo-2-2", path: [1,5] },
8: { id: 8, name: "bar", path: [] },
9: { id: 9, name: "bar-1", path: [8] },
10: { id: 10, name: "bar-1-1", path: [8,9] },
11: { id: 11, name: "bar-1-2", path: [8,9] },
12: { id: 12, name: "bar-2", path: [8] },
13: { id: 13, name: "bar-2-1", path: [8,12] },
14: { id: 14, name: "bar-2-2", path: [8,12] }
</pre>
</div>
<div id="app">
<form method="post">
<fieldset>
<legend>example</legend>
<tree-list name="cat[]" depth="3" :tree="mytree" :list="mylist"></tree-list>
<input type="submit">
</fieldset>
</form>
</div>
</body>
<script>
Vue.component("tree-list", {
props: [
"name",
"depth",
"tree",
"list"
],
mounted: function () {
this.on_list_change();
},
watch: {
list: 'on_list_change'
},
methods: {
on_list_change: function () {
console.log("list changed");
// TODO: how do we undisable when none of items children are checked?
for (let id of this.list) {
for (let parentId of this.tree[id].path) {
// TODO: we dont have reference to parent element
let parent = document.getElementById(`${this.name}${parentId}`);
if (parent) {
parent.disabled = true;
} else {
console.error("no parent found!");
}
}
}
},
to_show_or_not: function (item) {
if (
item.path.length == 0 // is root item
|| this.list.includes(item.path.slice(-1)[0]) // our parent is shown
) {
return true;
}
return false;
}
},
template: `
<div style="display:flex">
<div v-for="(_, d) in parseInt(depth)">
<template v-for="item in tree">
<tree-list-entry
v-if="item.path.length == d"
v-show="to_show_or_not(item)"
:name="name"
:item="item"
:list="list"
></tree-list-entry>
</template>
</div>
</div>
`.replace(/\n/g, "").replace(/>\s*</g, "><")
/* above removes those pesky whitespaces. TODO might break something... */
});
Vue.component("tree-list-entry", {
props: [
"name",
"item",
"list"
],
methods: {
on_click: function (evt) {
let id = parseInt(evt.target.value);
let list = this.$parent.list; // TODO: yeah, i dont care...
if(list.includes(id)) {
list.splice(list.indexOf(id), 1);
} else {
list.push(id);
}
}
},
computed: {
element_id: function () {
return `${this.name}${this.item.id}`;
}
},
template: `
<div>
<label :for="element_id">{{ item.name }}</label>
<input
type="checkbox"
:id="element_id"
:name="name"
:value="item.id"
:checked="list.includes(item.id)"
@click="on_click"
/>
</div>
`.replace(/\n/g, "").replace(/>\s*</g, "><")
/* above removes those pesky whitespaces. TODO might break something... */
});
/* ignore me, just an example tree list */
var cats = {};
var c = 1;
["foo", "bar"].forEach((name)=>{
let path = [];
cats[c] = {
id: c,
name: name,
path: Array.from(path)
};
path.push(c);
c++;
for (let x = 1; x <= 2; x++) {
cats[c] = {
id: c,
name: `${name}-${x}`,
path: Array.from(path)
};
path.push(c);
c++;
for (let y = 1; y <= 2; y++) {
cats[c] = {
id: c,
name: `${name}-${x}-${y}`,
path: Array.from(path)
};
c++;
}
path.splice(path.indexOf(c), 1);
}
});
var app = new Vue({
el: '#app',
data: {
mylist: [1,2,3],
mytree: cats
}
});
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment