How to create table as generic component in Angular 2? - javascript

I have this table below. This kind of table can be found anywhere in my project, with different number of columns, with-or-without header column. That's why I would like to create a generic component, more simple, and have his own CSS.
<table class="table">
<thead>
<tr>
<th style="width: 100px"></th>
<th> {{ 'nameColumn_result_name' | translate }} </th>
<th> {{ 'nameColumn_result_date' | translate }}
</tr>
</thead>
<tbody #lines>
<tr #lineSelected *ngFor="let result of results"
(click)="appendLine($event, lineSelected, result)"
(contextmenu)="multipleSelection($event)">
<td (click)="selectUnitaryLine($event, result)" class="arrowDown"></td>
<td>{{result.name}}</td>
<td>{{result.date}}</td>
</tr>
<tr *ngIf="result && result .length == 0" >
<td colspan="10" class="text-center">{{ 'no_result _found' | translate }}</td>
</tr>
</tbody>
</table>
I would like something like this :
<CustomTable [data]="results" (click)="appendLine($event, lineSelected, result)" (contextmenu)="multipleSelection($event)">
<CustomTableColumn style="width: 100px" (click)="selectUnitaryLine($event, result)"></CustomTableColumn>
<CustomTableColumn [data]="name"> {{ 'nameColumn_result_name' | translate }} </CustomTableColumn>
<CustomTableColumn [data]="date"> {{ 'nameColumn_result_date' | translate }}</CustomTableColumn>
</CustomTable>
The idea is that CustomTable generate table, thead, tbody and tr and CustomTableColumn generate td. The events (click) are not generic. It can be add by the page which use this table.
So I create my component:
customtable.component.ts
#Component({
selector: 'CustomTable',
templateUrl: './customtable.component.html',
styleUrls: ['./customtable.component.css']
})
(...)
I don't know how to do that?
Can you help me please?
Thanks

Related

How could I use ngFor to design this (maybe nested) table

I have an Object Array that has a key and then has an array for it's value. Something like this:
[
{key: 'example#example.com', value: ['message1', 'message2']}
]
I previously had this working using an object like this
[
{key: 'example#example.com', value: 'message'}
]
but I would like to change the functionality some so I switched to the value being an array instead.
I want to create a table that looks something like this
| User Email | Result |
| example#example.com | message1 |
| | message2 |
| example1#example.com | message1 |
| | message2 |
It can be a nested table or it can just show the two messages in the table cell. I am not too picky.
I tried nesting the table, but that did not work. I am not sure how I can use a second ngFor to do something like this.
This is my html that works with the Object Array that does not have an array for its value
<div class="container" style="text-align:center">
<br />
<h1>Results</h1>
<head>
<style>
table,
th,
td {
border: 1px solid black;
align: center;
}
</style>
</head>
<body>
<table style="width:50%" align="center">
<tr>
<th *ngFor="let col of displayedColumns">
{{ col }}
</th>
</tr>
<tr *ngFor="let item of userResults | keyvalue">
<td>{{ item.key }}</td>
<td>{{ item.value }}</td>
</tr>
<tr></tr>
</table>
</body>
I tried changing the item.value line with another table and another ngFor, but nothing printed.
any ideas would be appreciated
You're very close; you should just need another *ngFor directive inside your second tag, like this...
<td>
<span *ngFor="let val of item.value" style="display:inline-block">
{{ item.value }}
<span>
</td>
So your final table looks like...
<div class="container" style="text-align:center">
<br />
<h1>Results</h1>
<head>
<style>
table,
th,
td {
border: 1px solid black;
align: center;
}
</style>
</head>
<body>
<table style="width:50%" align="center">
<tr>
<th *ngFor="let col of displayedColumns">
{{ col }}
</th>
</tr>
<tr *ngFor="let item of userResults | keyvalue">
<td>{{ item.key }}</td>
<td>
<span *ngFor="let val of item.value" style="display:inline-block">
{{ item.value }}
<span>
</td>
</tr>
<tr></tr>
</table>
</body>
You do not need to use the keyvalue pipe. The keyvalue pipe is used to transform an object into an array of key value pairs so using this will give you incorrect values in your table. On the other hand, you have a normal array of objects with one property that contains an array. This format is perfect for a nested ngFor.
Change your table to the code below
<table style="width:50%" align="center">
<tr>
<th *ngFor="let col of displayedColumns">
{{ col }}
</th>
</tr>
<tr *ngFor="let item of userResults">
<td>{{ item.key }}</td>
<td>
<div *ngFor="let value of item.value">
{{ value }}
</div>
</td>
</tr>
<tr>
</table>
In your css add a vertical-align to keep the data in the cell on top.
table,
th,
td {
border: 1px solid black;
align: center;
vertical-align: top;
}
Here is a working example on stackblitz
Edit: As requested in the comments, to add html content, use innerHTML on the div like below
<div *ngFor="let value of item.value" [innerHTML]="value">
</div>

Is it possible to have both orderBy and filter for the same table in AngularJS?

In my table it works fine orderBy (descending and ascending). It looks like this:
<table class="table table-striped top-scroll__content">
<thead>
<tr>
<th ng-click="$ctrl.sorting('Name')">Name</th>
<th ng-click="$ctrl.sorting('Type')">Occurence</th>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="rows in $ctrl.alertsResponse | orderBy:$ctrl.sort.active:$ctrl.sort.descending track by $index">
<td>{{rows.Name}}</td>
<td>{{rows.Type}}</td>
</tr>
</tbody>
</table>
I added a dropdown selector from whom I select a type and I want the table to show only the rows having the selected type.
The JS function works well, it returns the desired result in console and looks like this:
updateFilter(type) {
debugger;
if (type === "0") return this.alertsResponse;
return this.alertsResponse.filter(function(item) {
return item.Type === type;
});
}
My problem comes when I want to add this functionality to the table. I tried to add the filer in the same place as orderBy but probably it is not the right way:
<tr ng-repeat="rows in $ctrl.alertsResponse | orderBy:$ctrl.sort.active:$ctrl.sort.descending track by $index | filter:$ctrl.updateFilter(Type)">
Any suggestions?
No need to pass controller function in filter just pass drop down selector text in filter instead of drop down selector value
ng-model of drop down should be **type**
<tr ng-repeat="rows in $ctrl.alertsResponse | orderBy:$ctrl.sort.active:$ctrl.sort.descending track by $index | filter:Type">
OR
You can filter your data by passing object in filter like
<tr ng-repeat="rows in $ctrl.alertsResponse | orderBy:$ctrl.sort.active:$ctrl.sort.descending track by $index | filter:{Type:type}">
angular.module('myApp', []).controller('namesCtrl', function($scope) {
$scope.rows = [
{Type:1, name:'Tom'},
{Type:2, name:'Jerry'},
{Type:2, name:'Dom'},
{Type:1, name:'Apple'}
];
$scope.type = "1";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="namesCtrl">
<select ng-model="type">
<option value="1">Tom</option>
<option value="2">Jerry</option>
</select>
<table border="1" style="margin-top:20px">
<thead>
<tr>
<th >Name</th>
<th >Occurence</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="rows in rows | filter:{Type:type}">
<td>{{rows.name}}</td>
<td>{{rows.Type}}</td>
</tr>
</tbody>
</table>
</div>

Using ngx-pagination on reusable component

I am attempting to use ngx-pagination on a reusable datatable component, however the change in one table is effecting the change in other tables on the page. How can I assure pagination events are only occurring on one component at a time?
table.component.html
<table>
<thead>
<tr>
<th *ngFor="let col of cols">
<label>{{col.header}}</label>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of data | paginate: { itemsPerPage: 6,
currentPage: p }">`
<td *ngFor="let col of cols">
{{row[col.prop]}}
</td>
</tr>
</tbody>
</table>
<pagination-controls
class="my-pagination"
(pageChange)="p = $event">
</pagination-controls>
table.component.ts
#Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.css']
})
export class DataTableComponent {
#Input() data
#Input() cols
p: number = 1
}

using ngif inside the loop and toggling the table row with specific class when clicking on table row with another class in angular 2

I have a table generated from the data and there are 2 tr with class default and toggle-row when i click on tr with class default it should only toggle the corresponding tr with class toggle-row however my code toggles all the toggle-row class when clicked on any one of table row with class default. how do if fix this. i am using *ngIF to toggle the table rows.
Template file is like this
<table class="table table-container table-responsive" id = "team-members">
<thead class="table-heading">
<tr>
</tr>
</thead>
<tbody class="data-item" *ngFor = "let member of teamMember; let i = index" >
<tr id ="{{i}}" (click)="Toggle(i)" class="default">
<td *ngFor = "let hrs of member.Value.hoursLogged">
{{ hrs }}
</td>
</tr>
<ng-container *ngFor = "let subtask of member.Value.subTasks">
<tr class="toggle-row" *ngIf="toggle" >
<td>
{{ subtask.taskType }}
</td>
<td *ngFor="let hrs of subtask.subtaskHoursLogged">
{{ hrs }}
</td>
</tr>
</ng-container>
<tbody>
</table>
basically this loop creates the structure
<table>
<thead></thead>
<tbody>
<tr id="1" class="default"><tr>
<tr class="toggle-row"></tr>
<tr class="toggle-row"></tr>
<tr class="toggle-row"></tr>
</tbody>
<tbody>
<tr id="2" class="default"><tr>
<tr class="toggle-row"></tr>
<tr class="toggle-row"></tr>
<tr class="toggle-row"></tr>
</tbody>
<tbody>
<tr id="3" class="default"><tr>
<tr class="toggle-row"></tr>
<tr class="toggle-row"></tr>
<tr class="toggle-row"></tr>
</tbody>
</table>
and i want to toggle table-row class when clicked on default class only inside that tbody
and typescript file for this template is like this
import { Component, OnInit } from '#angular/core';
import { DataServiceService } from "../../services/data-service.service";
#Component({
selector: 'app-projects',
templateUrl: './projects.component.html',
styleUrls: ['./projects.component.css']
})
export class ProjectsComponent implements OnInit {
private teamMember: any[];
public toggle = false;
constructor(private dataserve: DataServiceService) { }
ngOnInit() {
this.dataserve.getTeamMemberData()
.subscribe(
(data: any) => {
var localarray= [];
for (let key in data){
localarray.push({key:key, Value:data[key]});
}
this.teamMember = localarray;
console.log(this.teamMember);
}
);
}
Toggle(value){
this.toggle = !this.toggle;
}
}
you need to move toggle variable inside member.Value.subTasks variable to make things work for each row.
As toggle is global variable, it will simply update the view for all rows.
<ng-container *ngFor = "let subtask of member.Value.subTasks">
<tr class="toggle-row" *ngIf="subtask.toggle" >
<td>
{{ subtask.taskType }}
</td>
<td *ngFor="let hrs of subtask.subtaskHoursLogged">
{{ hrs }}
</td>
</tr>
</ng-container>
you need to change Toggle(i) function to update the member.Value.subTasks variable.
Hope it helps!.

Can you populate a table with Angular.js without hardcoding column names?

I have a simple Angular.js application that grabs tabular data from a mysql database and shows it in a simple bootstrap table. I’m using this code below to show the table column names without hardcoding them individually…
HTML:
<table class="table">
<thead>
<tr style="background:lightgrey">
<th ng-repeat="column in columns"> {{ column }} </th>
</tr>
</thead>
and in the controller I create ’$scope.columns’ with something like this…
var columnNames = function(dat) {
var columns = Object.keys(dat[0]).filter(function(key) {
if (dat[0].hasOwnProperty(key) && typeof key == 'string') {
return key;
}
});
return columns;
};
DataFactory.getTables(function(data) {
$scope.columns = columnNames(data);
$scope.tables = data;
});
And this works as expected and it’s great, but what about the the rest of the data.. So for example, the body of my table currently looks like this…
HTML:
<tbody>
<tr ng-repeat="x in tables ">
<td> {{ x.id}} </td>
<td> {{ x.name }} </td>
<td> {{ x.email }} </td>
<td> {{ x.company }} </td>
</tbody>
I’ve tried using two loops like this…
HTML:
<tbody>
<tr ng-repeat="x in tables">
<td ng-repeat=“column in columns”> {{ x.column }} </td>
</tr>
</tbody>
But this code doesn’t work, So is it possible to populate a table with angular without hardcoding the column names in HTML, and if so whats the most efficient way to do so?
You might want to try this https://jsfiddle.net/8w2sbs6L/.
<div data-ng-app="APP">
<table ng-controller="myController" border=1>
<thead>
<tr>
<td ng-repeat="column in columns">{{column}}</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in tables">
<td ng-repeat="column in columns">{{x[column]}}</td>
</tr>
</tbody>
</table>
</div>
<script>
'use strict';
angular.module('APP', [])
.controller('myController', ['$scope', function($scope){
$scope.tables = [
{
"column1":"row1-column1",
"column2":"row1-column2",
"column3":"row1-column3",
"column4":"row1-column4"
},
{
"column1":"row2-column1",
"column2":"row2-column2",
"column3":"row2-column3",
"column4":"row2-column4"
}
];
$scope.columns = [
"column1",
"column2",
"column3",
"column4"
];
}]);
</script>

Categories

Resources