Skip to content

Instantly share code, notes, and snippets.

@oskude
Created April 19, 2018 19:56
Show Gist options
  • Save oskude/18cb4b4fd18edcaafae5c1eaf20903e3 to your computer and use it in GitHub Desktop.
Save oskude/18cb4b4fd18edcaafae5c1eaf20903e3 to your computer and use it in GitHub Desktop.
vue.js tree-list form component experiment
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>vue.js tree-list form component experiment</title>
<script src="vue.js"></script>
</head>
<body>
<h2>vue.js tree-list form component experiment</h2>
<p>TODO: blah blah...</p>
<h3>element attributes/props</h3>
<ul>
<li><code>name</code> - string for the form input name (ex: <code>cat[]</code> for magic php array)</li>
<li><code>depth</code> - number of max tree path depth to descent to</li>
<li><code>:tree</code> - array of tree items</li>
<li><code>:list</code> - array of item ids that are checked</li>
</ul>
<h3>tree item</h3>
<pre>
{
id: 3, // unique id for this item
name: "foo-1-1", // name for this item
path: [1,2,3] // ids of all parent items, last id is this item
}
</pre>
<h3>example</h3>
<p>after submit, check the request post data in devtools</p>
<div id="app">
<form method="post">
<tree-list name="cat[]" depth="3" :tree="mytree" :list="mylist"></tree-list>
<input type="submit">
</form>
</div>
</body>
<script>
Vue.component("tree-list", {
props: [
"name",
"depth",
"tree",
"list"
],
template: `
<div style="display:flex">
<div v-for="d in parseInt(depth)"> <!-- TODO: can vue do parseInt for us? -->
<template v-for="item in tree">
<tree-list-entry
v-if="item.path.length == d"
v-show="item.path.length == 1 || list.includes(item.path.slice(-2)[0])"
: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_change: function (evt) {
let id = parseInt(evt.target.value);
let list = this.$parent.list; // TODO: yeah, i dont care...
if(evt.target.checked) {
list.push(id);
} else {
list.splice(list.indexOf(id), 1);
}
}
},
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)"
@change="on_change"
/>
</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", "zap"].forEach((name)=>{
let path = [c];
cats.push({
id: c,
name: name,
path: Array.from(path)
});
c++;
for (let x = 1; x <= 3; x++) {
path.push(c);
cats.push({
id: c,
name: `${name}-${x}`,
path: Array.from(path)
});
c++;
for (let y = 1; y <= 3; y++) {
path.push(c);
cats.push({
id: c,
name: `${name}-${x}-${y}`,
path: Array.from(path)
});
path.splice(path.indexOf(c), 1);
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