Why I cannot run this script in the netlify? - vue.js

I tried to run this code with github and deploy using the netlify but after deploying the code input cant be clicked but in my local machine it can be run perfectly. What is the problem of my code here? Or the problem that netlify cant execute my js script?
<template>
<v-layout
column
justify-center
align-center
>
<h3> Kalkulator Belian Semula 916</h3>
<br>
<v-alert
text
type="info"
>
Sila masukkan berat barang kemas <strong>916</strong> anda!
</v-alert>
<v-flex
xs12
sm8
md6
>
<tr v-for="(item, index) in items">
<td>
<v-text-field
label="Weight"
placeholder="Weight 916"
type="number"
suffix="gram"
solo-inverted
v-model.number="item.qty"
></v-text-field></td>
<!--
<td><v-btn small icon #click="addRow(index)"><v-icon>mdi-plus</v-icon></v-btn></td>
<td><v-btn small icon #click="removeRow(index)"><v-icon>mdi-minus</v-icon></v-btn></td>
-->
<tr>
<td><v-btn x-large color="red" block readonly>Total = RM {{total}}</v-btn></td>
</tr>
</tr>
</v-flex>
</v-layout>
</template>
<script>
export default {
data () {
return {
// dummy data
items: [
{qty: 1, price: 0 },
],
}
},
computed: {
subtotalRow() {
return this.items.map((item) => {
return Number(item.qty * 215)
});
},
total() {
return this.items.reduce((total, item) => {
return total + item.qty *215;
}, 0);
}
},
methods: {
addRow(index) {
this.items.splice(index + 1, 0, {
qty: 1, price: 0
});
},
removeRow(index) {
this.items.splice(index, 1);
}
}
}
</script>
Here the link to the sample running application I have try to run in heroku and netlify but the error came out like this
DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method.
Do anyone know how to run the code perfectly?

It seems that there are various reasons as to why this problem occurs (see here and here). However, there are some minor syntax errors in your code that might contribute to this error.
When using table elements, you need to have a proper syntax for that. In your case, you need to wrap your <tr/> with the <table/> element.
<table>
<tr>
<td>...</td>
<td>...</td>
...
</tr>
<tr>
<td>...</td>
<td>...</td>
...
</tr>
</table>
You must provide a v-bind:key, or simply :key, to the elements of v-for.
<tr v-for="(item, i) in items" :key="i">
...
</tr>
I made a demo at codesandbox, and deployed it to Netlify successfully without any console errors.

First of all, I think using tr is not suited for this. I recommend that you use div instead. And always add keys if your using v-for.
So your code should at least look like this.
<v-layout column justify-center align-center >
<h3> Kalkulator Belian Semula 916</h3>
<v-alert text type="info">
Sila masukkan berat barang kemas <strong>916</strong> anda!
</v-alert>
<v-flex xs12 sm8 md6 >
<div v-for="(item, index) in items" :key="index">
<div>
<v-text-field
label="Weight"
placeholder="Weight 916"
type="number"
suffix="gram"
solo-inverted
v-model.number="item.qty"
></v-text-field></div>
</div>
<div>
<v-btn x-large color="red" block readonly>Total = RM {{total}}</v-btn>
</div>
</v-flex>
</v-layout>

Related

Parent data not updated when using sync in v-for loop

I've build a component named Turno (a work shift). I have some kind of calendar, for every day I have more instance of Turno.
If I book myself to a shift then I need to add my name in the shift, but reactivity seems not to work, parent object (with all shifts) doesn't update. I've also added .sync to property.
Shift template:
<div v-for="mansione in turno.mansioni">
<v-row class="ma-0 pa-0 align-end">
<v-col class="ma-0 pa-0" cols="8">
<div class="caption font-weight-bold nome_mansione">{{ mansione.nome.toLowerCase() }}
<span class="caption">(Min. {{ mansione.min }})</span>
</div>
</v-col>
<v-col class="ma-0 pa-0 text-right" cols="4">
<div class="caption font-weight-bold nome_mansione">
<pulsante-generico :small="true" icon="mdi-account-plus" color="orange" #click="aggiungiPersona(turno,mansione)"/>
</div>
</v-col>
</v-row>
<hr class="mt-0">
<div v-for="milite in mansione.militi" class="ma-2" style="line-height: 0.8rem">
{{ milite.cognome }} {{ milite.nome }}
</div>
</div>
After a shift book (this should make reactivity? After this nothing changes, parent object is not affected):
turniService.prenotaTurno(prenotazione).then(d => {
this.$emit("update:turno", d || this.turno)
this.close()
})
Props in shift component:
props: {
turno: {
type: Object,
default: () => {
return {
dataInizio: null,
dataFine: null,
id: 0,
tipo: "",
mansioni: []
}
}
}
},
In the parent I render shifts like this:
<v-col v-for="day in dati.giorni">
<DatiGiornoCalendario :day="day.giorno"/>
<Turno v-for="(turno, i) in day.turni"
:turno.sync="turno"
/>
</v-col>
The turno variable in <Turno v-for="(turno, i) in day.turni" :turno.sync="turno" /> is a local variable in the loop
Use this instead: <Turno v-for="(turno, i) in day.turni" :turno.sync="day.turni[i]" />

How do I lazy load item lists on Vuejs and Vuetify's lazyload?

Im trying to make an infinite scroll list but it's really not lazy loading, been stuck with this for hours, the whole list will come in.
.....
<v-col
v-for="(post, i) in posts"
:key="i"
cols="12"
>
<v-lazy
v-model="isActive"
:options="{
threshold: .5
}"
transition="fade-transition"
>
{{Content here}}
</....
API used for test : https://jsonplaceholder.typicode.com/posts
There is a new virtual-scroller component, but it doesn't work with responsive content like grid rows/cols. Instead use v-lazy...
I discovered that the columns need to have defined min-height (approx. to the expected height of the cards) in order for the v-lazy intersection observer to work. Use something like a v-sheet or v-responsive to set the min-height and contain the cards.
Also bind the v-model of the v-lazy to each post (ie: post.isActive), instead of a global isActive var...
<v-col lg="3" md="4" sm="6" cols="12" v-for="(post, index) in posts">
<v-sheet min-height="250" class="fill-height" color="transparent">
<v-lazy
v-model="post.isActive" :options="{
threshold: .5
}"
class="fill-height">
<v-card class="fill-height" hover>
<v-card-text>
<v-row :key="index" #click="">
<v-col sm="10" cols="12" class="text-sm-left text-center">
#{{ (index+1) }}
<h2 v-html="post.title"></h2>
<div v-html="post.body"></div>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-lazy>
</v-sheet>
</v-col>
Demo: https://codeply.com/p/eOZKk873AJ
I can suggest another solution with v-intersect, which works perfect for me.
Sorry, the snippet may be not working as composed of my code, but the idea should be pretty clear
<template>
<v-list class="overflow-y-auto" max-height="500">
<v-list-item v-for="item in items">
{{ item.name }}
</v-list-item>
<v-skeleton-loader v-if="moreDataToAvailable" v-intersect="loadNextPage" type="list-item#5" />
</v-list>
</template>
<script lang="ts">
import Vue from 'vue'
const pageSize = 10
export default Vue.extend({
data(): any {
return {
pageLoaded: 0,
totalCount: 100,//fetch from API
items: []
}
},
computed: {
moreDataToAvailable (): boolean {
return Math.ceil(this.totalCount / pageSize) - 1 > this.pageLoaded
}
},
methods {
async loadNextPage (entries: IntersectionObserverEntry[]) {
if (entries[0].isIntersecting && this.moreDataToAvailable) {
const nextPage = this.pageLoaded + 1
const loaded = await this.loadPage(nextPage) //API call
loaded.data.forEach((item: any) => this.items.push(item))
this.totalCount = loaded.totalCount
this.pageLoaded = nextPage
}
},
}
})
</script>

Vue + Vuetify performance

So I have a Vuetify data table with a lot of items, I need to display 50/100/150 items.
The problem, when I have 50 items it takes about 2 to 3 seconds to load the entire table. My request takes about 500ms to load and vue takes 3 seconds to render. When I have 150 items it takes about 10 seconds.
Is it possible to reduce render time to at least 5 seconds with 150 items?
I'm using this table: https://vuetifyjs.com/en/components/data-tables#data-tables
My table code:
<template>
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
:items-per-page="50"
:footer-props="rowsPerPageItems"
>
<TableRow :row="item" v-for="item in clientList" :key="item.id">
</v-data-table>
</template>
// my clientList is async response from server
import { mapGetters } from "vuex";
export default {
data(){
return {
rowsPerPageItems: [50, 100, 150]
}
},
computed: {
...mapGetters["clientList"] // this comes from vuex, I don't think it's relevant. It returns about 400 client info
}
}
<!-- My component TableRow -->
<template>
<tr>
<td>
<v-checkbox v-model="row.checked" color="primary"></v-checkbox>
</td>
<td>{{ row.data }}</td>
<td>{{ row.name }}</td>
<td>
<!-- This is a jQuery plugin, I need it to keep track of every key pressed -->
<Select2
:id="row.id.toString()"
:settings="{ minimumInputLength: 3, ajax: ajaxData, placeholder: labels.descriptionList[row.description] }"
#select="handleSelect2($event)"
/>
</td>
<td v-if="this.is_expense">
<v-select
:items="labels.categoryName"
:placeholder="labels.categoryList[row.category]"
#input="updateCashflow"
v-model="row.category"
dense
></v-select>
</td>
<td v-else></td>
<td>{{ row.amount }}</td>
</tr>
</template>
Remove that component and read v-data-table documentation.
You shouldn't add v-checkbox to make it rows selectable, use show-select prop instead with v-model on v-data-table
Use item.<name> slot to add custom components into cells
In my case, I really need components inside my table so I used
<v-select v-if="mountedComponent" :items="myList"/>
<span v-else>Some default value</span>
When page mounted I set mounted to true
export default {
name: "Test",
data(){
return {
mountedComponent: false,
myList:["item 1", "item 2"]
}
},
mounted(){
this.mountedComponent= true;
}
}
This solved my performance issue, going from 10 ~ 15 seconds delay to 100ms.

Condition on template with v-if using v-slot prop

I'm trying to make a condition to enable a named slot like this:
<template v-slot:item="{ item }" v-if="item.loading">
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</template>
My use case is a Vuetify datatable: each item has a "loading" property, and I'd like to activate "item" slot only if the row is loading ("item" slot is Slot to replace the default rendering of a row)
The error is that item is undefined in the v-if, which seems logic : item is only defined for template children tag.
Is there a way to solve this problem?
You can filter the items that you pass to the datatable with a computed property.
Can you just not swap element based on loading ?
Vue.config.devtools = false;
Vue.config.productionTip = false;
var app = new Vue({
el: '#app',
data: {
items: [{data : "", loading: true}, {data : "Some data", loading: false}]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="item in items">
<div>
<div v-if="item.loading">
Loading...
</div>
<div v-else>
{{item.data}}
</div>
</div>
</div>
</div>
I had a similar problem, and I solved it in Vuetify 2 by importing VDataTable/Row as 'v-data-table-row', and using it to render 'regular' table rows, and for custom rows I used my own template.
JavaScript
import Row from 'vuetify/lib/components/VDataTable/Row.js';
export default {
components: { 'v-data-table-row': Row },
data() {
return {
currentItemName: 'Ice cream sandwich'
}
}
// headers, items, etc...
}
HTML
<template v-slot:item="{ item }">
<tr v-if="item.name == currentItemName" class="blue-grey lighten-4">
<td>Custom prefix - {{ item.name }}</td>
<td colspan="2">{{ item.calories }} - Custom suffix</td>
</tr>
<v-data-table-row v-else :headers="headers" :item="item">
<template
v-for="(index, name) in $scopedSlots"
v-slot:[name.substr(5)]="data"
>
<slot
v-if="name.substr(0, 5) === 'item.'"
:name="name"
v-bind="data"
></slot>
</template>
</v-data-table-row> </template
You can check out working example here.
You can just put the v-if on the child element
<template #item="{ item }">
<v-progress-circular
v-if="item.loading"
color="primary"
indeterminate
></v-progress-circular>
</template>

Passing scoped slots through multiple components

I have 2 components. One is a list component (list.vue). The other takes a list and wraps it with other features(searchandlist). Now, from the page.vue file I would like to call SearchAndList, giving it the list, and the render props. However, I cant get the dynamic data to show, only static.
ListItems.vue
<span>
<div v-for="item in items" :key="item.id">
<slot v-bind="item"></slot>
</div>
SearchAndList.vue
<div class="clients-list">
<div class="table-responsive">
<table class="table table-striped table-hover">
<list-items :items="items">
<slot name="row"></slot>
</list-items>
</table>
</div>
</div>
page.vue
<template>
<search-and-list :items="items">
<tr slot="row">
Hi
</tr>
</search-and-list>
</template>
<script>
import SearchAndList from '../components/base/SearchAndList'
export default {
components: {
SearchAndList
},
data() {
return {
items: [
{ id: 10, name: 'Marc' },
{ id: 11, name: 'Bob' },
{ id: 12, name: 'George' }
]
}
}
}
</script>
When using this, I get Hi listed out 3 times as exprected. However, when changing this to:
<search-and-list :items="items">
<tr slot="row" slot-scope="item">
{{ item.name}}
</tr>
</search-and-list>
I do get "Duplicate presence of slot "default" found in the same render tree - this will likely cause render errors." in the console, however, even giving the default slot a name=list, the error is the same, but default is not list.
Im sure there is something simple that I am missing. Any guidance would be great.
EDIT:
I have a child component () that exposes an { item } to its parent (). However, I would like to access { item } in the grand-parent (page.vue).
There is 2 missing bit in your configuration.
Expose you item in the List.vue:
<span>
<div v-for="item in items" :key="item.id">
<slot :item="item"></slot>
</div>
Then you need to bind the name in your SearchAndList.vue.
So try:
<div class="clients-list">
<div class="table-responsive">
<table class="table table-striped table-hover">
<list-items :items="items">
<slot scope-slot="{ item }" :name="item.name"></slot>
</list-items>
</table>
</div>