We are trying to achieve table design POC as given in following image which is having following features.
Issue is with following functionality
1) Expand and collapse behavior should be per row(Not for all rows at a time).
2) It should have value of particular row on click of any action from action-toolbar(i.e. Config, History, etc in image).
HTML
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Symbol </th>
<td mat-cell *matCellDef="let element">
<div [ngClass]="showFloatingButtons == true ? 'floating-pane-active' : 'floating-pane-deactive'"
class="button-row">
<mat-icon mat-fab *ngIf="showFloatingButtons == true" color="primary" class="floating-buttons">offline_pin
</mat-icon>
<mat-icon mat-fab *ngIf="showFloatingButtons == true" color="primary" class="floating-buttons">query_builder
</mat-icon>
<mat-icon mat-fab *ngIf="showFloatingButtons == true" color="primary" class="floating-buttons" disabled>restore
</mat-icon>
<mat-icon mat-fab *ngIf="showFloatingButtons == true" color="primary" class="floating-buttons">
play_circle_filled</mat-icon>
<mat-icon (click)="toggleFloat()" class="sky_blue">more_horiz</mat-icon>
</div>
</td>
CSS
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 50%;
}
.mat-column-position {
max-width: 100px;
min-width: 10px;
}
.mat-column-name {
max-width: 100px;
min-width: 10px;
}
.example-trigger {
display: inline-block;
}
.floating-buttons {
z-index: 2;
// position: fixed;
overflow: auto;
top: auto;
left: auto;
}
.floating-pane-active {
background-color: rgba(215, 228, 230, 0.39);
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
background-position: right;
background-repeat: repeat;
}
.floating-pane-deactive {
background-color: rgba(215, 228, 230, 0.39);
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
background-position: right;
background-repeat: repeat;
width: 30px;
}
.button-row {
align-items: center;
justify-content: space-around;
}
.action-buttons {
width: 20px;
}
.sky_blue {
color: skyblue;
}
.mat-column-symbol {
word-wrap: break-word !important;
white-space: unset !important;
flex: 0 0 10% !important;
width: 10% !important;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
text-align: right;
}
TS(putting only important line)
showFloatingButtons = false;
Collapsed column icons
Expanded column icons
FYI: I've refered this link for expandable row table.
Please find demo code here on stackblitz for more.
PS: Main problem here is to achieve expanding single row icons at a time.
Your first problem is simple, you are using the same variable to show/hide elements, so it's a natural behavior that they appear/disappear together. You have to create a table where you store the state of each row (expanded or not), for this I created this table and initialized it in ngOnInit:
expanded = [];
for(var i: number = 0; i < ELEMENT_DATA.length; i++) {
this.expanded[i] = false;
}
Then I changed your toggleFunction to change the value of that tables column instead:
toggleFloat(i:number) {
this.expanded[i] = !this.expanded[i];
}
And in the HTML i changed the *ngIf conditions to use the new table instead of the old variable:
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Symbol </th>
<td mat-cell *matCellDef="let element; let i = index">
<div [ngClass]="expanded[i] == true ? 'floating-pane-active' : 'floating-pane-deactive'"
class="button-row">
<mat-icon mat-fab *ngIf="expanded[i] == true" color="primary" class="floating-buttons">offline_pin
</mat-icon>
<mat-icon mat-fab *ngIf="expanded[i] == true" color="primary" class="floating-buttons">query_builder
</mat-icon>
<mat-icon mat-fab *ngIf="expanded[i] == true" color="primary" class="floating-buttons" disabled>restore
</mat-icon>
<mat-icon mat-fab *ngIf="expanded[i] == true" color="primary" class="floating-buttons">
play_circle_filled</mat-icon>
<mat-icon (click)="toggleFloat(i)" class="sky_blue">more_horiz</mat-icon>
</div>
</td>
</ng-container>
Here is the stackblitz, solves your first problem, I didnt really understand what's your second problem though.
For item 4 in your list, one way to approach this is to add a boolean property (which I called expand in my example) to every element itself to specify if it's expanded or not, like this...
{ id: 1, startDate: today, endDate: today, position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H', expand: false }
Then, you can access this new property in the template through the element variable (*matCellDef="let element").
But first make sure you pass the element when you your click function is called, like this...
<mat-icon (click)="toggleFloat(element)" class="sky_blue">more_horiz</mat-icon>
And change the toggleFloat function to change the element expand property of this element and not showFloatingButtons, like this...
toggleFloat(element) {
element.exapand = !element.exapand;
console.log('show:' + element.exapand);
}
With that done you can fix your template to start using element expand property instead of the component's by replacing showFloatingButtons by element.exapand in all *ngIf's for the symbol's column, like this...
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Symbol </th>
<td mat-cell *matCellDef="let element">
<div [ngClass]="element.exapand ? 'floating-pane-active' : 'floating-pane-deactive'"
class="button-row">
<mat-icon mat-fab *ngIf="element.exapand" color="primary" class="floating-buttons">offline_pin
</mat-icon>
<mat-icon mat-fab *ngIf="element.exapand" color="primary" class="floating-buttons">query_builder
</mat-icon>
<mat-icon mat-fab *ngIf="element.exapand" color="primary" class="floating-buttons" disabled>restore
</mat-icon>
<mat-icon mat-fab *ngIf="element.exapand" color="primary" class="floating-buttons">
play_circle_filled</mat-icon>
<mat-icon (click)="toggleFloat(element)" class="sky_blue">more_horiz</mat-icon>
</div>
</td>
</ng-container>
It's not clear to me what you want with the issue in item 5, but if you're going to display something specific to that element follow the same principle use for the expand functionality.
As a side note, since you are dealing with a boolean there is no need to test the equality like this *ngIf="showFloatingButtons == true", we can simply do this *ngIf="showFloatingButtons".
check the full solution here https://stackblitz.com/edit/angular-1tgnev?file=src/app/app.component.html.
Related
I created a Material Table where I give the user the option to add or remove columns. The table can also sort, arrange columns, and has a sticky actions column. I want the table to take 100% of the available width space and scroll on the table when there are too many columns instead of fitting them to the screen size. The problem that I have is when only a few columns are displayed, for some reason the first column takes a lot more space then the other columns. I've tried many things and the only solution that I've found was making the table-layout: fixed but this will break the scrolling of overflow-x: scroll which is not what the users want. Any suggestions?
<mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="drop($event)">
<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
<ng-container *ngIf="column !== 'Actions'; else action">
<th [ngClass]="{'border': hasTableBorders}" mat-header-cell cdkDrag [hidden]="column == 'Id'" *matHeaderCellDef mat-sort-header>{{ column }}</th>
<td [ngClass]="{'border': hasTableBorders}" mat-cell [hidden]="column == 'Id'" *matCellDef="let element">{{ element[column] | shorten:22 }}</td>
</ng-container>
<ng-template #action>
<th mat-header-cell *matHeaderCellDef>Actions</th>
<td mat-cell class="m-0 p-0" *matCellDef="let element">
<h3 class="btn bi bi-pencil-fill" matTooltip="Quick Edit" (click)="onQuickEdit(element.Id)" [matTooltipPosition]="'above'"></h3>
<h2 class="btn bi bi-eye-fill" matTooltip="View" (click)="onFullEdit(element.Id)" [matTooltipPosition]="'above'"></h2>
</td>
</ng-template>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr [ngClass]="{'alternate-row-colors': isAlternateRowColor}" mat-row *matRowDef="let row; columns: columnsToDisplay"></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>
</tr>
</mat-table>
css
.mat-table {
overflow-x: scroll;
width: 100%;
}
.mat-cell, .mat-header-cell {
word-wrap: initial;
display: table-cell;
padding: 0px 10px;
line-break: unset;
width: 100%;
white-space: nowrap;
overflow: hidden;
vertical-align: middle;
}
.mat-row,
.mat-header-row {
display: table-row;
}
Looks good with many columns
Bad display
I am new in Angular. this is my main table(its wireframe)
when i click on pencil icon it should look like this:
but i am not getting the output like this. i have tried this
stackblitz url: https://stackblitz.com/edit/mat-table-custom-dtb5bv?file=index.html
problem facing:
dropdown going in right side of update button
Seems like the menu is having width: 100%;. Which makes the button move to the next line. So to have both in the same row try adding the following.
.mat-cell .mat-select {
width: auto;
min-width: 100px; /*adjust accordingly*/
}
Some adjustments to CSS and HTML were necessary. Further adjustments will be necessary, but it is an initial idea.
HTML
<span *ngIf="!element.isSelected; else editPlace">
{{element.value}}
</span>
<button mat-icon-button aria-label="Toggle star" *ngIf="i!==2 && !element.isSelected"
(click)="editSetting(element)"
style="color: blue">
<mat-icon class="material-icons">edit</mat-icon>
</button>
<ng-template #editPlace>
<div class="editPlace">
<mat-select>
<mat-option *ngFor="let value of dropDownValues">
{{value.name}}
</mat-option>
</mat-select>
<button mat-raised-button color="accent" class="submit-button" *ngIf="element.isSelected" (click)="update(element)">Update</button>
</div>
</ng-template>
<ng-container *ngIf="i===2">
<mat-slide-toggle></mat-slide-toggle>
</ng-container>
CSS
.editPlace {
display: flex;
}
.editPlace > * {
margin-right: 10px;
}
.mat-select {
border: 1px solid #666666;
border-radius: 5px;
width: 10em;
}
I have an angular page with 3 components i'm trying to get to fill the entire horizontal space. Currently the parent flexbox div is not expanding to the full length, even though I have width: 100% on it. I am able to change the width using pixel values instead, however I have no idea how wide the viewport is going to be when the page is loaded. I have tried setting the margin and padding to 0, making sure the child flexdivs widths add up to 100%, etc...
Relevant html:
<div fxLayout="row" fxLayoutGap="15px" id="bottomContainer">
<div fxFlex="1 0 40%"><mat-card gdArea="chart">
<mat-card-subtitle>Messages Flagged <br>{{period}}<button mat-icon-button [matMenuTriggerFor]="menu"><mat-icon>more_vert</mat-icon></button></mat-card-subtitle>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="period = 'Week'; periodInt = 0; changeMessagesFlaggedChartPeriod('Week')">Week</button>
<button mat-menu-item (click)="period = 'Month'; periodInt = 1; changeMessagesFlaggedChartPeriod('Month')">Month</button>
<button mat-menu-item (click)="period = 'Year'; periodInt = 2; changeMessagesFlaggedChartPeriod('Year')">Year</button>
</mat-menu>
<mat-card-content gdAreas="chart | list" gdRows="auto">
<div style="display: block">
<canvas baseChart
[datasets]="this.currentMessagesFlaggedDataset"
[labels]="this.MESSAGES_FLAGGED_LABELS"
chartType="radar"
[options]="this.messagesFlaggedChartOptions"
[colors]="this.channelData.chartColors"
height="100%"
width="100%"
></canvas>
</div>
</mat-card-content>
</mat-card></div>
<div fxFlex="1 1 30%"><mat-card class="mat-elevation-z2 channelUserTableContainer">
<mat-card-subtitle>Most Negative Users</mat-card-subtitle>
<table mat-table class="channelUserTable" [dataSource]="channelData.negativeUsers">
<!-- Username column -->
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef>Username</th>
<td mat-cell *matCellDef="let element"> {{element.username}}</td>
</ng-container>
<!-- Number of flags column -->
<ng-container matColumnDef="numFlags">
<th mat-header-cell class="textAlignRight" *matHeaderCellDef>Number of Flags</th>
<td mat-cell class="textAlignRight" *matCellDef="let element"> {{element.numFlags}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="userTableColumns"></tr>
<tr mat-row *matRowDef="let row; columns: userTableColumns;"></tr>
</table>
</mat-card></div>
<div fxFlex="1 1 30%"><mat-card class="mat-elevation-z2 channelUserTableContainer">
<mat-card-subtitle>Most Positive Users</mat-card-subtitle>
<table mat-table class="channelUserTable" [dataSource]="channelData.positiveUsers">
<!-- Username column -->
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef>Username</th>
<td mat-cell *matCellDef="let element"> {{element.username}}</td>
</ng-container>
<!-- Number of flags column -->
<ng-container matColumnDef="numFlags">
<th mat-header-cell class="textAlignRight" *matHeaderCellDef>Number of Flags</th>
<td mat-cell class="textAlignRight" *matCellDef="let element"> {{element.numFlags}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="userTableColumns"></tr>
<tr mat-row *matRowDef="let row; columns: userTableColumns;"></tr>
</table>
</mat-card></div>
</div>
CSS:
padding-left: 16px;
padding-top: 16px;
}
#channelHeaderText {
font-size: x-large;
font-weight: bold;
}
.mindChartNoMargin :nth-child(1) {
margin: 0;
}
.channelUserTable {
width: 100%;
}
.channelUserTableContainer {
background-color: white;
}
.textAlignRight {
text-align: right;
}
#bottomContainer {
width: 100%;
}
Help is much appreciated
Try moving the width to the container instead, also try making the container a flexbox and the items flex too.
.channelUserTableContainer {
background-color: white;
width: 100%;
display: flex;
}
.channelUserTable {
display: flex;
}
I like to add a dotted line to understand how the flexboxes are working so you could also add a dotted border
border: dotted;
I have some checkboxes, but they are positioned next each other and not under each other.
I have this:
.mat-header-cell mat-checkbox {
padding-top: 50px;
padding-right: 1px;
padding-left: -10px;
display: block;
}
.mat-header-cell:hover mat-checkbox {
padding-top: 50px;
padding-right: 1px;
padding-left: -10px;
display: block;
}
.mat-checkbox-inner-container{
display: block;
}
And this is the html:
<div class="col-sm-12" *ngFor="let item of returnProjectCodes; let i = index">
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="selected = i"
[checked]="selelected === i"
>{{item.name}}
</mat-checkbox>
</div>
But the header 'projects' doesnt positioned correct anymore.[![enter image description here][1]][1]
<ng-container matColumnDef="projects">
<th mat-header-cell *matHeaderCellDef (mouseover)="show = true" (mouseout)="show = false" mat-sort-header i18n>
<div class="col">
<div class="row" *ngFor="let item of returnProjectCodes; let i = index">
<mat-checkbox (click)="$event.stopPropagation()" (change)="selected = i" [checked]="selelected === i"
>{{ item.name }}
</mat-checkbox>
</div>
</div>
Projects
</th>
<td mat-cell *matCellDef="let row">{{ row.projects }}</td>
</ng-container>
Not sure entirely what you are asking, but I assume it is for them to be in vertical order and not horizontal.
You can apply a CSS display as block as you are doing, however you should do it on the parent, and the col-sm-12 is probably keeping the width small so that they line up horizontally.
You can remove that and try setting the width to 100% (this probably wont be necessary, it should default to that width for a block div)
Please keep in mind the more context you can provide the better, such as a picture of what you have versus what you are going for.
I have this:
.mat-header-cell mat-checkbox {
padding-top: 1px;
padding-left: -10px;
margin-bottom: 1px;
display:table;
}
.mat-header-cell:hover mat-checkbox {
padding-top: 1px;
padding-left: -10px;
padding-bottom: 10px;
display: table;
}
And this is html:
<ng-container matColumnDef="projects">
<th mat-header-cell *matHeaderCellDef (mouseover)="show = true" (mouseout)="show = false" mat-sort-header i18n>
<div class="mat-checkbox-project">
<div class="mat-checkbox-label">
<div class="row" *ngFor="let item of returnProjectCodes; let i = index">
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="filterProjects($event, i, item)"
[checked]="selected === i"
>{{ item.name }}
</mat-checkbox>
</div>
</div>
</div>
<div class="mat-sort-header-button-project">Project</div>
</th>
<td mat-cell *matCellDef="let row">{{ row.projects }}</td>
</ng-container>
But when I hovering over the project column header the project column will jump little bit down. So that it collide with the checkboxes.
But what I want is that when you hover over the column header the layout will not change.
So how to do that?
Thank you
Since you have added margin-bottom property in hover, the style will definitely change. Either remove the hover css or remove the padding-bottom: 10px; and replace back the margin-bottom: 1px; in hover state