I am working on a project which requires me to make table using *ngFor directive of Angular. But after several failed attempts I couldn't get the table layout properly . The table cells don't match up with headings and the width of table rows is also not consistent as you can see in the pic . I'm new to Angular and also don't have much experience in debugging css. I think the problem is due to *ngFor directive. Here is the HTML and CSS code snippet. There is *ngIf condition on each td as the table should show the data in a row only when the user clicks it. I'll be very thankful for any help or guidance given.
* {
color: hsla(210, 100%, 100%, 0.9) !important;
background: hsla(210, 100%, 50%, 0.5) !important;
outline: solid 0.25rem hsla(210, 100%, 100%, 0.5) !important;
}
.border {
border: 1px solid #cecece;
}
.heading {
width: 100%;
float: left;
}
th {
background-color: #4CAF50;
color: white;
width: 100px;
}
table {
width: 100%;
}
#container {
width: 98.7%;
height: 300px;
overflow-x: scroll;
overflow-y: scroll;
position: fixed;
}
td {
width: 100px;
}
<table class="table table-bordered table-hover">
<thead class="thead-dark">
<tr>
<th class="text-center">registrationNo</th>
<!--adding heading to criterias using *ngFor -->
<div formArrayName="participants" *ngFor="let candidate of myForm.controls.participants['controls'];let i = index;">
<div [formGroupName]="i">
<div formArrayName="criteriaArray" class="d-inline-block" *ngFor="let criteria of candidate.get('criteriaArray').controls;let j = index;">
<div [formGroupName]="j">
<th *ngIf="(i === 0) && (EditRowId2 !== criteria.get('id').value)" class="text-center" style="width: 100%" (click)="Edit2(criteria.get('id').value)">{{criteria.get('criteriaName').value}}</th>
<th *ngIf="(i === 0) && (EditRowId2 === criteria.get('id').value)" class="text-center" style="width: 100%"><input type="text" formControlName="criteriaName"></th>
</div>
</div>
</div>
</div>
</tr>
</thead>
<tbody>
<tr>
<td>Maximum Marks</td>
<!--adding maximum marks row to the table using *ngFor -->
<div (click)="Edit(0)" formArrayName="participants" *ngFor="let candidate of myForm.controls.participants['controls'];let i = index;">
<div [formGroupName]="i">
<div formArrayName="criteriaArray" class="d-inline-block" *ngFor="let criteria of candidate.get('criteriaArray').controls;let j = index;">
<div [formGroupName]="j">
<td *ngIf="(i === 0) && (EditRowId2 !== criteria.get('id').value)" (click)="Edit2(criteria.get('id').value)">{{criteria.get('max_marks').value}}</td>
<td *ngIf="(EditRowId2 === criteria.get('id').value) && (i===0)"> <input type="number" formControlName="max_marks"> </td>
</div>
</div>
</div>
</div>
</tr>
<div formArrayName="participants" *ngFor="let candidate of myForm.controls.participants['controls'];let i = index;" (click)=Edit2(0)>
<div [formGroupName]="i">
<tr>
<td> {{candidate.get('registrationNo').value}} </td>
<div formArrayName="criteriaArray" class="d-inline-block" *ngFor="let criteria of candidate.get('criteriaArray').controls;let j = index;">
<div [formGroupName]="j">
<td *ngIf="EditRowId === candidate.get('id').value"> <input [class.is-invalid]="criteria.errors?.notValid" type="number" formControlName="marks" (click)="changeButtonColor(i)"> </td>
<td [class.is-invalid]="criteria.errors?.notValid" *ngIf="EditRowId !== candidate.get('id').value" (click)="Edit(candidate.get('id').value)">-----</td>
<small *ngIf="criteria.errors?.notValid" class="text-danger">Invalid marks</small>
</div>
</div>
<button *ngIf="candidate.get('dataSaveCheck').value === true" type="button" value="candidate.get('id').value" class="btn btn-primary btn-sm m-2" (click)="saveCandidateForm(candidate , i )" [disabled]='!userForm.form.valid'>save</button>
<button *ngIf="candidate.get('dataSaveCheck').value === false" type="button" value="candidate.get('id').value" class="btn btn-danger btn-sm m-2" (click)="saveCandidateForm(candidate , i )" [disabled]='!userForm.form.valid'>save</button>
</tr>
</div>
</div>
</tbody>
</table>
Related
I am building a To-Do application, and want to remove a row when I click the button.
This is my table HTML:
<table *ngFor="let todo of todos; let i = index;" class="todo {{(todo.completed ? 'done' : '')}}" >
<!-- Position Column -->
<td style="width: 10%;text-align: left;">{{i+1}}</td>
<!-- Name Column -->
<td style="width: 80%;text-align: left;" (dblclick)="toggleDone(i)">{{todos[i].content}}</td>
<!-- Weight Column -->
<td style="width: 10%;text-align: left;">
<button class="delete" mat-raised-button color="warn" (click)="deleteTodo(i)">Sil</button>
</td>
</table>
This is my deleteTodo method. I get the console message with the right index but it won't delete from the table:
deleteTodo(id:number){
this.todos=this.todos.splice(id,1);
console.log(id +"silindi");
Here are the changes you need to do:
CSS - Use classes instead of placing all the styles on the elements:
.position {
width: 10%;
text-align: left;
}
.name {
width: 80%;
text-align: left;
}
.weight {
width: 10%;
text-align: left;
}
HTML:
<table>
<!-- The ngFor should be on the tr (table row) element, not the table element. Same goes for the "todo" and "done" classes -->
<tr *ngFor="let todo of todos; let i = index;" class="todo" [class.done]="todo.completed">
<td class="position">{{i+1}}</td>
<!-- Use todo instead of todos[i] -->
<td class="name" (dblclick)="toggleDone(i)">{{todo.content}}</td>
<td class="weight">
<button class="delete" mat-raised-button color="warn" (click)="deleteTodo(i)">Sil</button>
</td>
</tr>
</table>
TypeScript in your component:
deleteTodo(id: number) {
this.todos.splice(id, 1);
this.todos = [...this.todos];
console.log(id +"silindi");
}
Try this change:
deleteTodo(id:number){
const deletedElemnt = this.todos.splice(id,1);
console.log(id +"silindi");
console.log("deleted row: ", deletedElemnt );
console.log("todos list: ", this.todos );
}
The this.todos.splice(id,1) operation was deleting the desired row, but at the same time was returning the deleted element.
You were assigning that returned element to your whole list of todos, so finally your 'todos' list were just 1 row, the deleted element.
I'm new to angular 6 so please. I have my component.ts where i'm having my response. Now I want to bind data based on filter value in my HTML page. That is when the user clicks on the Owner Name. Now I want to display the owner name on the top right corner of my HTML page. How can I achieve that?
Here is how my HTML page looks like.
My component.ts page looks like this:
import { CampaignService } from './../../../services/campaign.service';
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private campaignService : CampaignService) { }
Time :any;
campaigns :any;
filter;
show:boolean = false ;
ngOnInit(){
setInterval(() => {
this.Time = Date.now()
}, 1000);
this.campaignService.CampaignsInfo()
.subscribe(response=>{
this.show = false;
this.campaigns = response;
});
}
filterByOwnr(val){
if(val != null)
{
this.show=true;
}
else
{
this.show=false;
}
this.filter = val;
}
}
and my HTML page looks like this:
<campaign-header></campaign-header>
<div class="container-fluid date-time sticky-top">
<div class="container">
<div class="d-flex justify-content-end" style="margin-top: -16px;">
<span id="date_time"><i class="zmdi zmdi-calendar-check zmdi-hc-fw"></i> {{Time | date}} <i class="zmdi zmdi-time zmdi-hc-fw"></i> {{ Time | date:'mediumTime' }} </span>
</div>
</div>
</div>
<br>
<!-- content -->
<div class="container">
<h3>Campaigns</h3>
<div class="clearfix"></div>
<div class="row">
<div class="col-sm-12">
<div class="card campaign border-top wrap mt-4">
<br>
<div class="card-body table-responsive">
<table class="table table-hover mb-0 ">
<thead>
<tr>
<th class="border-top-0">CAMPAIGN </th>
<th class="border-top-0">STATUS</th>
<th class="border-top-0">DIALED</th>
<th class="border-top-0">OWNERS</th>
<th class="border-top-0"> <span class="invisible">Action</span></th>
<th></th>
<!-- <button mat-button color="primary" routerLink="/campaign-details">CampaignDetails</button> -->
</tr>
</thead>
<tbody>
<tr *ngFor="let campaign of campaigns?.result | filter : 'OWNERS' : filter;">
<td style="max-width:280px">
<p>{{campaign.CampaignName}}</p>
<small>{{campaign.DepartmentName}}</small>
</td>
<td>
<small class="text-info">Active</small>
</td>
<td>
<p>{{campaign.Dialed}} / <small>1500000</small></p>
<div class="progress mt-2 w-75">
<div class="progress-bar bg-info" role="progressbar" style="width: 90%;" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td>
<span class="badge badge-pill badge-secondary cursor" (click)="filterByOwnr(campaign.CampaignName)"> {{ campaign.CampaignName }} </span>
<a (click)="filterByOwnr()" *ngIf=show style="position: relative; left: -16px; top: -1px; color: #fff; font-size: 8px; border: 1px solid #fff; border-radius: 15px; font-weight: bold; cursor: pointer; "><i class="zmdi zmdi-close zmdi-hc-fw"></i> </a>
</td>
<td class="ml-0 pl-0">
<a [routerLink]="['/campaign-details' , campaign.Id]" [queryParams]="{ CampaignName : campaign.CampaignName , SubCampaign : campaign.SubCampaign, DepartmentName : campaign.DepartmentName }"><img src="../../assets/Images/next.png" class="next" /></a>
<a (click)="filterByOwnr()" *ngIf=show class="close_icon"><i class="zmdi zmdi-close zmdi-hc-fw"></i> </a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<br>
</div>
import { CampaignService } from './../../../services/campaign.service';
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private campaignService : CampaignService) { }
Time :any;
campaigns :any;
filter;
show:boolean = false ;
selectedOwner:string;
ngOnInit(){
setInterval(() => {
this.Time = Date.now()
}, 1000);
this.campaignService.CampaignsInfo()
.subscribe(response=>{
this.show = false;
this.campaigns = response;
});
}
filterByOwnr(val){
if(val != null)
{
this.selectedOwner = val;
this.show=true;
}
else
{
this.show=false;
}
this.filter = val;
}
}
<campaign-header></campaign-header>
<div class="container-fluid date-time sticky-top">
<div class="container">
<div class="d-flex justify-content-end" style="margin-top: -16px;">
<span id="date_time"><i class="zmdi zmdi-calendar-check zmdi-hc-fw"></i> {{Time | date}} <i class="zmdi zmdi-time zmdi-hc-fw"></i> {{ Time | date:'mediumTime' }} </span>
</div>
</div>
</div>
<br>
<!-- content -->
<div class="container">
<h3>Campaigns</h3>
<div class="clearfix"></div>
<div class="row">
<div class="col-sm-12">
<div class="card campaign border-top wrap mt-4">
<br>
<div class="card-body table-responsive">
<span class="badge badge-pill badge-secondary" *ngIf="selectedOwner && show"> {{selectedOwner}} </span> <a (click)="filterByOwnr()" *ngIf=show style="position: relative; left: -16px; top: -1px; color: #fff; font-size: 8px; border: 1px solid #fff; border-radius: 15px; font-weight: bold; cursor: pointer; "><i class="zmdi zmdi-close zmdi-hc-fw"></i> </a>{{selectedOwner}}</span>
<table class="table table-hover mb-0 ">
<thead>
<tr>
<th class="border-top-0">CAMPAIGN </th>
<th class="border-top-0">STATUS</th>
<th class="border-top-0">DIALED</th>
<th class="border-top-0">OWNERS</th>
<th class="border-top-0"> <span class="invisible">Action</span></th>
<th></th>
<!-- <button mat-button color="primary" routerLink="/campaign-details">CampaignDetails</button> -->
</tr>
</thead>
<tbody>
<tr *ngFor="let campaign of campaigns?.result | filter : 'OWNERS' : filter;">
<td style="max-width:280px">
<p>{{campaign.CampaignName}}</p>
<small>{{campaign.DepartmentName}}</small>
</td>
<td>
<small class="text-info">Active</small>
</td>
<td>
<p>{{campaign.Dialed}} / <small>1500000</small></p>
<div class="progress mt-2 w-75">
<div class="progress-bar bg-info" role="progressbar" style="width: 90%;" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td>
<span class="badge badge-pill badge-secondary cursor" (click)="filterByOwnr(campaign.CampaignName)"> {{ campaign.CampaignName }} </span>
<a (click)="filterByOwnr()" *ngIf=show style="position: relative; left: -16px; top: -1px; color: #fff; font-size: 8px; border: 1px solid #fff; border-radius: 15px; font-weight: bold; cursor: pointer; "><i class="zmdi zmdi-close zmdi-hc-fw"></i> </a>
</td>
<td class="ml-0 pl-0">
<a [routerLink]="['/campaign-details' , campaign.Id]" [queryParams]="{ CampaignName : campaign.CampaignName , SubCampaign : campaign.SubCampaign, DepartmentName : campaign.DepartmentName }"><img src="../../assets/Images/next.png" class="next" /></a>
<a (click)="filterByOwnr()" *ngIf=show class="close_icon"><i class="zmdi zmdi-close zmdi-hc-fw"></i> </a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<br>
</div>
Here I am assuming you can only filter on one owner at a time, from the code that is what it looks like. If you can filter on multiple you would obviously have to store the selected in an array. Also not sure where you would be clearing the owner, but wherever you do that you then also would want to clear the selected owner string or array.
Initialize a class property which hold the selected owner name
public selectedOwnerName: string = '';
Make the owner's section as
<td>
<span class="badge badge-pill badge-secondary cursor" (click)="selectedOwnerName = campaign?.CampaignName"> {{ campaign?.CampaignName }}
<a *ngIf="selectedOwnerName == campaign?.CampaignName" style="position: relative; left: -16px; top: -1px; color: #fff; font-size: 8px; border: 1px solid #fff; border-radius: 15px; font-weight: bold; cursor: pointer; "><i class="zmdi zmdi-close zmdi-hc-fw"></i> </a>
</span>
</td>
No need to use a filterByOwnr() method to set values, you can set the value to the class property directly on the click. Use the class property {{selectedOwnerName}} (find the appropriate place to place this elem) in your HTML to display the selected owner.
As far as displaying anchor is concerned, you can use a check in the anchor tag to see if the selectedOwnerName matches with the owner name in the current for block.
Update
If you want to reset the list on click of anchor then you might want to stop the event propagation so that the event doesn't bubble up to span again.
<td>
<span class="badge badge-pill badge-secondary cursor" (click)="selectedOwnerName = campaign?.CampaignName"> {{ campaign?.CampaignName }} </span>
<a *ngIf="selectedOwnerName == campaign?.CampaignName" (click)="selectedOwnerName=""; $event.stopPropagation()" style="position: relative; left: -16px; top: -1px; color: #fff; font-size: 8px; border: 1px solid #fff; border-radius: 15px; font-weight: bold; cursor: pointer; "><i class="zmdi zmdi-close zmdi-hc-fw"></i> </a>
</td>
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;
}
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;
When a field value is too long in my bootstrap table, the table will extend to the length of the parameter even if its past the container. The only way I was able to somewhat prevent this is by using responsive-table, however then a scroll bar shows up on the bottom and you have to scroll all the way to the right to see the table data. How can I make it so when my table reaches the length of the container, the row data will wrap?
Here is an image of what is going on: http://i.stack.imgur.com/Bo1dO.jpg
Here is a portion of my view, the CSS and example can be seen here: https://jsfiddle.net/bsxtpoqd/
<div class="container">
<div class="row tab-content">
<div class="row">
<h3>Assigned Games</h3>
<p>Please enter a search string in the textbox to search for users</p>
<form class="form-inline">
<div class="form-group">
<input type="text" class="form-control" id="tableSearch" placeholder="Enter search term...">
</div>
</form>
<div class="table">
<table id="userTable" class="table">
<thead>
<tr>
<th>UserName</th>
<th>Alternate</th>
<th>Email</th>
<th>Assigned Games</th>
<th>Unassigned Games</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model)
{
<tr>
<td>#Html.ActionLink(user.UserName, "_GameAssigner", "Admin", new { insUserId = user.InstitutionUserId }, new { #class = "modal-link" })</td>
<td>
#user.AlternateId
</td>
<td>#user.Email</td>
<td>
#if (user.Assigned.Any())
{
<a href="#" tabindex="0" role="button" data-toggle="popover" title="Games" data-trigger="focus"
data-content="#foreach (var gameName in user.Assigned){<div>#gameName</div>}">
#user.Assigned.Count</a>
}
else
{
<div class="text-warning">0</div>
}
</td>
<td>
#if (user.Unassigned.Any())
{
<a href="#" tabindex="0" role="button" data-toggle="popover" title="Games" data-trigger="focus"
data-content="#foreach (var gameName in user.Unassigned) {<div>#gameName</div>}">
#user.Unassigned.Count</a>
}
else
{
<div class="text-warning">0</div>
}
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
You need to break up the long word.
<td style="word-break:break-all">
This is you need:
<style>
td
{
word-break: normal;
}
</style>