How to display data using angularJS Loop in 2 separate lines - html

I am trying to displaying the products using Angular JS loop.
<tr ng-repeat="od in OrderDetail">
<td> {{ od.ProductName }} </td><br />
<td align='right'> {{ od.MRP }} </td>
<td align='right'> {{ od.SellPrice }} </td>
<td> {{ od.Quantity }} </td>
<td align='right'> {{ od.Quantity * od.SellPrice | currency:""}}</td>
</tr>
My requirement is display the product name in 1 line, then MRP, sellprice, quantity, total in next line... and so on.
I tried after product name, also i tried using colspan=5 for product name. None of them is working.
Can someone help me on this.

This might be what you want:
<table>
<tbody ng-repeat="od in OrderDetail" >
<tr>
<td colspan="4"> {{ od.ProductName }} </td>
</tr>
<tr>
<td align='right'> {{ od.MRP }} </td>
<td align='right'> {{ od.SellPrice }}</td>
<td> {{ od.Quantity }}</td>
<td align='right'> {{ od.Quantity * od.SellPrice | currency:""}}</td>
</tr>
</tbody>
</table>
And yes, it's okay to have more than one <tbody>
EDIT: It's good practice to use :: for variables in ngRepeat, if you are only changing the entire array (such as renewing the array) and not modifying elements in the array. This will reduce the amount of watchers needed.

You want ng-repeat-start and ng-repeat-end: https://docs.angularjs.org/api/ng/directive/ngRepeat#special-repeat-start-and-end-points

Related

How to combine two arrays into one array of objects?

Can I use an ngFor instead of repeating <table> two times?
NB: I thought to combine all the items into objects as items of a single array of mapping(each object contains a variable, label and value) but it does not work for me)
....
this.maxValueTable.push(selectedData.res.maxValue);
this.minValueTable.push(selectedData.res.minValue);
...
<div style="display: flex;">
<table style="width:100%;">
<thead>
<tr>
<th>Max</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let maxValue of maxValueTable">
<td> {{ maxValue | numberFormatter: (getUnit() | async)}}</td>
</tr>
</tbody>
</table>
<table style="width:100%;">
<thead>
<tr>
<th>Min</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let maxValue of minValueTable">
<td> {{ MinValue| numberFormatter: (getUnit() | async)}}</td>
</tr>
</tbody>
</table>
</div>
Another way:
<!--create an array directly in the .html: you can also use
a variable in your .ts-->
<table *ngFor="let table of [{head:'Max',data:maxValueTable},
{head:'Max',data:maxValueTable}]
style="width:100%;">
<thead>
<tr>
<!--use table.head-->
<th>{{table.head}}</th>
</tr>
</thead>
<tbody>
<!--see how iterate over table.data-->
<tr *ngFor="let maxValue of table.data">
<td> {{ maxValue | numberFormatter: (getUnit() | async)}}</td>
</tr>
</tbody>
</table>
If your arrays has the same length and only want a table, iterate over one array ans use the index to get the value of the another one
<table style="width:100%;">
<thead>
<tr>
<th>Max</th>
<th>Min</th>
</tr>
</thead>
<tbody>
<!--see the "let i=index"-->
<tr *ngFor="let maxValue of maxValueTable;let i=index">
<td> {{ maxValue | numberFormatter: (getUnit() | async)}}</td>
<!--use the "index" "i" to get the element of the another array-->
<td>
{{ minValueTable[i] | numberFormatter: (getUnit() | async)}}
</td>
</tr>
</tbody>
</table>
in this case you can also use map to create a new Array
minMax=this.minValueTable.map((x,index)=>({
min:x,
max:this.maxValueTable[index]
}))
And use {{value.min}} and {{value.max}}
You can create a function that will combine min and max values into an array like that:
mergeIntoArray(maxValue: Array<number>, minValue: Array<number>): IMergedObj[] {
let mergedArray = [];
maxValue.forEach((value, index) => {
let tempObj = {};
tempObj['maxValue'] = value;
tempObj['minValue'] = minValue[index];
mergedArray.push(tempObj);
});
return mergedArray;
}
and call this function like that:
let minAndMax = [];
this.minAndMax = this.mergeIntoArray(this.maxValueTable, this.minValueTable);
after that, use this variable (minAndMax) in your HTML template. This way you do not need to use ngFor twice.
<table style="width:100%;">
<thead>
<tr>
<th>Max</th>
<th>Min</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of minAndMax">
<td>{{ item.maxValue }}</td>
<td>{{ item.minValue }}</td>
</tr>
</tbody>
</table>
Here is the stackblitz link created for you. Hope that might help you.
You can use *ngTemplateOutlet for this case:
<div style="display: flex;">
<ng-container *ngTemplateOutlet="tableTemplate; context: {$implicit: maxValueTable, header: 'Max'}"></ng-container>
<ng-container *ngTemplateOutlet="tableTemplate; context: {$implicit: minValueTable, header: 'Min'}"></ng-container>
</div>
<ng-template #tableTemplate let-values, let-header="header">
<table style="width:100%;">
<thead>
<tr>
<th>{{ header }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let value of values">
<td> {{ value | numberFormatter: (getUnit() | async) }}</td>
</tr>
</tbody>
</table>
</ng-template>
And you will get the same table rendered twice - for Max and Min values.
As you can see, the arguments are passed as a second argument inside ngTemplateOutlet:
context: {$implicit: valuesArgument, header: headerArgument}
Later you could use this template to create infinite amount of tables:
<div *ngFor="let table of tables">
<ng-container *ngTemplateOutlet="tableTemplate; context: {$implicit: table.values, header: table.header}"></ng-container>
</div>
Assuming your tables property will look like
export class C {
tables: Table[] = [{header: 'Min', values: [1, 2, 3]}, {header: 'Max', values: [4, 5, 6]}, {header: 'Other', values: [0, -1, -2]}]
}

HTML table with conditional rows

I'm using html templates to deliver email to my customers. The template holds a table, and I need this table to show or hide rows based on the data it's receiving. The data is injected to the HTML using handlebars.
I tried to add conditional if to the table, which works fine on the browser, but not when seeing the email:
<table class="tg">
<thead>
<tr>
<th class="tg-0pky">Name</th>
<th class="tg-0pky">{{ recipientName }}</th>
</tr>
</thead>
<tbody>
{{#if recipientId}}
<tr>
<td class="tg-0pky">ID</td>
<td class="tg-0pky">{{ recipientId }}</td>
</tr>
{{/if}}
{{#if recipientBank}}
<tr>
<td class="tg-0pky">Bank</td>
<td class="tg-0pky">{{ recipientBank }}</td>
</tr>
{{/if}}
{{#if recipientBranch}}
<tr>
<td class="tg-0pky">Branch</td>
<td class="tg-0pky">{{ recipientBranch }}</td>
</tr>
{{/if}}
{{#if recipientAccountNumber}}
<tr>
<td class="tg-0pky">Account number<br/></td>
<td class="tg-0pky">{{ recipientAccountNumber }}</td>
</tr>
{{/if}}
{{#if recipientAccountType}}
<tr>
<td class="tg-0pky">Account type</td>
<td class="tg-0pky">{{ recipientAccountType }}</td>
</tr>
{{/if}}
<tr>
<td class="tg-0pky">Amount to receive</td>
<td class="tg-0pky">{{ recipientReceive }}</td>
</tr>
</tbody>
</table>
When receiving the email:
When I receive the email, the rows are shown or not based on the data injected, but the table loses its formatting.
I've read that using a script is not the best way to handle this, because it's not a good practice to use scripts in email.
How can I dynamically show or hide the rows if the variable is present or not?

Passing an argument into sqlalchemy query, displaying tables data dynamically

I am trying to implement a data tables that will show all EMPLOYEE data for 3 tables but I am having issue displaying the data dynamically if triggered by employee.id. I'm trying to get my head aorund this. Any help will be appreciated
`
#bp.route('/employees/show_all/<int:id>')
#login_required
def show_table(id):
success = db.session.query(Employee, Passport, Cerpac).\
select_from(Employee).join(Passport).join(Cerpac).filter(Employee.id==id).all()
return render_template('admin/employees/show-card.html', show_table=show_table, title="Show all Employee" )
--------------------THE LINK------------------------------
<a class="dropdown-item" href="{{ url_for('admin.show_table', id=employee.id) }}"><i class="fa fa-pencil m-r-5">view</a>
--------------------HTML ------------------------------
{% for employee, passport, cerpac in success %}
<tr>
<td> Employeees </td>
<td> {{ employee.first_name }} </td>
<td> {{ employee.last_name }} </td>
----------------------------------------
<td> Cerpac </td>
<td> cerpac.cerpac_serial_no}} </td>
<td> {{ cerpac.cerpac_issue_date}} </td>
-----------------------------------------
<td> Passport </td>
<td> {{ passport.nationality }} </td>
<td> {{ pasport.passport_no }} </td>
------------------------------------------

Cannot find a differ supporting object '[object Object]'. NgFor only supports binding to Iterables such as Arrays

here is code i am trying to access object of objects.
template
<table class="table table-striped">
<tr *ngFor="let response of response">
<td><b>ID</b><br>{{ response.user_id }} </td>
<td><b>Name:</b> {{ response.first_name }}</td>
</tr>
</table>
The response isn't directly an array. It is an object with properties that contain the array. From the image you posted, you could try the following
<table class="table table-striped">
<tr *ngFor="let customer of response._embedded.customers"> <!-- access properties here -->
<td>
<b>ID</b><br>
{{ customer.user_id }}
</td>
<td>
<b>Name:</b> {{ customer.first_name }}
</td>
</tr>
</table>

Angular CDK table: Element 'td' cannot be nested inside element 'table'

I'm trying to use the Angular CDK table in an Angular 7 project in Visual Studio 2017. When I follow the official code sample from here it works perfectly but I get these warnings from visual studio: Element 'td'/'th' cannot be nested inside element 'table'.
Below is the code for reference:
<table cdk-table [dataSource]="masterIds">
<ng-container cdkColumnDef="name">
<th cdk-header-cell *cdkHeaderCellDef> Name </th>
<td cdk-cell *cdkCellDef="let id"> {{ ws[id].Name }} </td>
</ng-container>
<ng-container cdkColumnDef="code">
<th cdk-header-cell *cdkHeaderCellDef> Code </th>
<td cdk-cell *cdkCellDef="let id"> {{ ws[id].Code }} </td>
</ng-container>
<tr class="small" cdk-header-row *cdkHeaderRowDef="['name', 'code']"></tr>
<tr cdk-row *cdkRowDef="let id; columns: ['name', 'code']" [routerLink]="['./', id]"></tr>
</table>
Any idea how to get rid of these warnings? They are poking me in the eye. Thanks
UPDATE
Here is a picture of the warnings:
And the green squiggles :
I just found a way which "seems" to work; wrap all the column definitions inside an invisible <tr> element and that's that:
<table cdk-table [dataSource]="masterIds">
<tr style="display:none!important">
<ng-container cdkColumnDef="name">
<th cdk-header-cell *cdkHeaderCellDef> Name </th>
<td cdk-cell *cdkCellDef="let id"> {{ ws[id].Name }} </td>
</ng-container>
<ng-container cdkColumnDef="code">
<th cdk-header-cell *cdkHeaderCellDef> Code </th>
<td cdk-cell *cdkCellDef="let id"> {{ ws[id].Code }} </td>
</ng-container>
</tr>
<tr class="small" cdk-header-row *cdkHeaderRowDef="['name', 'code']"></tr>
<tr cdk-row *cdkRowDef="let id; columns: ['name', 'code']" [routerLink]="['./', id]"></tr>
</table>
A th should be inside a tr, you should have something like :
<table>
<tr>
<th></th>
<th></th>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
For your updated question
That's because of the Visual studio compiler itself, you can search for How to suppress VS studio compiler warnings (try this), and a tip: switch to VsCode for your frontend dev.