Composition API arrow function is not recognized in Nuxt js - javascript

I am using the Nuxt Composition API and trying to render the elements in getList to my page. When I load the page I get an error saying that "_vm.getList is not a function".
<template>
<div class="drop-zone">
<div v-for="item in getList(1)" :key="item.id" class="drag-el">
{{item.title}}
</div>
</div>
</template>
<script>
export default{
setup(){
const items = ref([
{id:0, title: 'Item A', list:1},
{id:1, title: 'Item B', list:1},
{id:2, title: 'Item C', list:2},
]),
const getList = (list) => {
return items.value.filter((item) => item.list == list);
},
return {
getList,
}
},
}
</script>

You need to import ref (not sure how), then this one should work
<template>
<div class="drop-zone">
<div v-for="item in getList(1)" :key="item.id" class="drag-el">
{{ item.title }}
</div>
</div>
</template>
<script>
export default {
setup() {
const items = ref([
{ id: 0, title: 'Item A', list: 1 },
{ id: 1, title: 'Item B', list: 1 },
{ id: 2, title: 'Item C', list: 2 },
])
const getList = (list) => {
return items.value.filter((item) => item.list === list)
}
return {
getList,
}
},
}
</script>
At least, ESlint is not complaining with this. Sorry if I can't help more, didn't worked with Vue3 so far (yet).

Related

How to map through array of objects and list each object in a card using javascript and react?

i have the data structure like below,
const item = {
id: '1',
orders: [
{
id: '1',
title: 'order-1',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
}
],
subItems: [
{
id: '1',
title: 'subitem-one',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '1',
title: 'subitem1-order-one',
status: 'new',
},
{
id: '2',
title: 'subitem1-order-two',
status: 'new',
},
]
},
{
id: '2',
title: 'subitem-two',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '2',
title: 'subitem2-order-one',
status: 'new',
},
},
I have to display each subitem name from above data in each card in a list.
below is how it should look in a list.
below is my code,
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
//how should i map the items data to loop through each subitem and display it as in the picture above.
);
}
I am not sure how to loop through each subitem and display its name in a card using javascript and react.
could someone help me with this. thanks.
Ciao, assuming that you are using Card component from material ui you could do something like:
import { Card, CardHeader} from '#material-ui/core';
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
items.subItems.map(el => {
<Card>
<CardHeader
title={el.title}
/>
</Card>
})
);
}
I'm assuming that Parent is a React functional component, so you can return the data in this way,
function Parent({items} : Props) {
return (
<div>
{
items.subItems.map(function (subItem) {
return <div>{subItem.title}</div>;
});
}
</div>
)
}
The template is shown below:
const Parent = () => {
const data = [...] // the data must be an array
return data.map(child => <Child data={child} />)
}

Vue not Defined

I have been struggling this error for a while now. I've tried multiple ways and none of them work. All I am trying to do is to get this simple component working. Someone help please. :)
<script>
const app = new Vue({
el: "#main",
data: function(){
return {
search: '',
customers: [
{ id: '1', name: 'Something', },
{ id: '2', name: 'Something else', },
{ id: '3', name: 'Something random', },
{ id: '4', name: 'Something crazy', }
]};
},
computed:
{
filteredCustomers:function()
{
var self=this;
return this.customers.filter(function(cust){return cust.name.toLowerCase().indexOf(self.search.toLowerCase())>=0;});
//return this.customers;
}
}
});
</script>
<template>
<div id="main">
Search: <input type="text" v-model="search"/>
<div v-bind:v-for="customer in filteredCustomers">
<span>{{customer.name}}</span>
</div>
</div>
</template>
You should include the Vue library.
One way of doing so is including using <script> as described in Vue's documentation.

react-sortablejs - Setting the 'onChange' method on an object with nested arrays

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>
);
};

Vue keep alive component when moving to other array

I'm trying to keep a component alive when moving the bound item object to a different data array. Because it gets moved, the default keep-alive tag doesn't work.
I need this to improve loading time when dynamic components in my app use external libraries.
Simplified example: (https://jsfiddle.net/eywraw8t/24419/)
HTML:
<div id="app">
<div v-for="list in lists">
<h1>{{ list.title }}</h1>
<ul>
<draggable v-model="list.items" :options="{group: 'list-items'}">
<list-item
v-for="item in list.items"
:key="item.key"
:content="item.content">
</list-item>
</draggable>
</ul>
</div>
</div>
JS:
Vue.component('list-item', {
props: {
content: {
required: true
}
},
mounted () {
document.body.insertAdjacentHTML('beforeend', 'Mounted! ');
},
template: '<li>{{ content }}</li>'
})
new Vue({
el: "#app",
data: {
lists: [
{
title: 'List 1',
items: [
{ key: 'item1', content: 'Item 1' },
{ key: 'item2', content: 'Item 2' },
{ key: 'item3', content: 'Item 3' }
]
},
{
title: 'List 2',
items: [
{ key: 'item4', content: 'Item 4' },
{ key: 'item5', content: 'Item 5' },
{ key: 'item6', content: 'Item 6' }
]
}
]
}
})
If the problem is just one of caching expensive html build, you can do it by removing the list-item component from the template and building them ahead of time in app.mounted().
How well this works in your real-world scenario depends on the nature of item.content and it's lifecycle.
console.clear()
const ListItem = Vue.component('list-item', {
props: {
content: {
required: true
}
},
mounted () {
document.body.insertAdjacentHTML('beforeend', 'Mounted! ');
},
template: '<li>{{ content }}</li>'
})
new Vue({
el: "#app",
methods: {
getHtml(content) {
const li = new ListItem({propsData: {content}});
li.$mount()
return li.$el.outerHTML
}
},
mounted () {
this.lists.forEach(list => {
list.items.forEach(item => {
const cacheHtml = this.getHtml(item.content)
Vue.set( item, 'cacheHtml', cacheHtml )
})
})
},
data: {
lists: [
{
title: 'List 1',
items: [
{ key: 'item1', content: 'Item 1' },
{ key: 'item2', content: 'Item 2' },
{ key: 'item3', content: 'Item 3' }
]
},
{
title: 'List 2',
items: [
{ key: 'item4', content: 'Item 4' },
{ key: 'item5', content: 'Item 5' },
{ key: 'item6', content: 'Item 6' }
]
}
]
}
})
ul {
margin-bottom: 20px;
}
li:hover {
color: blue;
cursor: move;
}
h1 {
font-size: 20px;
font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.6.0/Sortable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/15.0.0/vuedraggable.min.js"></script>
<div id="app">
<div v-for="list in lists">
<h1>{{ list.title }}</h1>
<ul>
<draggable v-model="list.items" :options="{group: 'list-items'}">
<div v-for="item in list.items" :key="item.key">
<li v-html="item.cacheHtml"></li>
</div>
</draggable>
</ul>
</div>
</div>
Reactive item.content
To keep reactivity when item.content changes, you will need a little more code.
add a copy of the item.content to the cache
add a method to fetch the cached html with refresh if content has changed.
(You may be able to do this a little more elegantly with a parameterized computed property).
To simulate an item.content change, I've added a setTimeout to mounted().
console.clear()
const ListItem = Vue.component('list-item', {
props: {
content: {
required: true
}
},
mounted () {
document.body.insertAdjacentHTML('beforeend', 'Mounted! ');
},
template: '<li>{{ content }}</li>'
})
new Vue({
el: "#app",
methods: {
getHtml(content) {
const li = new ListItem({
propsData: { content }
});
li.$mount()
return li.$el.outerHTML
},
cacheHtml(item) {
if (item.cache && item.cache.content === item.content) {
return item.cache.html
} else {
const html = this.getHtml(item.content)
const cache = {content: item.content, html}
Vue.set(item, 'cache', cache)
}
}
},
mounted () {
this.lists.forEach(list => {
list.items.forEach(item => {
this.cacheHtml(item)
})
})
setTimeout(() =>
Vue.set( this.lists[0].items[0], 'content', 'changed' )
,2000)
},
data: {
lists: [
{
title: 'List 1',
items: [
{ key: 'item1', content: 'Item 1' },
{ key: 'item2', content: 'Item 2' },
{ key: 'item3', content: 'Item 3' }
]
},
{
title: 'List 2',
items: [
{ key: 'item4', content: 'Item 4' },
{ key: 'item5', content: 'Item 5' },
{ key: 'item6', content: 'Item 6' }
]
}
]
}
})
ul {
margin-bottom: 20px;
}
li:hover {
color: blue;
cursor: move;
}
h1 {
font-size: 20px;
font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.6.0/Sortable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/15.0.0/vuedraggable.min.js"></script>
<div id="app">
<div v-for="list in lists">
<h1>{{ list.title }}</h1>
<ul>
<draggable v-model="list.items" :options="{group: 'list-items'}">
<div v-for="item in list.items" :key="item.key">
<li v-html="cacheHtml(item)"></li>
</div>
</draggable>
</ul>
</div>
</div>
i looked into your problem and i think i might found a solution, i cannot do it in js fiddle but i'll try and explain it:
in your js fiddle the mounted is hooked in your list-item component, so indeed every time that state changed (when dragging), the event is triggered.
i create a setup with a main templated component (componentX), with a mounted function, and then created a seperated list-item component
in my sample you will see the mounted twice at the start, that is normal since we have 2 lists! but then when you start to drag and drop you will not get additional mounted events
you can download the solution in a zip from:
http://www.bc3.eu/download/test-vue.zip
it is a vue cli project, so you can just npm run dev to start a local server

Vue.js and Twig weird collision

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 ?

Categories