how can i achieve pagination in vue js - javascript

please i'm trying to paginate data but i'm getting this error in my console
Property or method "$index" is not defined on the instance but referenced during render.
this is my html template which displays the data in which i'll want to paginate
<div id="heroes">
<table class="table table-striped">
<thead>
<tr>
<td>Hero Name</td>
<td>Universe</td>
</tr>
</thead>
<tbody>
<tr
v-for="hero in heroes "
v-show="setPaginate($index)"
>
<td>{{ hero.name }}</td>
<td>{{ hero.universe }}</td>
</tr>
</tbody>
</table>
<div id="pagination">
<a
href="#"
class="btn btn-default"
v-for="page_index in paginate_total"
#click.prevent="updateCurrent(page_index + 1)"
>
{{ page_index + 1 }}
</a>
</div>
</div>
this is my script tag
<script>
export default {
data() {
return {
current: 1,
heroes: [
{ name: "Wolverine", universe: "Marvel" },
{ name: "Batman", universe: "DC" },
{ name: "Beast", universe: "Marvel" },
{ name: "Superman", universe: "DC" },
{ name: "Wonder Woman", universe: "DC" },
{ name: "Iceman", universe: "Marvel" },
{ name: "Black Panther", universe: "Marvel" },
{ name: "Beast Boy", universe: "DC" },
{ name: "Captain America", universe: "Marvel" },
{ name: "Hawkgirl", universe: "DC" },
{ name: "Cyclops", universe: "Marvel" },
{ name: "Green Lantern", universe: "DC" },
],
paginate: 5,
paginate_total: 0
};
},
created() {
this.paginate_total = this.heroes.length / this.paginate;
},
methods: {
setPaginate: function(i) {
console.log(i);
if (this.current == 1) {
return i < this.paginate;
} else {
return (
i >= this.paginate * (this.current - 1) &&
i < this.current * this.paginate
);
}
},
setStatus: function(status) {
this.status_filter = status;
this.$nextTick(function() {
this.updatePaginate();
});
},
updateCurrent: function(i) {
this.current = i;
},
updatePaginate: function() {
this.current = 1;
this.paginate_total = Math.ceil(
document.querySelectorAll("tbody tr").length / this.paginate
);
}
}
};
</script>
i got the example from codepen which works fine when using it on codepen but i'm getting an error in my code ,here's the link
https://codepen.io/lorena-tapia/details/VwZzpRZ
please how can i go about this

The $index is not defined anywhere, you could define it in the v-for loop like :
<tr v-for="(hero,index) in heroes " v-show="setPaginate(index)">
<td>{{ hero.name }}</td>
<td>{{ hero.universe }}</td>
</tr>

Related

Vue.draggable - swapping between two list

I have a problem. I need to organaze two draggable table like swapping.
1 table: have 7 fixed items.
2 table: Other items.
When you swapping items from the second table to the first, a dialog box should appear to confirm swapping.
I did swap for first list, but not understand how to do for two table.
my code now:
<template>
<table>
<draggable v-model="items" tag="tbody" :move="handleMove" #end="handleDragEnd" :options="{animation:500}">
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td><td>{{ item.name }}</td><td>{{ item.age }}</td>
</tr>
</draggable>
</table>
</template>
<script>
import draggable from "vuedraggable";
export default {
components: {
draggable,
},
data() {
const items = [
{ id: 1, name: "Bianka Effertz", age: 37 },
{ id: 2, name: "Mckayla Bogan", age: 20 },
{ id: 3, name: "Estevan Mann", age: 17 },
{ id: 4, name: "Cloyd Ziemann", age: 55 }
]
return { items }
},
computed: {
orders() {
return this.items.map(x => x.id)
}
},
methods: {
handleDragEnd() {
this.$toast.show('dragEnd')
this.futureItem = this.items[this.futureIndex]
this.movingItem = this.items[this.movingIndex]
const _items = Object.assign([], this.items)
_items[this.futureIndex] = this.movingItem
_items[this.movingIndex] = this.futureItem
this.items = _items
},
handleMove(e) {
const { index, futureIndex } = e.draggedContext
this.movingIndex = index
this.futureIndex = futureIndex
return false // disable sort
}
}
</script>

How to handle complex rowspan in angular 6?

I have created table from the below mentioned JSON which works fine. I have certain condition that needs to be handled. the function which i used is also mentioned here.I also attached output image for the same.Help for the same is highly appreciated... Thanks in advance
Conditions :
if email row is empty need to remove that particular row.
Let's say value2 has one value in email, in that case it should be displayed.
rows = [];
generateTable() {
if (!this.data) {
return;
}
this.rows.push([
{
text: this.data.e_o_name,
rowspan: 0
}
]);
let maxRowSpan = 0;
this.data.matching_details.forEach((detail, i) => {
const elemRowSpan = Math.max(detail.matching_attributes.length, 1);
maxRowSpan += elemRowSpan;
if (i > 0) {
this.rows.push([])
}
this.rows[this.rows.length - 1].push({
text: detail.me_value,
rowspan: elemRowSpan
});
detail.matching_attributes.forEach((attr, j) => {
if (j > 0) {
this.rows.push([])
}
const mail = attr.me_list[0];
this.rows[this.rows.length - 1].push(
{
text: attr.me_name,
rowspan: 1
},
{
text: mail.me_email_list.map(({ me_value }) => me_value).join(', '),
rowspan: 1
},
{
text: mail.me_percent,
rowspan: 1
}
);
})
});
this.rows[0][0].rowspan = maxRowSpan;
}
```
#Josn : #
```
{
"e_id":"1234",
"e_o_name":"Contact_info",
"matching_details":[
{
"me_value":"value1",
"matching_attributes":[
{
"me_id":"1234",
"me_name":"28 sai",
"me_list":[
{
"me_type":"Email ID",
"me_email_list":[
{
"me_value":"a#gmail"
},
{
"me_value":"b#gmail"
}
],
"me_percent":"100"
}
]
},
{
"me_id":"5678",
"me_name":"29 meena",
"me_list":[
{
"me_type":"Email ID",
"me_email_list":[
{
"me_value":"c#gmail.com"
},
{
"me_value":",d#gmail.com"
}
],
"me_percent":"100"
}
]
}
]
},
{
"me_value":"value2",
"matching_attributes":[
{
"me_id":"1234",
"me_name":"rimzim",
"me_list":[
{
"me_type":"Email ID",
"me_email_list":[
{
"me_value":"p#gmail"
},
{
"me_value":"q#gmail"
}
],
"me_percent":"100"
}
]
},
{
"me_id":"5678",
"me_name":"ranu",
"me_list":[
{
"me_type":"Email ID",
"me_email_list":[
{
"me_value":"t#gmail.com"
},
{
"me_value":",u#gmail.com"
}
],
"me_percent":"100"
}
]
}
]
}
]
}
Seems like you want to put in column (attr) level validations, so in the html while looping through it you will need to implement the checks
https://stackblitz.com/edit/angular-zm1ap1?file=src/app/app.component.html
<table>
<tbody>
<tr>
<th>contact</th>
<th>ty</th>
<th>ed</th>
<th>mail</th>
<th>percent</th>
</tr>
<tr *ngFor="let row of rows">
<!-- check if row is empty or could add additional check such
row[3].text (email) is true
-->
<ng-container *ngIf='row && row.length > 0'>
<td [attr.rowspan]='row[0].rowspan'>{{row[0].text}}</td>
<td *ngIf='row.length > 1' [attr.rowspan]='row[1].rowspan'>{{row[1].text}}</td>
<td *ngIf='row.length > 2' [attr.rowspan]='row[2].rowspan'>{{row[2].text}}</td>
<td *ngIf='row.length > 3' [attr.rowspan]='row[3].rowspan'>{{row[3].text}}</td>
<td *ngIf='row.length > 4' [attr.rowspan]='row[4].rowspan'>{{row[4].text}}</td>
</ng-container>
</tr>
</tbody>
</table>

How to merge properties JavaScript objects

I'm starting with Vue and I'm having a little difficulty.
In the image below I have a table with some items:
Every time an item is chosen and the amount increased I need that in my addOptional method (optional) my variable gets the amount of that item concatenated with the value. Example if I choose hammer would look like this `
let variavel = opcional.Qtd + 'x' + opcional.Code
If I give console.log the result would be 2x1
But if I choose another option, example Serrote I should join the first choice in that same variable and separate with Pipe ( | ) Example would look like this.
2x1 | 1x2
How should I do this? Should I use array?
What I already have:
new Vue({
el: '#app',
data() {
return {
Opcionais: [
{ Code: 1, Nome: 'Martelo', Valor: 50.00, Qtd: 0 },
{ Code: 2, Nome: 'Serrote', Valor: 50.00, Qtd: 0 },
{ Code: 3, Nome: 'Prego', Valor: 60.00, Qtd: 0 }
]
}
},
methods: {
addOpcional(opcional) {
// The variable below should receive the value of the quantity plus the code. If more than one option is chosen the variable must receive this new value and separate with pipe example Qty (2) x Code (2) | Qty (3) x Code (2)
opcional.Qtd += 1
let Code = [opcional.Qtd + 'x' + opcional.Code]
},
remove(opcional) {
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<template>
<div class="usuario-lista">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Nome</th>
<th>Valor Unitário</th>
<th>Valor Total</th>
</tr>
</thead>
<tbody>
<tr v-for="opcional in Opcionais" :key="opcional.Code">
<td>
<button #click="opcional.Qtd ? opcional.Qtd-- : false">-</button>
<input type="text" :value="opcional.Qtd">
<button #click="addOpcional(opcional)">+</button>
</td>
<td>{{ opcional.Nome }}</td>
<td>{{ opcional.Valor }}</td>
<td>{{ opcional.Valor * opcional.Qtd }}</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
This seems like a perfect use case for a computed property:
computed: {
Code: function () {
return this.Opcionais
.filter( opcional => opcional.Qtd > 0 )
.map( opcional => opcional.Qtd + 'x' + opcional.Code )
.join( ' | ' );
}
}
Here's a full working example, showing the code below the table and updating it live:
new Vue({
el: '#app',
data() {
return {
Opcionais: [
{ Code: 1, Nome: 'Martelo', Valor: 50.00, Qtd: 0 },
{ Code: 2, Nome: 'Serrote', Valor: 50.00, Qtd: 0 },
{ Code: 3, Nome: 'Prego', Valor: 60.00, Qtd: 0 }
]
}
},
computed: {
Code: function () {
return this.Opcionais
.filter( opcional => opcional.Qtd > 0 )
.map( opcional => opcional.Qtd + 'x' + opcional.Code )
.join( ' | ' );
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<template>
<div class="usuario-lista">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Nome</th>
<th>Valor Unitário</th>
<th>Valor Total</th>
</tr>
</thead>
<tbody>
<tr v-for="opcional in Opcionais" :key="opcional.Code">
<td>
<button #click="opcional.Qtd > 0 && opcional.Qtd--">-</button>
<input type="text" v-model.number="opcional.Qtd">
<button #click="opcional.Qtd++">+</button>
</td>
<td>{{ opcional.Nome }}</td>
<td>{{ opcional.Valor }}</td>
<td>{{ opcional.Valor * opcional.Qtd }}</td>
</tr>
</tbody>
</table>
</div>
<p>Code: {{Code}}</p>
</template>
</div>
Not really familiar with Vue but you can reduce Opcionais like so:
const Opcionais = [
{ Code: 1, Nome: 'Martelo', Valor: 50.00, Qtd: 0 },
{ Code: 2, Nome: 'Serrote', Valor: 50.00, Qtd: 0 },
{ Code: 3, Nome: 'Prego', Valor: 60.00, Qtd: 0 }
];
const result = Opcionais.reduce((arr, { Qtd, Code }) => {
return [...arr, `${Qtd}x${Code}`];
}, []).join(' | ');
console.log(result);
You can use the spread operator to preserve the current state and add new items.
To join with pipes, use the 'reducer' as answered below or just do it in the html, as you wish.
new Vue({
el: '#app',
data() {
return {
Opcionais: [
{ Code: 1, Nome: 'Martelo', Valor: 50.00, Qtd: 0 },
{ Code: 2, Nome: 'Serrote', Valor: 50.00, Qtd: 0 },
{ Code: 3, Nome: 'Prego', Valor: 60.00, Qtd: 0 }
],
Elements: []
}
},
methods: {
addOpcional(opcional) {
// The variable below should receive the value of the quantity plus the code. If more than one option is chosen the variable must receive this new value and separate with pipe example Qty (2) x Code (2) | Qty (3) x Code (2)
opcional.Qtd += 1
this.Elements = [...this.Elements, (opcional.Qtd + 1) + 'x' + opcional.Code]
},
remove(opcional) {
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<template>
<div class="usuario-lista">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Nome</th>
<th>Valor Unitário</th>
<th>Valor Total</th>
</tr>
</thead>
<tbody>
<tr v-for="opcional in Opcionais" :key="opcional.Code">
<td>
<button #click="opcional.Qtd ? opcional.Qtd-- : false">-</button>
<input type="text" :value="opcional.Qtd">
<button #click="addOpcional(opcional)">+</button>
</td>
<td>{{ opcional.Nome }}</td>
<td>{{ opcional.Valor }}</td>
<td>{{ opcional.Valor * opcional.Qtd }}</td>
</tr>
</tbody>
</table>
<pre>{{ Elements.join("|") }}</pre>
</div>
</template>
</div>

Knockout Table : Highlight a Table Row

I have an Example Fiddle here. In this Table I wish to achieve Highlighting a Particular Row selected. If unselected Row should not be highlighted.
One of many sample I found Fiddle but I am unable to incorporate them inside my Example Fiddle Above.
Below is the HTML Code which shows basic Table.
<table id="devtable">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr data-bind=" click: $parent.select ">
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Status"></td>
</tr>
</tbody>
ID :
Name :
Status :
Here is the knockout function to do manipulations
<Script>
var rowModel = function (id, name, status) {
this.ID = ko.observable(id);
this.Name = ko.observable(name);
this.Status = ko.observable(status);
};
var myData = [{
id: "001",
name: "Jhon",
status: "Single"
}, {
id: "002",
name: "Mike",
status: "Married"
}, {
id: "003",
name: "Marrie",
status: "Complicated"
}];
function MyVM(data) {
var self = this;
self.items = ko.observableArray(data.map(function (i) {
return new rowModel(i.id, i.name, i.status);
}));
self.select = function(item) {
self.selected(item);
self.enableEdit(true);
};
self.flashCss = ko.computed(function () {
//just an example
return 'flash';
});
self.selected = ko.observable(self.items()[0]);
self.enableEdit = ko.observable(false);
self.changeTableData = function() {
// How do I change the Data here and it should also reflect on the Page.
// If I do binding depending on condition it gives me error
if(true){
var myData = [{
id: "001",
name: "Jhon",
status: "Single"
}, {
id: "002",
name: "Mike",
status: "Married"
}, {
id: "003",
name: "Marrie",
status: "Complicated"
}];
}
else{
myData = [{
id: "111",
name: "ABC",
status: "Single"
}, {
id: "222",
name: "XYZ",
status: "Married"
}, {
id: "3333",
name: "PQR",
status: "Complicated"
}];
}
}
}
ko.applyBindings(new MyVM(myData));
</script>
CSS code below
.flash { background-color: yellow; }
You can use the css binding to add the .flash class based on the currently selected value:
<tr data-bind="click: $parent.select,
css: { flash: $parent.selected() === $data }">
...
</tr>
If you don't like this logic being defined in the view, you can pass a reference to the selected observable and create a computed property inside your RowModel:
var RowModel = function( /* ... */ selectedRow) {
// ...
this.isSelected = ko.pureComputed(function() {
return selectedRow() === this;
}, this);
}
Here's the quick fix in your fiddle:
http://jsfiddle.net/wa78zoe4/
P.S. if you want toggle-behavior, update select to:
self.select = function(item) {
if (item === self.selected()) {
self.selected(null);
self.enableEdit(false);
} else {
self.selected(item);
self.enableEdit(true);
}
};

Dynamically Filter an Array of Objects in Vue.js

I have a Vue.js app. In this app, I'm trying to dynamically apply filter value to an Array of objects. Each object in the Array has fields. I'm trying to filter these objects by field values. Each field can be filtered by multiple values.
At this time, I have been unsuccessful in figuring out how to do this filtering. I've tried using JavaScript's baked-in filter function. However, that always returned an empty result set for me. I've put together this Fiddle, which includes this code:
new Vue({
el: '#app',
data: {
currentFilterProperty: '',
currentFilterValue: '',
cols: [
{ title: 'Name', prop:'name' },
{ title: 'Age', prop:'age' },
{ title: 'Birthday', prop:'birthday' },
],
dataFilters: [],
data: [
{ name:'Patricia Miller', age:69, birthday:'04-15-1948' },
{ name:'Bill Baggett', age:62, birthday:'05-07-1955' },
{ name:'Maxine Thies', age:21, birthday:'11-28-1995' },
{ name:'Alison Battle', age:65, birthday:'08-07-1952' },
{ name:'Dick Triplett', age:25, birthday:'08-27-1982' }
]
},
methods: {
addFilter: function() {
var f = this.dataFilters[this.currentFilterProperty];
if (!f) {
this.dataFilters = {};
this.dataFilters[this.currentFilterProperty] = [ this.currentFilterValue ];
} else {
this.dataFilters[this.currentFilterProperty].push(this.currentFilterValue);
}
// How to apply filter?
}
}
})
I'm not sure how to apply the filters to the data object.
Complete solution. Best test: add filter Age 62, then Birthday 04-15-1948, then 'tri' in Name Patricia.
new Vue({
el: '#app',
data: {
filteredProperty: 'name',
query: '',
activeFilters: [],
data: [
{name: 'Patricia Miller', age: 62, birthday: '04-15-1948'},
{name: 'Bill Baggett', age:62, birthday: '04-15-1948' },
{name:'Maxine Thies', age:62, birthday:'11-28-1948'},
{name:'Alison Battle', age:65, birthday:'08-07-1952'},
{name:'Dick Triplett', age:25, birthday:'08-27-1982'}
]
},
computed: {
filtered () {
var filtered = this.data
this.activeFilters.forEach(filter => {
filtered = filtered.filter(record => {
return filter.name === 'name'
? new RegExp(filter.value, 'i').test(record[filter.name])
: record[filter.name] == filter.value
})
})
return filtered
}
},
methods: {
addFilter () {
this.activeFilters.push({
name: this.filteredProperty,
value: this.query
})
this.query = ''
},
removeFilter (idx) {
this.activeFilters.splice(idx, 1)
}
}
})
<div id="app">
<div>
<select v-model="filteredProperty">
<option value="name">Name</option>
<option value="age">Age</option>
<option value="birthday">Birthdate</option>
</select>
<input placeholder="filter value" v-model="query">
<button #click="addFilter">add filter</button>
</div>
<hr>
<table v-if="activeFilters.length">
<tr style="width: 100px">
<th colspan="3">Filters in use:</th>
</tr>
<tr v-for="(filter, index) in activeFilters" :key="index">
<td>{{ _.capitalize(filter.name) }}:</td>
<td>{{ filter.value }}</td>
<td style="padding-left: 10px;">
<a href="#" #click.prevented=removeFilter(index)>
remove
</a>
</td>
</tr>
</table>
<hr v-if="activeFilters.length">
<table>
<tbody>
<tr v-for="(record, index) in filtered" :key="index">
<td style="padding-right:18px;">{{ record.name }}</td>
<td style="padding-right:18px;">{{ record.age }}</td>
<td>{{ record.birthday }}</td>
</tr>
</tbody>
</table>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/lodash"></script>
Take a look the below code. Change your method to a computed property and then the filter can happen automatically without pressing a button. The fiddle always filters by Name so you'll need to make a few adjustments to work for all filter criteria, but it should get you moving in the correct direction.
new Vue({
el: '#app',
data: {
currentFilterProperty: '',
currentFilterValue: '',
cols: [
{ title: 'Name', prop:'name' },
{ title: 'Age', prop:'age' },
{ title: 'Birthday', prop:'birthday' }
],
data: [
{ name:'Patricia Miller', age:69, birthday:'04-15-1948' },
{ name:'Bill Baggett', age:62, birthday:'05-07-1955' },
{ name:'Maxine Thies', age:21, birthday:'11-28-1995' },
{ name:'Alison Battle', age:65, birthday:'08-07-1952' },
{ name:'Dick Triplett', age:25, birthday:'08-27-1982' }
]
},
computed:{
filteredData(){
var self = this;
// Add condition for currentFilterProperty == 'Name'
if(this.currentFilterValue != undefined && this.currentFilterValue != ''){
return this.data.filter(function(d){
//alert(d.name + " " + this.currentFilterValue);
return d.name.indexOf(self.currentFilterValue) != -1;
});
}
// else if(currentFilterProperty == 'Date'){
// return this.data.filter(function(d){
//return d.birthday.indexOf(self.currentFilterValue) != -1;
// });
else{
return this.data;
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.4/vue.min.js"></script>
<div id="app">
<div>
<select v-model="currentFilterProperty">
<option v-for="c in cols" :value="c.prop">{{c.title}}</option>
</select>
<input placeholder="filter value" v-model="currentFilterValue" />
</div>
<hr />
<table>
<tbody>
<tr v-for="(record, index) in filteredData">
<td style="padding-right:18px;">{{ record.name }}</td>
<td style="padding-right:18px;">{{ record.age }}</td>
<td>{{ record.birthday }}</td>
</tr>
</tbody>
</table>
</div>
Here is working solution By checking captaining condition
new Vue({
el: '#app',
data: {
currentFilterProperty: 'name',
currentFilterValue: '',
filteredData:[],
cols: [
{ title: 'Name', prop:'name' },
{ title: 'Age', prop:'age' },
{ title: 'Birthday', prop:'birthday' },
],
dataFilters: [],
addFilters:[],
data: [
{ name:'Patricia Miller', age:69, birthday:'04-15-1948' },
{ name:'Bill Baggett', age:62, birthday:'05-07-1955' },
{ name:'Maxine Thies', age:21, birthday:'11-28-1995' },
{ name:'Alison Battle', age:65, birthday:'08-07-1952' },
{ name:'Dick Triplett', age:25, birthday:'08-27-1982' }
]
},
methods: {
addFilter: function() {
if(!this.currentFilterValue){
return false;
}
var obj = {};
this.addFilters.push({name:this.currentFilterProperty,value:this.currentFilterValue});
this.currentFilterValue = "";
var vm = this;
this.dataFilters = this.data
//var temp = [];
for(var i in vm.addFilters){
this.dataFilters = this.dataFilters.filter(function(a,b){
return ((a[vm.addFilters[i].name]).toString().toLowerCase()).indexOf((vm.addFilters[i].value).toString().toLowerCase()) !== -1;
});
}
// How to apply filter?
}
},
mounted(){
this.dataFilters = this.data;
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div>
<select v-model="currentFilterProperty">
<option value="name">Name</option>
<option value="age">Age</option>
<option value="birthday">Birthdate</option>
</select>
<input placeholder="filter value" v-model="currentFilterValue" />
<button v-on:click="addFilter">
add filter
</button>
</div>
<div v-for="(filter,index) in addFilters">{{filter.name}} : {{filter.value}}</div>
<hr />
<table>
<tbody>
<tr v-for="(record, index) in dataFilters">
<td style="padding-right:18px;">{{ record.name }}</td>
<td style="padding-right:18px;">{{ record.age }}</td>
<td>{{ record.birthday }}</td>
</tr>
</tbody>
</table>
</div>

Categories