Angular 2+ : Condition based on previous index date value ngIf NgFor - html

Trying to format a table using Angular where:
If the day of the month changes, then you insert a new row which just contains the date (but also displays the data for that index value immediately below). If the day of the week is the same as before continue inserting the rows.
1) Clearly my code for accessing previous value in index is wrong but I can't seem to find anything clearly which helps.
2) I realise that my current code would compare the full datetime value and not just the day of the month (or week) but I am unsure how to do this in this scenario.
3) when the day changes and I try and insert the date line, I cannot get an additional new row formatted correctly which includes the data for that index value. I have tried playing around with various and combinations.
Please could someone help correct this code or point me in the right direction
Thanks
<table class="table-striped">
<thead>
<tr>
<td>day</td>
<td>time</td>
<td>region</td>
<td>event</td>
<td>period</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let eco of eco_r ; let i = index">
<template [ngIf]="eco.date != eco[i-1].date">
<td colspan="5">{{eco.datetime| date:'longDate' }}</td>
<tr>
<td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td>{{eco.region}}</td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</template>
<template [ngIf]="eco.date == eco[i-1].date">
<td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td>{{eco.region}}</td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</template>
</tr>
</tbody>
</table>
------------UPDATE ---------------
Following #Iancovici comments I have revised the following
i) corrected to reference eco_r[i-1].date
ii) Changed sql source to provide eco.day_of_month and eco.week_of_year to make it easier to reference and check conditions
iii) updated code to only check previous value when i > 0
I am still unable to get it to display a new line with the date AND also include the data for that value of i on a separate row where it formats correctly. Utilising as in my revised code puts all 5 values into the first column of the next row and messes put the table format. How should I resolve this please?
Thanks
<template [ngIf]="i >0 && eco.day_of_month != eco_r[i-1].day_of_month">
<tr><td colspan="5">{{eco.datetime| date:'longDate' }}</td>
</tr>
<tr> <td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td> {{eco.region}} </td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</template>

Should probbly be *ngIf not [ngIf] in general. But I see in your case it’s ok because you’re using an ng template which means instead of directive *ngIf it’s not a bonded property [ngIf]
Also you're accesing the same instance, should access index of array instead so..
change from
*ngIf="eco.date == eco[i-1].date">
to
*ngIf="eco.date == eco_r[i-1].date">
Update: Two more notes
Make sure you create a table, with tag
Don't be afraid to use paranthesis if conditonal expressions become more complex, so you can distinguish the two conditions.
Try this without the filters, then integrate the filters in.
<table>
<div *ngFor="let eco of eco_r; let i = index">
<div *ngIf="(i > 0) && (eco.day_of_month != eco_r[i-1].day_of_month)">
<tr>
<td colspan="5">{{eco.datetime }}</td>
</tr>
<tr>
<td>{{eco.datetime }}</td>
<td>{{eco.datetime }}</td>
<td> {{eco.region}} </td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</div>
</div>
</table>

Related

How to bind data with ngFor in angular

I am new to angular. Just learning it.
I want to bind data with ngFor. but its not showing any data. Kindly help me to solve this
html file :
<tbody class="text-center">
<tr *ngFor="let agent of agentlist ;let i = index">
<td>{{i + 1 + paginationObject?.page * paginationObject?.itemPerPage}}</td>-->
<td>{{agent?.id?agent?.id:''}}</td>
</tr>
</tbody>
error : <!--bindings={ "ng-reflect-ng-for-of": null }-->
Try removing the --> at the end of the first table cell and correct the binding on the second one.
<tbody class="text-center">
<tr *ngFor="let agent of agentlist ;let i = index">
<td>{{i + 1 + paginationObject?.page * paginationObject?.itemPerPage}}</td>-->
<td>{{agent?.id}}</td>
</tr>
</tbody>
Also, you need to make sure that agentlist has something to iterate. maybe putting a console.log(agentlist) and see what it has inside of it in the ts class. If angelist is only declared but never defined you will get that error. Initialize angelist as an empty array to make sure that have an iterable before defining with the final data.

How to show only 5 rows of data from 100 in angular 8 HTML and sort them directly while displaying on screen in descending order

I've used [row] attribute but still not working and when the data reflects on UI I want it in descending order. Can anyone please let me know how it is done without adding sorting Icon?
More
{{col.header}}
{{rowData[col.field]}}
</tr>
</ng-template>-->
<ng-template pTemplate="body" let-rowData let-columns="columns">
<tr [pSelectableRow]="rowData">
<td style="width:300px">{{rowData.atomName}} </td>
<td style="width:300px" (click)="show(rowData.message,op2.show($event))" pTooltip="View" tooltipPosition="top" tooltipStyleClass="custom-tooltip">
{{rowData.processName}}<!--</td>-->
<!--<td style="width:20px">-->
</td>
<td style="width:20px">
<!--{{rowData.executionTime}}-->
{{rowData.executionTime | date :'MM/dd/yyyy' }} ({{rowData.executionTime | date :'h:mm:ss a' }})
</td>
</tr>
</ng-template>
</p-table>
</p-panel>
</div>
It looks more like Angular Js than Angular 8 but if referring to Angular 8 -
Only possible solution to this is sort in the TS file using Array Sort (refer link - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort). and then display only 5 top results using *ngFor and index inside *ngFor.

How to make table with 4 cells in row, in html using angularJS

I have to make a table, where the first cell in a row is the name of the store, and other cells are names of terminals related to that store. Below you can see how it looks now. Stores is a list of stores, where every store has a list of terminals.
<tbody>
<tr *ngFor="let store of stores; let i = index">
<td>
<label>{{ store.name }}</label
>
</td>
<td *ngFor="let terminal of store.terminals">
<label>{{ terminal.name }}</label
>
</td>
</tr>
</tbody>
It's working perfectly until there aren't too many terminals. Now I need to break that row in more of them.
Now the table looks like this:
Store1 Terminal1 Terminal2 terminal3 terminal4 Terminal5 Terminal6 terminal7 terminal8
Store2 Terminal1 Terminal2 terminal3 terminal4 Terminal5 Terminal6 terminal7 terminal8
And I need to make it look like this:
Store1 Terminal1 Terminal2 terminal3 terminal4
Terminal5 Terminal6 terminal7 terminal8
Store2 Terminal1 Terminal2 terminal3 terminal4
Terminal5 Terminal6 terminal7 terminal8
I thought, that I could make another table, only for terminals, but that didn't work as I thought it would.
Instead of repeating the "td" with terminal data. Add a div inside that td and repeat the terminal data inside that.
<table>
<tbody>
<tr *ngFor="let store of stores; let i = index">
<td>
<label >{{ store.name }}</label>
</td>
<td>
<div class="terminals">
<span class="terminals_value" *ngFor="let terminal of store.terminals">{{ terminal.name }}</span></div>
</td>
</tr>
</tbody>
</table>
Add the css to style the div block as appropriate
.terminals{
width:500px;
display:flex;
flex-wrap: wrap;
}
.terminals_value{
width:100px;
padding:2px;
}
I have created a stackblitz project as a solution, you can check it out here - https://stackblitz.com/edit/table-structure

How to hide the null date[0001-01-01T00:00:00] value in view?

In my manager, I set the null value to date.but in view it shows the some value.I need to hide that date value.I tried if the created date is null, I showed empty data.but it comes with some value
Html:
<ng-template #tmplt>
<tr *ngFor="let manage of managecontent; let i =index">
<td>{{manage.CategorytypeName}}</td>
<td>{{manage.CreatedBy}}</td>
<td *ngIf="manage.CreatedDate!=null">{{manage.CreatedDate}}</td>
<td *ngIf="manage.CreatedDate == null"></td>
<td *ngIf="manage.DocumentDetails!=null">{{manage.DocumentDetails.DocName}}</td>
<td *ngIf="manage.DocumentDetails==null"></td>
<td>
<app-file-upload [documentModel]="manage.DocumentDetails" [isMultipleFile]="true" [model]="manage" (emitterFile)="fileSelect($event)"></app-file-upload>
</td>
</tr>
</ng-template>
First, you should use the *ngIf like this.
<td *ngIf="!manage.CreatedDate">{{manage.CreatedDate}}</td>
Second, you should use timestamps or date objects for your dates. Not strings.
Third, once you manage your dates with objects or timestamps, you can test them easily : either they have the value null, or their value is the start of the Unix time (maning the timestamp would be equal to zero). In both cases, those are falsy values, that you can test as I told you in the first point of my answer.
Maybe like this
<td *ngIf="!manage.CreatedDate; else elseBlock">{{manage.CreatedDate}}</td>
<ng-template #elseBlock> - </ng-template>

Angular checkbox gets updated even though ngModel doesn't

I'm working on a shift arrangement app. In it I'm trying to create two tables that show which possible shifts each user has selected.
Both tables display the same data, but arrange it differently. Each table cell has a number of check-boxes that display the possible shifts for each person (in table 1) or the possible people for a shift (in table 2). A checkbox from table 1 that displays shift A option for person X will have the same data-bind as its equivalent checkbox in table 2, which displays person X option for shift A.
The purpose of this is to update the equivalent data in both tables simultaneously when the user couples a person with a shift. The problem: when a checkbox in table 1 is checked/unchecked, all of the check-boxes in table 2 gets checked/unchecked, as shown below:
Here is my template:
<div class="table-container" dir="ltr">
<h3>People</h3>
<table>
<thead>
<th>Name</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let user of userPreferences">
<td>{{user.name}}</td>
<td>
<div *ngFor="let selection of userYesses[user.name]">
<mat-checkbox class="option-checkbox" dir="ltr" [(ngModel)]="selection.isSelected" name="usc">{{selection.option}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="table-container" dir="ltr">
<h3>Shifts</h3>
<table>
<thead>
<th>Time</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let shift of totalShifts">
<td dir="ltr">{{shift.time}}</td>
<td>
<div *ngFor="let selection of shiftYesses[shift.time]">
<mat-checkbox class="option-checkbox" [(ngModel)]="selection.isSelected" name="syc">{{selection.name}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
And here is relevant component code:
this.userPreferences.forEach(u => {
this.userYesses[u.name] = [];
u.preferences.shifts.forEach(week => {
week.forEach(day => {
if (!day.shifts) return;
day.shifts.forEach(shift => {
if (!this.shiftYesses[`${day.date} ${shift.time}`]) this.shiftYesses[`${day.date} ${shift.time}`] = [];
if (shift.isSelected) {
let selection = new Selection(`${day.date} ${shift.time}`, u.name);
this.userYesses[u.name].push(selection);
this.shiftYesses[`${day.date} ${shift.time}`].push(selection);
}
});
});
});
});
The code seems alright to me, am I missing anything? Maybe it's a bug in Angular?
Thanks in advance!
In case anyone else experiences this issue -
After a few days of struggling with this, I stumbled upon this issue from Angular's git - https://github.com/angular/angular/issues/9230
I've read the following in kara's answer:
In the case that you don't want to register a form control, you currently have a few options:
1 - Use ngModel outside the context of a form tag. This will never throw.
<input [(ngModel)]="person.food">
After reading this, I switched the <form> tag into a <div> and everything works as expected now.