Angular *ngFor to generate table 4 cells wide - html

I have an array in a component file that will by dynamically updated based on a database query. I need this array to be populating the contents of a table like this:
For an array of 7 items:
---------------------------------------------
| array[0] | array[1] | array[2] | array[3] |
---------------------------------------------
| array[4] | array[5] | array[6] |
----------------------------------
I have this method so far:
HTML:
<table>
<ng-container *ngFor="let employer of businessAdmins">
<tr>
<div class="card shadow m-2" style="height:25vh;width:18.75vh;border-radius:5%;overflow:hidden;">
<div class="ml-1"><div style="font-weight:bold">Name: </div>{{employer.data().first_name + " " + employer.data().last_name}}</div>
</div>
</tr>
</ng-container>
</table>
This works fine in producing a list of cells however I do not know how to populate them horizontally until there are 4 horizontal cells and then move on to the next line.

It is very simple with CSS flex box. Try this code -
HTML
<div class="table">
<ng-container *ngFor="let employer of businessAdmins">
<div class="card shadow">
<div style="font-weight:bold">
Name: {{employer.data().first_name + " " + employer.data().last_name}}
</div>
</div>
</ng-container>
</div>
CSS
.table {
display: flex;
flex-wrap: wrap;
width: 100%;
.card {
flex: 1 0 25%;
}
}
Result-

You can do something like this (manually) as I was not able to find the "step" in *ngFor so far (I've simplified your employer as simple string).
I don't like it as it's not using any advantage of the framework and we are scanning the list/array even if we don't need every element (performance issue).
<table>
<ng-container *ngFor="let employer of businessAdmins; let i = index">
<tr *ngIf="i % 4 == 0">
<td> {{ businessAdmins[i] }} </td>
<td *ngIf="businessAdmins[i+1]"> {{ businessAdmins[i+1] }} </td>
<td *ngIf="businessAdmins[i+2]"> {{ businessAdmins[i+2] }} </td>
<td *ngIf="businessAdmins[i+3]"> {{ businessAdmins[i+3] }} </td>
</tr>
</ng-container>
</table>

You can acheive it with flex box.
flexbox
td {
width: 20%;
background-color: aqua;
border: 1px solid black;
}
tr {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
height: 100%;
}
table {
width: 40vw;
margin: 30px
}
<table>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
</table>

Related

Group several table columns and overflow to left

I want to display a kind of competitions results table. Each row has a participant name, followed by several cells representing participant results in last competitions (say, the competitions take place once per week). Something like this:
User name Aug 1 Aug 8 Aug 15
John Doe 1 10 100
Jane Doe 100 10 1
The table may become very wide if many columns are present. In such a case, I want the oldest columns to be hidden, so that only a few most recent are visible, and the table does not overflow the available space. The user name columns should always be visible.
The "borderline" cells can be "cut" like this:
User name g 1 Aug 8 Aug 15
John Doe 1 10 100
Jane Doe 00 10 1
...or they can be completely invisible, both variants are acceptable to me.
It is possible to achieve this with pure css?
For just one line, I've achieved it without a table, using display: flex together with direction: rtl for the 'columns' only:
https://jsfiddle.net/fo2Ldk3n/
.outer {
width: 350px;
display: flex;
justify-content: flex-right;
border: 1px solid black;
}
.header {
white-space: nowrap;
margin-right: 10px;
}
.line-box {
direction: rtl;
overflow: hidden;
white-space: nowrap;
}
.line {
padding-right: 10px;
display: inline;
white-space: nowrap;
}
<div class="outer">
<div class="header">
User Name
</div>
<div class="line-box">
<div class="line">
2223 +1
</div>
<div class="line">
10
</div>
<div class="line">
100
</div>
<div class="line">
1
</div>
<div class="line">
10
</div>
<div class="line">
100
</div>
<div class="line">
1
</div>
<div class="line">
10
</div>
<div class="line">
100
</div>
<div class="line">
1
</div>
</div>
</div>
However, this obviously fails for several rows, because the numbers will not be aligned into columns:
I've tried to use colgroup and set display: rtl etc. for the results col, but it would not work.
Also note that direction: rtl results in wrong order of 'words' within a cell (see 1+ 2223, which should be 2223 +1). The latter is not really a big problem, as I will mostly have only numbers in the cells, so it's ok if the solution has this problem. But it'll be better if it does not.
I've got it. The key is to use table wrapped into div with direction: rtl, this gives cells going from right to left and overflowing to the left. And use position: absolute for user names.
An additional direction: ltr on td even makes cell content render in correct direction.
.outer {
width: 300px;
border: 1px solid black;
position: relative;
direction: rtl;
overflow: hidden;
}
.table {
white-space: nowrap;
}
.row td {
direction: ltr;
}
.header {
position: absolute;
left: 0;
background: white;
padding-right: 10px;
}
<div class="outer">
<table class="table">
<tr class="row">
<td>1 + 100</td>
<td>100</td>
<td>1000</td>
<td>1</td>
<td>10</td>
<td>100</td>
<td>1000</td>
<td>1</td>
<td>100</td>
<td>1000</td>
<td>1</td>
<td>10</td>
<td>100</td>
<td>1000</td>
<td>1</td>
<td>10</td>
<td>100</td>
<td>1000</td>
<td class="header">User name</td>
</tr>
<tr class="row">
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>10</td>
<td>100</td>
<td>1000</td>
<td>1</td>
<td>100</td>
<td>1000</td>
<td>1</td>
<td>10</td>
<td>100</td>
<td>1000</td>
<td>1</td>
<td>10</td>
<td>100</td>
<td>1000</td>
<td class="header">Long long user name</td>
</tr>
</table>
</div>
The user name cells have different widths, but this seems to me.

HTML table; How to format content within 2nd column to align all - except first element - to right and stretch 1st element to fill remaining width

want to display the following:
where the "..." button in the first row (Web Project) is completely right-aligned to the red line (with a little padding to it)
where the Input field in the 2nd row (Root Namespace) is filling up the space to the right until the red line (with a little padding to it)
where the 2 buttons in the 3rd row (Connection String) are completely right-aligned to the red line (with a liddle padding to it).
I have tried the following but it does not do it correctly - and it only works with a certain width - If I increase or decrease the width, things are getting ugly:
decreasing the width:
My current HTML looks like this:
<div id = "ProjectSelector" width = 100%>
<table width = "100%" style = "padding-bottom: 10px;">
<tr>
<td style="white-space: nowrap; width: 140px;">Web Project (.csproj)</td>
<td style="width: 99%;" ><input id = "webproj" style="width: 97%"/><button id="webproj_browse">...</button></td>
</tr>
<tr>
<td>Root Namespace</td>
<td style="width: 99%;"><input id = "rootnamespace" style="width: 99%"/></td>
</tr>
<tr>
<td>Connection String</td>
<td style="width: 99%;"><select id = "connectionstring" style = "width: 87%"></select><button id="newConnection">New Connection</button><button id="connstringDelete">Delete</button></td>
</tr>
</table>
</div>
Question: How to format the table and the content of 2nd column to accomplish this properly?
the title of your question describes a typical flex behavior. You may use inside your table a flex container :
.flex {
display: flex;
}
.flex-1 {
flex-grow: 1;
}
<div id="ProjectSelector" width=1 00%>
<table width="100%" style="padding-bottom: 10px;">
<tr>
<td style="white-space: nowrap; width:0;">Web Project (.csproj)</td>
<td>
<div class="flex"><input id="webproj" class="flex-1" /><button id="webproj_browse">...</button></div>
</td>
</tr>
<tr>
<td>Root Namespace</td>
<td>
<div class="flex"><input id="rootnamespace" class="flex-1" /></div>
</td>
</tr>
<tr>
<td>Connection String</td>
<td>
<div class="flex">
<select id="connectionstring" class="flex-1"></select><button id="newConnection">New Connection</button><button id="connstringDelete">Delete</button></div>
</td>
</tr>
</table>
</div>
It can also be build with grid or flex without a table.
For infos & demo , an example mixing grid and flex, i would probably not use this HTML structure H + P at first :
* {
margin: 0;
}
.flex {
display: flex;
}
.flex-1 {
flex-grow: 1;
}
#ProjectSelector {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 0.25em;
;
}
p {
grid-column: 2;
}
<div id="ProjectSelector">
<h4>Web Project (.csproj)</h4>
<!-- title that matches your structure or else can be plain text -->
<p class="flex"><input id="webproj" class="flex-1" /><button id="webproj_browse">...</button></p>
<h4>Root Namespace</h4>
<p class="flex"><input id="rootnamespace" class="flex-1" /></p>
<h4>Connection String</h4>
<p class="flex">
<select id="connectionstring" class="flex-1"></select><button id="newConnection">New Connection</button><button id="connstringDelete">Delete</button></p>
</div>

How to get only one column of a table to wrap

I have a 5 column table, where the 5th column contains the "add to cart" button. When shrinking down to mobile, the 5th column gets cut off. How can I make only that 5th column end up underneath? Code below
<td class="align-product-header text-medium">{{ fulfillmentOption.quantity | number: '2.'}} </td>
<td class="align-product-header text-blue text-medium">{{ computeShipDate(fulfillmentOption) }}</td>
<td class="align-product-header">{{fulfillmentOption.pricePerUnit | currency:'USD':true:'1.4-4' }}</td>
<td class="align-product-header text-green text-medium">{{ fulfillmentOption.totalPrice | currency:'USD' }}</td>
<td class="align-product-header" style="width: 150px">
<button class="btn btn-primary btn-block btn-sm m-0 bg-warning" data-toast data-toast-type="success" (click)="addPartToCart(fulfillmentOption)">Add to Cart</button>
</td>```
You may reset the table-display of that last td.
If you have more than one row, then tr display is to be reset too :
example
tr {
/* if more than one tr involved */
display: table;
margin-bottom: 2px;
}
tr td:last-child {
display: table-caption;
caption-side: bottom;
width: 100%;
}
/* demo styling , use yours */
table,
tr {
width: 100%;
border-collapse: collapse
}
td {
border: solid 1px;
text-align: center;
background: lightblue;
}
tr td:last-child {
background: lightgreen;
}
* {
box-sizing: border-box;
margin:0;
}
<table><!--td html attributes remove for clarity -->
<tr>
<td> fulfillmentOption.quantity </td>
<td>computeShipDate</td>
<td>fulfillmentOption.pricePerUnit </td>
<td> fulfillmentOption.totalPrice </td>
<td>
<button>Add to Cart</button>
</td>
</tr>
<tr>
<td> fulfillmentOption.quantity </td>
<td>computeShipDate</td>
<td>fulfillmentOption.pricePerUnit </td>
<td> fulfillmentOption.totalPrice </td>
<td>
<button>Add to Cart</button>
</td>
</tr>
</table>
You may use mediaquery to trigger this any time you which to switch layout.

How can I highlight on mouse click selected row of the table using Bootstrap 4 and Angular 6?

I have a Bootstrap table using table-hover and everything works properly .table-hover enables a hover state on table rows within a <tbody>. I also have this method:
listClick(event, newValue) {
this.UploaderService.getFileName(newValue[1])
}
which sets name of the file from the specified row and then other methods from
UploaderService uses this variable to execute specified operations like deleting, uploading etc.
My problem is that everything works fine, unfortunately the line being clicked is not highlighted so the user is not completely aware of the selected row. I would like to leave this line highlighted at the moment of clicking a specific action on this object, such as deleting etc.
Furthermore I would like to have a possibility to select multiple rows using combination for instance of mouse clicking + cmd in case of mac os. Any ideas how can I do this?
<div style="display: block;" class="table-div content table-responsive table-full-width" >
<table class="Table table table-hover">
<div>
<thead >
<tr >
<th style="width: 20vw; min-width: 150px; text-align: left " *ngFor="let cell of this.UploaderService.tableData2.headerRow">{{ cell }}</th>
</tr>
</thead>
</div>
<tbody style=" overflow:auto; height:60vh; margin-bottom:1vh; display: block; left: 0vw; right: 0vw">
<tr *ngFor="let item of this.UploaderService.uploader.queue">
<td><button type="button" (click)="item.remove()">Cancel</button>
<div class="progress">
<div class="progress-bar bg-success"
[ngStyle]="{'width':item.progress+'%'}"></div>
</div>
</td>
<td>
<div >{{item.file.name}}</div>
</td>
<td>
<div >{{item.file.size}}</div>
</td>
<td>
<div >{{item.file.type}}</div>
</td>
<td>
<div >{{item.file.lastModifiedDate}}</div>
</td>
<tr *ngFor="let row of this.UploaderService.tableData2.dataRows">
<td [ngClass]="{'active': selectedItem == cell}" (click)="listClick($event, row)" (dblclick)="listDoubleClick($event, row)" style="cursor: pointer; width: 20vw; min-width: 150px; text-align: left" *ngFor="let cell of dateFormat(row)">{{cell}}</td>
</tr>
</tbody>
</table>
</div>
I try like this:
ts:
listClick(event, row) {
row.isSelected = !row.isSelected;
this.UploaderService.getFileName(row[1])
}
html:
<tr *ngFor="let row of this.UploaderService.tableData2.dataRows">
<td [ngClass]="{'active': row.isSelected}" (click)="listClick($event, row)" (dblclick)="listDoubleClick($event, row)" style="cursor: pointer; width: 20vw; min-width: 150px; text-align: left" *ngFor="let cell of dateFormat(row)">{{cell}}</td>
</tr>
A simple way is just to add one attribute like:
isSelected: boolean to you dataRows when one or more of them is selected;
listClick(event, newValue, cell) {
cell.isSelected = !cell.isSelected;
this.UploaderService.getFileName(newValue[1])
}
but i highly recommend you to use this excellent data table in angular
ngxDataTable
hope it help.
In bootstrap 5 you need to use bootstrap class "table-active".
html:
<tr [class.table-active]="i == currentRowIndex" *ngFor="let row of this.UploaderService.tableData2.dataRows; let i = index" (click)="onRowClick(i)">
ts:
currentRowIndex: number = -1;
onRowClick(index: number) {
this.currentRowIndex = index;
}

Ionic 2 : how to seperate two tables side by side

I m trying to align two tables side by side.It is coming but its combining both tables as below.How to seperate two tables
.scss
when i give margin left completely moving
.tablediv {
margin-top: 2.2vw;
float: left;
margin-left: 0vw;
overflow:auto;
}
.html
<div *ngFor="let Table of Global_TablePerCard[TablePerCardIndexCounter]">
<div class="tablediv">
<table class="tablesalign">
<thead class="tableheader">
<div *ngFor = "let Param of Table; let j=index">
<div *ngIf = "j == 0; else elsetag">
<th class="col" *ngFor="let value of Param">
{{value}}
</th>
</div>
<div>
<ng-template #elsetag>
<tr>
<td *ngFor="let value of Param">
{{value}}
</td>
</tr>
</ng-template>
</div>
</div>
</thead>
</table>
</div>
</div>
It's working fine with padding.
padding: 2px 4px 2px 4px;