How to traverse through Dynamic Object of Arrays in VueJS - vue.js

I have an object with arrays which is nothing but JSON reply from server which I converted into Object and now it looks like this (but lot of values into it):-
Object_return:{
name:[1,25,2,24,3,78],
age:[2,34,4,78]
}
here name and age is dynamic coming from the server, so I do not know what exact values coming there so I can not refer it while iterating through the for loop
<th v-for = "item in Object_return.name">
and also I want to show this in a DataTable so the first row should looks like this
------------------
1 25
-------
name 2 24
-------
3 78
--------------------
second row
---------------------
2 34
-------
age 4 78
------------------------
and so on and so forth for all the values coming from the server
Does someone have an idea how to do this

You can iterate over an object and get the key value as the second argument.
<tr v-for="val, key in Object_return">
Here, key will be the name of the property.
Then, since you want to group the arrays in pairs, I suggest a computed property to massage the data into the format you want.
Here is a working example.
console.clear()
new Vue({
el: "#app",
data:{
serverData: {
name:[1,25,2,24,3,78],
age:[2,34,4,78]
}
},
computed:{
massaged(){
return Object.keys(this.serverData).reduce((acc, val) => {
// split each array into pairs
const copy = [...this.serverData[val]]
let pairs = []
while (copy.length > 0)
pairs.push(copy.splice(0, 2))
// add the paired array to the return object
acc[val] = pairs
return acc
}, {})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<table>
<tr v-for="val, key in massaged">
<td>{{key}}</td>
<td>
<table>
<tr v-for="pair in val">
<td>{{pair[0]}}</td>
<td>{{pair[1]}}</td>
</tr>
</table>
</td>
</tr>
</table>
</div>

Related

how to apply filter on JQuery DataTable each columns? [duplicate]

I'm trying to filter table rows in an intelligent way (as opposed to just tons of code that get the job done eventually) but a rather dry of inspiration.
I have 5 columns in my table. At the top of each there is either a dropdown or a textbox with which the user may filter the table data (basically hide the rows that don't apply)
There are plenty of table filtering plugins for jQuery but none that work quite like this, and thats the complicated part :|
Here is a basic filter example http://jsfiddle.net/urf6P/3/
It uses the jquery selector :contains('some text') and :not(:contains('some text')) to decide if each row should be shown or hidden. This might get you going in a direction.
EDITED to include the HTML and javascript from the jsfiddle:
$(function() {
$('#filter1').change(function() {
$("#table td.col1:contains('" + $(this).val() + "')").parent().show();
$("#table td.col1:not(:contains('" + $(this).val() + "'))").parent().hide();
});
});
Slightly enhancing the accepted solution posted by Jeff Treuting, filtering capability can be extended to make it case insensitive. I take no credit for the original solution or even the enhancement. The idea of enhancement was lifted from a solution posted on a different SO post offered by Highway of Life.
Here it goes:
// Define a custom selector icontains instead of overriding the existing expression contains
// A global js asset file will be a good place to put this code
$.expr[':'].icontains = function(a, i, m) {
return $(a).text().toUpperCase()
.indexOf(m[3].toUpperCase()) >= 0;
};
// Now perform the filtering as suggested by #jeff
$(function() {
$('#filter1').on('keyup', function() { // changed 'change' event to 'keyup'. Add a delay if you prefer
$("#table td.col1:icontains('" + $(this).val() + "')").parent().show(); // Use our new selector icontains
$("#table td.col1:not(:icontains('" + $(this).val() + "'))").parent().hide(); // Use our new selector icontains
});
});
This may not be the best way to do it, and I'm not sure about the performance, but an option would be to tag each column (in each row) with an id starting with a column identifier and then a unique number like a record identifier.
For example, if you had a column Produce Name, and the record ID was 763, I would do something like the following:
​​<table id="table1">
<thead>
<tr>
<th>Artist</th>
<th>Album</th>
<th>Genre</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td id="artist-127">Red Hot Chili Peppers</td>
<td id="album-195">Californication</td>
<td id="genre-1">Rock</td>
<td id="price-195">$8.99</td>
</tr>
<tr>
<td id="artist-59">Santana</td>
<td id="album-198">Santana Live</td>
<td id="genre-1">Rock</td>
<td id="price-198">$8.99</td>
</tr>
<tr>
<td id="artist-120">Pink Floyd</td>
<td id="album-183">Dark Side Of The Moon</td>
<td id="genre-1">Rock</td>
<td id="price-183">$8.99</td>
</tr>
</tbody>
</table>
You could then use jQuery to filter based on the start of the id.
For example, if you wanted to filter by the Artist column:
var regex = /Hot/;
$('#table1').find('tbody').find('[id^=artist]').each(function() {
if (!regex.test(this.innerHTML)) {
this.parentNode.style.backgroundColor = '#ff0000';
}
});
You can filter specific column by just adding children[column number] to JQuery filter. Normally, JQuery looks for the keyword from all the columns in every row. If we wanted to filter only ColumnB on below table, we need to add childern[1] to filter as in the script below. IndexOf value -1 means search couldn't match. Anything above -1 will make the whole row visible.
ColumnA | ColumnB | ColumnC
John Doe 1968
Jane Doe 1975
Mike Nike 1990
$("#myInput").on("change", function () {
var value = $(this).val().toLowerCase();
$("#myTable tbody tr").filter(function () {
$(this).toggle($(this.children[1]).text().toLowerCase().indexOf(value) > -1)
});
});
step:1 write the following in .html file
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
</table>
step:2 write the following in .js file
function myFunction() {
// Declare variables
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}

calculate 2d array with reduce in vuejs

In Vue, I'm inserting a value in a 2d array input field and calculating it per row, but the total value that is being returned only calculates the first row, and when I display, the computed value is all the same.
How can i calculate the inputted value so that the value will compute it per row and not just the first value?
This is what i get:
sample image of the value
FIDDLE:jsfiddle
NAME | VALUE1 | VALUE2 | TOTAL
name1 | 1 | 1 | 2
name2 | 2 | 3 | 2
name3 | | | 2
script
data() {
return {
form: new Form({
labStudentScores: [],
})
};
},
computed: {
studentTotalScore: function() {
return this.form.labStudentScores.reduce(
(acc, item) => acc + parseInt(item.value),
0
);
},
methods: {
addScore: function() {
this.form.labStudentScores.push({ value: [] });
}
}
Template
<button type="button" #click="addScore">score(+)</button>
//classlists is comming from http request
<tr v-for="(classlist,index) in classlists" :key="'lab'+ classlist.id">
<td>{{index +1}}</td>
<td>
{{classlist.student}}
</td>
<td v-for="(labStudentScore,i) in form.labStudentScores" :key="i">
<input v-model="labStudentScore.value[index]" />
</td>
<td>{{studentTotalScore}}</td>
</tr>
Your computed variable is really only one number studentTotalScore. Since you want a number for each row, this computed value should be an array studentTotalScores. Each row should have its own index.
this.form.labStudentScores[index].push(value);
And in your template you should also refer to the correct row too for calulation.
{{studentTotalScore[index]}}
Of course your compute function should also only compute values of the related row.

How to hide a column in dynamic Material table in Angular 6?

I have the following dynamic Angular material 6 tables.
<table mat-table [dataSource]="animalDataSource" matSort *ngIf="animal && animal.length > 0">
<ng-container *ngFor="let disCol of animalColumns;" matColumnDef="{{disCol}}">
<th mat-header-cell *matHeaderCellDef mat-sort-header >{{disCol}}</th>
<td mat-cell *matCellDef="let rowValue;">{{rowValue[disCol]}}
<button *ngIf="disCol == 'Action'" mat-mini-fab class="delete-icon" (click)="deleteAnimalData(rowValue)">
<mat-icon>delete</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="animalColumns"></tr>
<tr mat-row *matRowDef="let rowdata; columns: animalColumns;"></tr>
</table>
And here's my script:
this.animals = [];
this.animalColumns = [];
for (var i in animalList) {
this.animal = {
"Id": animalList[i]["_id"],
"Animal": animalList[i].name,
"Created By": animalList[i].createdBy,
"Created On": new Date(animalList[i].dateOfEntry)
}
this.animals.push(this.animal);
}
this.animalDataSource = new MatTableDataSource(this.animals);
for (let displayColName in this.animals[0]) {
this.animalColumns.push(displayColName);
}
this.animalColumns.push("Action");
There are 4 columns in the table. And I don't need the 'Id' column to be displayed in the table. I have tried giving *ngIf and [style.display]='none'. Both are hiding the column with the full-length gap between the columns.
I could have removed the 'Id' field from the object, but I need the value of the 'Id' column when the user clicks on the delete button[method: deleteAnimalData(rowValue)].
Please suggest me, without removing the 'ID' key from the object, how I can hide the column.
The way I was able to make it work is by having an array of objects(say animalObjects) that define all the table columns building the template.
Once they are all defined I have another array that has the name of the columns (animalColumns) to be displayed.
When you need to hide a column then you can remove the item from the 2nd array (animalColumns) while leaving the first (animalObjects) untouched.
You basically have to create the table with all the columns, then update the displaycolumn property with the modified animalColumn array.
stackblitz example here
Just do NOT add the ID to animalColumns, as this array is what defines your columns. See columns: animalColumns in your HTML

Accessing $index of outer v-repeat directive in inner v-repeat directive

Here is the simplified example of data I am working with. fruits:['apple','orange','banana'] which is dynamic. The number and types of fruits are not same always.
I have another list seasons:['summer','winter'] which is also dynamic. The number and type of seasons are also not same always.
I need to generate a table. The table has one row for each of the fruit. There will be one column for each season in the table.
For the values of seasons columns I have another object like this:
available: {
summer: ['yes', 'no', 'yes'],
winter: ['yes', 'no', 'no']
}
After the table is generated it would look like this:
Fruits Summer Winter
Apple yes yes
orange no no
Banana yes no
To render this in vue I am using this:
<tr v-repeat="fruit: fruits">
<td v-text="fruit"></td>
<td v-repeat="season: seasons" v-text="available[season][$index]"></td>
</tr>
The problem here is $index gives the index of seasons object. But I need to access the index of fruits object.
How can I access index of fruits object inside inner v-repeat?
I don't know if it's possible to access the fruit $index inside the inner v-repeat, but you could try something like this:
<table>
<tr>
<th>Fruits</th>
<th>Summer</th>
<th>Winter</th>
</tr>
<tr v-repeat="fruit: fruits">
<td v-text="fruit"></td>
<td v-repeat="season: seasons" v-text="isAvailable(fruit, season)"></td>
</tr>
</table>
and
data: {
fruits: [
'apple', 'orange', 'banana'
],
seasons: [
'summer', 'winter'
],
available: {
summer: ['yes', 'no', 'yes'],
winter: ['yes', 'no', 'no']
}
},
methods: {
isAvailable: function (fruit, season) {
var fruitIndex = this.fruits.indexOf(fruit)
return this.available[season][fruitIndex]
}
}
http://codepen.io/pespantelis/pen/BozNWm

Srpy dataset if decision based on value from different dataset

Many thanks for reading this.
I have asked as well in Adobe forums with no luck.
I am building a small library application for school books.
I have created a database with lets say 2 tables
Books ( ID_Book , Writer , Title , Copies) and
Loans ( ID_Book , Load_ID , Loan_Date ) etc
I have used correctly spry to create easily a table which print the book list in a table
with pagination .
var ds1 = new Spry.Data.XMLDataSet("ajaxquery.php", "root/row", {sortOnLoad: "Writer", sortOrderOnLoad: "ascending"});
ds1.setColumnType("ID_Book", "number");
var pv1 = new Spry.Data.PagedView( ds1 ,{ pageSize:10 });
var pv1PagedInfo = pv1.getPagingInfo();
pv1.setColumnType("ID_Book", "number");
I have made the necessary declarations to produce the dataset for the Loans
var ds3 = new Spry.Data.XMLDataSet("ajaxallloans", "root/row", {sortOnLoad: "ID_Book", sortOrderOnLoad: "ascending"});
ds3.setColumnType("ID_Book", "number");
ds3.setColumnType("ID_Dan", "number");
I would like to find a way to change the table row color for the BOOKS table IF an ID_Book is within the Loans table - ds3.
The table is created
<div spry:region="pv1" id="bibliapv">
<div spry:state="loading" class="loading" >Loading...</div>
<div spry:state="ready">
<table>
<tr >
<th width="75" spry:sort="ID_Book"> Book No</th>
<th width="123" spry:sort="Writer">Writer </th>
etc...
</tr>
<tr spry:repeat="pv1" spry:select="mySelectClass" spry:hover="hover">
<td >{ID_Book}</td>
<td>{writer}</td>
etc ..
</tr>
</table>
</div>
</div>
<div>
Many thanks again.
Dinos - Greece
Many thanks again for reading .
I found a solution based on the ideas drawn from
labs.adobe.com/technologies/spry/samples/data_region/CustomColumnsSam ple.html
I have added the following code:
created a css rule
lets say
.match {
background-color: #0CF;
}
In spry:region add the class {cssrule} which is added dynamically shortly after <tr class="{cssrule}" spry:repeat="pv1" spry:select="mySelectClass" spry:hover="hover">
3.
Then just before closing tag added (you could put it earlier in code)
<script type="text/javascript">
ds2.addObserver({
onPostLoad:function( ds2, data ){
var data = ds2.getData();
var pv1data = pv1.getData();
for( var i = 0; i < pv1data.length; i++ )
{
for (var j =0 ; j< data.length ; j++)
{ if ((data[j].Writer).toString()== (pv1data[i].Writer).toString() ) //or whatever you like!
{pv1data[i].cssrule="match"; }
}
}
}
});
</script>