I have this fiddle:
https://jsfiddle.net/pnqzspoe/12014/
I want to modify it a bit and want to display each node as a text area containing the corresponding text. Further, I want to give an option to 'reply' to it. This would mean insertion of a new text area into which we can enter text.
Here is the code:
<script type="text/x-template" id="item-template">
<li>
<div
:class="{bold: isFolder}"
#click="toggle"
#dblclick="changeType">
{{ model.name }}
<span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
</div>
<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>
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
}
})
What would be the template for this use-case?
If I don't understand your question wrongly...
Replace
{{model.name}}
with
<textarea v-model="model.name"></textarea>
should work?
Related
I have this component that shows a whole bunch of different components. Like so:
computed: {
...mapGetters('forms', ['formErrors']),
input: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
},
},
component() {
const components = {
'ls-text-field': () =>
import('../../../../common/ls-text-field.vue'),
'simple-date-picker': () =>
import('../../../../common/simple-date-picker.vue'),
select: 'v-select',
combobox: 'v-combobox',
};
return components[this.setting.component];
},
attributes() {
const attrs = {
'ls-text-field': {
label: this.setting.name,
},
'simple-date-picker': {},
select: {
label: 'Select this foo',
items: this.setting.options,
},
combobox: {
'return-object': true,
items: this.productList,
loading: this.loading_product_list,
'item-value': 'sku',
'item-text': 'sku',
label: this.setting.name,
name: this.setting.key,
},
};
return {
...attrs[this.setting.component],
'error-messages': this.formErrors(this.setting.key),
};
},
},
and the Template looks something like this:
<template>
<v-col md="4" cols="12">
<component
:is="component"
v-bind="attributes"
v-model="input"
:search-input.sync="searchSku"
/>
But you'll notice I had to do v-model in the template and not in the computed property. I suppose there is NO way to do this:
attributes() {
const attrs = {
'ls-text-field': {
label: this.setting.name,
},
'simple-date-picker': {},
select: {
label: 'Select this foo',
items: this.setting.options,
},
combobox: {
'return-object': true,
items: this.productList,
loading: this.loading_product_list,
'item-value': 'sku',
'item-text': 'sku',
label: this.setting.name,
name: this.setting.key,
'v-model': this.item.info.someKey // This doesn't seem possible
},
};
I'm using the react-sortablejs library.
When trying to move cards within the list. I get the error:
Cannot read property 'map' of undefined
I have a dense structure and it gets lost here. How to handle onChange so that I can see in the console that the order of the notes within the list has changed.
Demo here
import Sortable from 'react-sortablejs';
// Functional Component
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
console.log(order)
onChange(order);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
class App extends React.Component {
state = {
item: {
id: "abc123",
name: "AAA",
lists: [
{
id: "def456",
list_id: "654wer",
title: 'List1',
desc: "description",
listItems: [
{
id: "ghj678",
title: "ListItems1",
listItemsId: "88abf1"
},
{
id: "poi098",
title: "ListItems2",
listItemsId: "2a49f25"
},
{
id: "1oiwewedf098",
title: "ListItems3",
listItemsId: "1a49f25dsd8"
}
]
},
{
id: "1ef456",
list_id: "654wer",
title: 'List 2',
desc: "description",
listItems: [
{
id: "1hj678",
title: "ListItems4",
listItemsId: "18abf1"
},
{
id: "1oi098",
title: "ListItems5",
listItemsId: "1a49f25"
},
{
id: "1oiwewe098",
title: "ListItems6",
listItemsId: "1a49f25dsd"
}
]
},
{
id: "2ef456",
title: 'List 3',
list_id: "254wer",
desc: "description",
listItems: [
{
id: "2hj678",
title: "ListItems7",
listItemsId: "28abf1"
},
{
id: "2oi098",
title: "ListItems8",
listItemsId: "234a49f25"
},
{
id: "df098",
title: "ListItems9",
listItemsId: "1asd8"
}
]
}
]
}
};
render() {
const c = this.state.item['lists'].map(item => { return item.listItems});
return (
this.state.item['lists'].map(item => {
return (<div>
{item.title}
<SortableList
key={uniqueId()}
items={item}
onChange={(item) => {
console.log(item)
this.setState({item});
}}
>
</SortableList>
</div>)
})
)
}
};
Thanks in advance.
You have to update few changes in your code.
Update the SortableList function as below.
First pass data-id={val.id} in li and after that in onChange method you will receive the order with id. So based on that we are sorting the records.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
items.listItems.sort(function(a, b){
return order.indexOf(a.id) - order.indexOf(b.id);
});
onChange(items);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val.id}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
Update the onChange event of App component.
onChange={(item) => {
let itemObj = {...this.state.item};
itemObj.lists.map(x=>{
if(x.id === item.id) x = item;
});
this.setState({itemObj});
}}
That's it!
Here is the working demo for you
https://stackblitz.com/edit/react-sortablejs-blzxwd
When remove the onChange event in the Sortable list, Its works.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
I have a Vue file that looks like so :
import store from '#/store'
export default{
name: 'myList',
data: () => ({
show: true,
listContent: [{
name: '1',
icon: 'person',
value: function () {
return store.state.myStore.settings.one
}
}, {
name: '2',
icon: 'person',
value: function () {
return store.state.myStore.settings.two
}
}, {
name: '3',
icon: 'person',
value: function () {
return store.state.myStore.settings.three
}
}
]
})
}
The part that's not working is getting the 'value' from the 'listContent'.
{
name: '3',
icon: 'person',
value: function () {
return store.state.myStore.settings.three
}
}
In my code, I have imported the view as if I were to put :
this.$store.state.myStore.settings.one
Inside the value function, 'this' would refer to the object
{
name: '3',
icon: 'person',
value: function () {
return store.state.myStore.settings.three
}
}
And I wouldnt be able to get the store. However, my code still doesn't work. I need to get access to the store inside the listContent.
The list is rendered like so :
<v-data-table :items="listContent" hide-actions hide-headers>
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td class="text-xs-right" v-text="props.item.value()"> </td>
</template>
</v-data-table>
Either I have referenced the store incorrectly, or the template is incorrect. Any ideas ?
Why do you want the value to be a function that returns the state value. You can just assign it to state value using this.$store.state.myStore.settings.one
For this to work make the data option a normal function instead of an arrow function so that this still represents the vue instance
export default {
name: "myList",
data() {
return {
show: true,
listContent: [
{
name: "1",
icon: "person",
value: this.$store.state.myStore.settings.one
},
{
name: "2",
icon: "person",
value: this.$store.state.myStore.settings.two
},
{
name: "3",
icon: "person",
value: this.$store.state.myStore.settings.three
}
]
};
}
};
May be this will help. Long one, but it works.
const myModule = {
state: {
test: "modulle",
settings: {
one: "This is one",
two: "This is two",
three: "This is three"
}
}
};
const store = new Vuex.Store({
modules: { myModule }
});
new Vue({
el: "#app",
store,
data() {
return {
listContent: [
{
name: "1",
icon: "person",
value: null
},
{
name: "2",
icon: "person",
value: null
},
{
name: "3",
icon: "person",
value: null
}
]
};
},
watch:{
'$store.state.myModule.settings.one':{
immediate:true,
handler:function(value){
this.listContent[0].value = value;
}
},
'$store.state.myModule.settings.two':{
immediate:true,
handler:function(value){
this.listContent[1].value = value;
}
},
'$store.state.myModule.settings.three':{
immediate:true,
handler:function(value){
this.listContent[2].value = value;
}
},
}
});
Hello I have this code in my symfony 3 project :
TWIG TEMPLATE:
<div id="fileManagerContainer" class="AppContent">
{% verbatim %}
<!-- item template -->
<script type="text/x-template" id="item-template">
<li>
<div
:class="{bold: isFolder}"
#click="toggle"
#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" #click="addChild">+</li>
</ul>
</li>
</script>
{% endverbatim %}
<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>
</div>
VUE FILE :
// 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({
delimiters: ['{{', '}}'],
el: '#demo',
data: {
treeData: data
}
})
ant it works on jsfiddle, but doesnt do a thing in real project. All scripts are loaded perfectly, Vue.js works but just this piece of code does not. Any ideas ?
Learning JS and trying to figure out the tree view from Vue.js.
The example is on the Vue site here: Tree view on Vue site
What I have done is created a html doc that has the HTML code as per JSFiddle:
<!DOCTYPE html>
<html>
<head>
<style>
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;
}
</style>
</head>
<body>
<script type="text/x-template" id="template">
<div v-class="bold: isFolder"
v-on="click: toggle, dblclick: changeType">
{{model.name}}
<span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<li class="item"
v-repeat="model: model.children"
v-component="item">
</li>
<li v-on="click: addChild">+</li>
</ul>
</script>
<script src="JS/app.js"></script>
<script src="JS/vue.min.js"></script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<li class="item"
v-component="item"
v-with="model: treeData">
</li>
</ul>
</body>
</html>
Then I added the Javascript to a separate app.js file and put it in a folder in same dir as html file called JS.
I have also put vue.min.js in that folder but the code doesn't work at all.
It appears that the script is just not running as the CSS and everything else displays OK.
I'm probably making a fairly elementary mistake here in terms of pointing towards correct js files or leaving something out but the syntax hasn't been changed from the working online demo so I doubt it's that.
JS:
// 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: '#template',
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) {
this.model.$add('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
}
})
If anyone has any ideas of what I am doing incorrectly please let me know.
Issue present on all browsers(Safari, Firefox, Chrome) -> I am fairly certain this is a high level issue as the JSFiddle page and example page linked above both display properly and I literally just copy+pasted the code into the html and js files in addition to downloading and referencing vue.min.js
All help and suggestions welcome!
M
Edit:
After Orland's answer below I included all the code in one file as below:
<!DOCTYPE html>
<html>
<head>
<style>
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;
}
</style>
</head>
<body>
<script src="https://cdn.rawgit.com/yyx990803/vue/master/dist/vue.min.js"></script>
<!-- item template -->
<script type="text/x-template" id="item-template">
<div v-class="bold: isFolder"
v-on="click: toggle, dblclick: changeType">
{{model.name}}
<span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<li class="item"
v-repeat="model: model.children"
v-component="item">
</li>
<li v-on="click: addChild">+</li>
</ul>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<item model="{{ treeData }}"></item>
</ul>
<script>
// demo data
var data = {
name: 'My Tree',
children: [
{ 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'],
data: function () {
return {
open: false,
model: {}
}
},
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) {
this.model.$add('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
}
})
</script>
</body>
</html>
This works perfectly but I am developing an App that will be run mostly offline so I tried changing the vue.min.js source to the local vue.min.js I have and it stops working!! The change I make is:
From <script src="https://cdn.rawgit.com/yyx990803/vue/master/dist/vue.min.js"></script>
to <script src="JS/vue.min.js"></script>
Cannot understand this but assume it is something I am doing in locating the vue.min.js!!!???
It seems that even the original snippet on Vue JS site is not working. I updated the snippet to make it work.
// demo data
var data = {
name: 'My Tree',
children: [
{ 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'],
data: function () {
return {
open: false,
model: {}
}
},
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) {
this.model.$add('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
}
})
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://cdn.rawgit.com/yyx990803/vue/master/dist/vue.min.js"></script>
<!-- item template -->
<script type="text/x-template" id="item-template">
<div v-class="bold: isFolder"
v-on="click: toggle, dblclick: changeType">
{{model.name}}
<span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<li class="item"
v-repeat="model: model.children"
v-component="item">
</li>
<li v-on="click: addChild">+</li>
</ul>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<item model="{{ treeData }}"></item>
</ul>