AngularJs - Reference the same scope property from multiple ngRepeat's - javascript

I have multiple ngRepeats generate table contents, depending on the view the user wants to see, a different ngRepeat is used to generate the table. When the user switches their view, and one of the following is removed from the DOM and another added, the new ngRepeat does not reference to the same pagination.filteredData array.
Example: Main is my controller, using controller as syntax.
<tr ng-if="Main.tableConfig.programGranularity == 'overall'" ng-repeat="item in Main.pagination.filteredData = ( Main.data.overallData | filterByDateRange | filter: Main.tableConfig.generalSearch | orderBy: ['Date', 'Name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-repeat="column in Main.tableConfig.columnsConfig | selectColumnsByGranularity: Main.tableConfig.programGranularity">
<span ng-if="!column.isDate" ng-bind="item[column.dataValue] | ifEmpty: 0"></span>
<span ng-if="column.isDate" ng-bind="item[column.dataValue] | date:'MM/dd/yyyy': 'UTC' | ifEmpty: 0"></span>
</td>
</tr>
<tr ng-if="Main.tableConfig.programGranularity == 'team'" ng-repeat="item in Main.pagination.filteredData = ( Main.data.teamData | filterByDateRange | filter: Main.tableConfig.generalSearch | orderBy: ['Date', 'Name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-repeat="column in Main.tableConfig.columnsConfig | selectColumnsByGranularity: Main.tableConfig.programGranularity">
<span ng-if="!column.isDate" ng-bind="item[column.dataValue] | ifEmpty: 0"></span>
<span ng-if="column.isDate" ng-bind="item[column.dataValue] | date:'MM/dd/yyyy': 'UTC' | ifEmpty: 0"></span>
</td>
</tr>
<tr ng-if="Main.tableConfig.programGranularity == 'colleague'" ng-repeat="item in Main.pagination.filteredData = ( Main.data.parsedData | filterByDateRange | filter: Main.tableConfig.generalSearch | orderBy: ['Date', 'Name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-repeat="column in Main.tableConfig.columnsConfig | selectColumnsByGranularity: Main.tableConfig.programGranularity">
<span ng-if="!column.isDate" ng-bind="item[column.dataValue] | ifEmpty: 0"></span>
<span ng-if="column.isDate" ng-bind="item[column.dataValue] | date:'MM/dd/yyyy': 'UTC' | ifEmpty: 0"></span>
</td>
</tr>
I want the same pagination.filteredData array to be set by each of the ngRepeat directives. However, only the first ngRepeat that runs sets the value and no other ngRepeat will set it again.
I've tried ngInit and initializing an object with pagination inside of it, and referencing that in my ngRepeat. I have also tried using $parent.pagination.filteredData.
Using AngularJS v1.5.0
How do I get this to work?
Similar to https://stackoverflow.com/questions/38235907/angularjs-service-variable-not-being-set-inside-of-ngrepeat but reworded and fundamentally different. Solving the same problem though.
Edit: Refactored to utilize the controller as syntax, the problem still persists. To me it seems that when I switch to a different ngRepeat, a new array and reference is created, instead of overwriting the current arrays values.

Okay, I have spent some time putting together a demo replicating (as best I could) the code that you have provided <-- Broken, and I think I understand your issue. You say "the first ng-repeat that runs sets the value", and I think it's actually the LAST ng-repeat that runs that is setting it. It's not having a problem setting the value, the problem is that all 3 ng-repeats run every time, so it's always the last one that wins.
The reason this happens is because ng-repeat executes BEFORE ng-if for the common case of <element ng-if="item.showMe" ng-repeat="item in Main.items"></element>
That being said, even though your ng-if condition is false, so the <tr> does not get displayed, the ng-repeat has already run, and already set Main.pagination.filteredData
I think your best course of action would be to move your ng-if up one level to the <tbody>. It would look like the following:
WORKING DEMO <-- Working
<table>
<thead>
<tr>
<th>Name</th>
<th>Data</th>
<th>Date</th>
</tr>
</thead>
<tbody ng-if="Main.tableConfig.programGranularity == 'overall'" >
<tr ng-repeat="item in Main.pagination.filteredData = (Main.data.overallData | filterByDateRange | orderBy: ['date', 'name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-bind="item.name"></td>
<td ng-bind="item.overall"></td>
<td ng-bind="item.date"></td>
</tr>
</tbody>
<tbody ng-if="Main.tableConfig.programGranularity == 'team'" >
<tr ng-repeat="item in Main.pagination.filteredData = (Main.data.teamData | filterByDateRange | orderBy: ['date', 'name']) | startFrom: Main.pagination.startAtIndex | limitTo: Main.pagination.pageSize">
<td ng-bind="item.name"></td>
<td ng-bind="item.team"></td>
<td ng-bind="item.date"></td>
</tr>
</tbody>
</table>

Related

Using *ngFor to display string values from array

I have an array which is created from splitting a string using str.split() and this creates an array and it looks like this:
var array = [
"TEXT1,1234,4321,9876",
"TEXT2,2345,5432",
"TEXT3,6543,3456"
]
I want to be able to display this information in a table using *ngFor.
I have tried this (from this question):
<tr>
<td *ngFor="let info of array">{{info.join(",")}}</td>
</tr>
But I get this error:
ERROR TypeError: _v.context.$implicit.join is not a function
at Object.eval [as updateRenderer]
The table should look like this:
TITLE | VALUE1 | VALUE2 | VALUE3
--------------------------------
TEXT1 | 1234 | 4321 | 9876
--------------------------------
TEXT2 | 2345 | 5432 |
--------------------------------
TEXT3 | 6543 | 3456 |
How do I achieve this table?
To make array from string with , delimiters use String.prototype.split method
<tr *ngFor="let row of array">
<td *ngFor="let info of row.split(',')">{{info}}</td>
</tr>
Ng-run Example
You will need two *ngFors. One to loop through each item in the array and one to iterate through each item in the array that you'll create by splitting the string with ,
Give this a try:
<table border="1">
<thead>
<tr>
<td>TITLE</td>
<td>VALUE 1</td>
<td>VALUE 2</td>
<td>VALUE 3</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of array">
<td *ngFor="let column of row.split(',')">
{{ column }}
</td>
</tr>
</tbody>
</table>
Here's a Working Sample StackBlitz for your ref.

Create a dynamic Table out of JSON Object using Angular 5 directives

Is it possible to create a dynamic Table(dynamic Columns) based on a JSON object with Angular 5 directives/ Or with the help of jQuery? If so how?
Lets say i get this JSON response from a REST API:
{
name: "Ferrari"
country: "Italy",
creater: "Enzo Ferrari"
cars: [
{
modell: "Ferrari 488",
price: "215.683€"
},
{
modell: "Ferrari Portofino",
price: "189.704€"
}
]
}
Now i want to create a Table out of this Data that should look like this:
+-----------+----------+--------------+--------------+------------+--------------------+-------------+
| Name | Country | Creater | Modell | Price | Modell | Price |
+-----------+----------+--------------+--------------+------------+----------------------------------+
| Ferrari | Italy | Enzo Ferrarie| Ferrarie 488 | 189.704€ | Ferrarie Portofino | 189.704€ |
+-----------+----------+--------------+--------------+------------+--------------------+-------------+
What would the best approach be to solve this? I just cant figure it out how to solve this problem? Any help is really appreciated.
If you only have one object in the table (meaning one header row and one data row) you could do something like this:
<table>
<thead>
<tr>
<th>Name</th>
<th>Country</th>
<th>Creater</th>
<ng-template ngFor [ngForOf]="data.cars">
<th>Modell</th>
<th>Price</th>
</ng-template>
</tr>
</thead>
<tbody>
<tr>
<td>{{ data.name }}</td>
<td>{{ data.country }}</td>
<td>{{ data.creater }}</td>
<ng-template ngFor let-car [ngForOf]="data.cars">
<th>{{ car.modell }}</th>
<th>{{ car.price }}</th>
</ng-template>
</tr>
</tbody>
</table>
You can us ng-template and the ngFor directive to loop over the cars.
Important: If you have multiple data rows you need to make sure to transform your data so you always display the same amount of columns, otherwise the html will be broken.

Grouping HTML table rows with rowspan

I am struggling with this issue for a while and really appreciate if someone can give some idea on how I can move forward with.
The idea is to reduce the number of rows in the table by grouping the relevant data in the below format.
I need to convert the JSON response coming from server (non-grouped data) to a particular format so that I can paint the table with the grouped data.
**Initial Layout**
+------------+-----------+--------+------------+
| Category | Product | Size | Shipping
+------------+-----------+--------+------------+
| Category 1 | Product 1 | Big | Free |
| Category 1 | Product 2 | Small | Free |
| Category 1 | Product 3 | Big | Free |
| Category 1 | Product 4 | Small | Free |
+------------+-----------+--------+-------------
**Expected Result**
+------------+----------------------+--------+-----------
| Category | Product | Size | Shipping
+------------+----------------------+--------+------------
| Category 1 | Product 1, Product 3 | Big | Free |
| | Product 2, Product 4 | Small | Free |
+------------+----------------------+--------+----------
More details in the jsfiddle:
https://jsfiddle.net/zy8kj2tb/2/
// please see the code in jsfiddle
<h3>
Initial layout:
</h3>
<h6>
<p>
Category = Category 1, Category 2, etc or "blank"
</p>
<p>
Product = Product 1, Product 2, etc or "blank"
</p>
<p>
Size = Big, Small, XL, etc or "blank"
</p>
<p>
Shipping = Free, Standard, Expedited, etc or "blank"
</p>
<p>
dont group blank rows with cat, prod, size = make it as individual row
</p>
</h6>
<div id="initialLayout">
</div>
<h3>Expected result:</h3>
<table id="expectedTable" border="1" cellpadding="3" cellspacing="0">
<tr>
<th>Category</th>
<th>Product</th>
<th>Size</th>
<th>Shipping</th>
</tr>
<tr>
<td rowspan=2>Category 1</td>
<td rowspan="2">Product 1, Product 3 <br>Product 2, Product 4</td>
<td rowspan="2">Big <br>Small</td>
<td rowspan="2">Free</td>
</tr>
</table>
<br/>
Just replace your HTML with this one, I did two things -
Changed first row with -
<td rowspan="2">Product 1, Product 3 <br>Product 2, Product 4</td>
<td rowspan="2">Big <br>Small
</td>
Removed respective td tags from the second row
I just looked at your code
where you have written
<td rowspan=2>Category 1</td>
<td>Product 1, Product 3</td>
<td>Big</td>
<td rowspan=2>Free</td>
It should be
<td rowspan="2">Category 1</td>
<td>Product 1, Product 3</td>
<td>Big</td>
<td rowspan="2">Free</td>
you have just missed some quotes

Angular 1.5 Expected array but received: 0 when using filter

I'm creating a table, it works fine when I display data, this is the code
<tr ng-repeat="value in sd.data track by $index | orderBy: syscode">
<td>{{($index>0 && sd.data[$index].syscode === sd.data[$index-1].syscode) ? '' : value.syscode}}</td>
<td>{{value.out_signal_id}}</td>
<td class="text-center no-wrapping">{{value.sig_epoch_utc}}</td>
<td class="text-center ">{{value.num_of_signals}}</td>
<td class="text-center no-wrapping">{{value.status_code}}</td>
<td class="text-center no-wrapping">{{value.status_note}}</td>
<tr >
My issue is that when I use 'orderBy:' as a filter, I get this error
`Error: [orderBy:notarray] Expected array` but received: 0
I am not sure why, I have checked other questions similar to this, but those didn't answer my question. Any feedback will be appreciated thanks
Track by should be always at the end and you miss apices so this:
<tr ng-repeat="value in sd.data track by $index | orderBy: syscode">
should be:
<tr ng-repeat="value in sd.data | orderBy: 'syscode' track by $index">
This exact scenario is covered in the docs for ngRepeat (see the note at the bottom of the section). Basically, the track by needs to be the last thing in your expression.
value in sd.data | orderBy: 'syscode' track by $index

How to display a multi dimensional array as a table?

This problem's been haunting me for days... I have the following JSON that I'm trying to render as a table using Tempo.js but keep getting nothing rendered:
[
{
"id":"xxxxxxxxxxxxxxxxxxxxxxxxxx",
"name":"Family One",
"parents":[
{
"id":"yyyyyyyyyyyyyyyyyyyyyyyyyy",
"name":"John Doe",
"children":[
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz",
"name":"Fabrice A",
"description":"Good kid",
"Age":"20",
"Weight":"60"
}
]
},
{
"id":"hhhhhhhhhhhhhhhhhhhhhhhhhh",
"name":"Jane Doe",
"children":[
{
"id":"wwwwwwwwwwwwwwwwwwwwwwww",
"name":"Maurice A",
"description":"Bad kid",
"Age":"22",
"Weight":"50"
}
]
}
]
},
{
"id":"xxxxxxxxxxxxxxxxxxxxxxxxxx2",
"name":"Family Two",
"parents":[
{
"id":"yyyyyyyyyyyyyyyyyyyyyyyyyy2",
"name":"Sonny Doe",
"children":[
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz2",
"name":"Juan B",
"description":"Good kid",
"Age":"30",
"Weight":"70"
},
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz3",
"name":"Alberto B",
"description":"Fine kid",
"Age":"20",
"Weight":"60"
},
{
"id":"zzzzzzzzzzzzzzzzzzzzzzzzz4",
"name":"Roberto B",
"description":"Medium kid",
"Age":"10",
"Weight":"50"
}
]
}
]
}
]
The table is supposed to look like this:
_______________________________________________________________________________________
| FAMILY NAME | PARENTS | CHILD NAME | CHILD DESCRIPTION | CHILD AGE | CHILD WEIGHT |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
| Family One | John Doe | Fabrice A | Good kid | 20 | 60 |
| |''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
| | Jane Doe | Maurice A | Bad kid | 22 | 50 |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
| Family Two | Sonny Doe | Juan B | Good kid | 30 | 70 |
| | | Alberto B | Fine kid | 20 | 60 |
| | | Roberto B | Medium kid | 10 | 50 |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Please notice how the family cell stretches to house more than one parent rows, and the parent cell streches to house more than one children rows.
I prepare the JSON in js in a variable called familyTree, and then call Tempo.prepare('family-list').render(familyTree);
No I've read all of the documentation for tempo.js (which wasn't too long), but I still haven't found a way of rendering the table properly. Here's what I got so far:
<div id="family-list">
<table id="families">
<tr data-before-template='data-before-template'>
<th>
FAMILY NAME
</th>
<th>
PARENTS
</th>
<th>
CHILD NAME
</th>
<th>
CHILD DESCRIPTION
</th>
<th>
CHILD AGE
</th>
<th>
CHILD WEIGHT
</th>
</tr>
<tr data-template='data-template'>
<td id="family-column">
{{name}}
</td>
<td id="parent-column" data-template-for='parents'>
{{name}}
</td>
<td colspan="4">
<table id='children-table' data-template-for="children">
<tr>
<td>
{{name}}
</td>
<td>
{{description}}
</td>
<td>
{{age}}
</td>
<td>
{{weight}}
</td>
</tr>
</table>
</td>
</tr>
I've used tempo before. I've even mixed it with wkhtmltopdf to render some nice-looking pdf files. But I just cannot solve this. If any of you out there has been through anything similar..would you please share your experience? Thanks so much in advance.
Using tempo.js is not ideal to render hierarchical data in a table. To render hierarchical data, tempo.js requires that the HTML elements also exists in a hierarchy. This is not ideal when dealing with tables, because creatign a table inside a table cell will eventually lead to column alignment issues. You can take care of alignment issues to a certain degree by fixing the width of each column, but this will not be a perfect solution.
Having said above, I've fixed your HTML markup to render your JSON data using tempo.js. See the changes below (jsfiddle here):
<div id="family-list">
<table id="families">
<tr data-before-template='data-before-template'>
<th width="100px">
FAMILY NAME
</th>
<th width="100px">
PARENTS
</th>
<th width="100px">
CHILD NAME
</th>
<th width="150px">
CHILD DESCRIPTION
</th>
<th width="50px">
CHILD AGE
</th>
<th width="50px">
CHILD WEIGHT
</th>
</tr>
<tr data-template='data-template'>
<td id="family-column">
{{name}}
</td>
<td colspan="5">
<table cellpadding="0">
<tr data-template-for='parents'>
<td width="100px">
{{name}}
</td>
<td>
<table id='children-table' cellpadding="0">
<tr data-template-for="children">
<td width="100px">
{{name}}
</td>
<td width="150px">
{{description}}
</td>
<td width="50px">
{{Age}}
</td>
<td width="50px">
{{Weight}}
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>

Categories