1

Please don't mark it as a duplicate- I have tried the below links already: 1) Hide/show individual items inside ngFor 2) Angular 2 - expand collapse table row 3) Hide/show individual items inside ngFor in angular 2

Problem:
I am trying to hide/show a table row when clicking on a link in the previous row like below: component.html

<div class="table-responsive" *ngFor="let total of totals; let i=index">
<table class="table">
    <ng-container *ngIf="total">   
            <h4 class="productName">Product: {{total.projectGroup}}</h4>
            <tr>
                <th>Total LOC</th>
                <th>Total Test Coverage</th>
                <th>Total Coverage on New Code</th>
                <th>Total Technical Debt</th>
                <th>Total Issues</th>
            </tr>        
            <tr>
                <td>{{total.totalLOC}}</td>
                <td>{{total.totalCoverage}}</td>
                <td>{{total.totalNewCoverage}}</td>
                <td>{{total.totalTechDebtDays}}</td>
                <td><span *ngIf="total.totalCriticalIssues >= 0">Critical: </span>{{total.totalCriticalIssues}} <br/> <span *ngIf="total.totalNonCriticalIssues >= 0">Non-critical: </span>{{total.totalNonCriticalIssues}}</td>
            </tr>
            <tr>
                <td><a id="{{i}}" class ="a_link"  (click)="toggle[total.projectGroup]=!toggle[total.projectGroup]; expand(total.projectGroup)"> Expand/Collapse</a></td>
            </tr>
            <tr [hidden]="!toggle[total.projectGroup]">                       
                <div class="table-responsive">
                    <table class="table">
                        <tr class="table-header">
                            <th>Project Key</th>
                            <th>Quality Gate</th>
                            <th>LOC</th>
                            <th>Test Coverage</th>
                            <th>Coverage on New Code</th>
                            <th>Technical Debt</th>
                            <th>Issues</th>
                        </tr>  
                        <tr *ngFor="let pjt of indProjects" class="table-condensed">
                            <td>{{pjt.projectKey}}</td>
                            <td>{{pjt.qualityGate}}</td>
                            <td>{{pjt.loc}}</td>
                            <td>{{pjt.coverage}}</td>
                            <td>{{pjt.newCoverage}}</td>
                            <td>{{pjt.techDebtDays}}</td>
                            <td><span *ngIf="pjt.criticalIssues >= 0">Critical: </span>{{pjt.criticalIssues}} <br/> <span *ngIf="pjt.nonCriticalIssues >= 0">Non-critical: </span>{{pjt.nonCriticalIssues}}</td>
                        </tr>
                    </table>
                </div>
            </tr>                
    </ng-container>
</table>

Its working if I click on the same "Expand/Collapse" link 2 times - first it shows and then it hides. But if I click on a link once(it shows) and then click on another link, both of the expansions will show the same data in the inner table( which is the data of the last expansion). What I need is the first expansion should show the data related to that link and second expansion should show the data related to the second one.

Please, any pointers would be helpful. Please let me know if I am not clear in describing the issue.

ljs
  • 495
  • 1
  • 8
  • 23

1 Answers1

2

The problem you are facing here is that you are associating a toggle to an element inside a for loop without actually creating different references. This means that all the generated table rows will point to the same reference so when you click one link it will affect multiple.

Since you are already getting the index on the ngFor loop you should associate that index to the toggle references. The result would become something like this

toggle_1[total.projectGroup]
toggle_2[total.projectGroup]

This way the reference for the action would be kept on each row of the table.

But to simplify what it seems to be your goal you could just have

(click) = “toggle[i] = !toggle[i]”

And then where you have the hidden checking the toggle I would also replace

[hidden]="!toggle[total.projectGroup]"

With

[hidden]="!toggle[i]”

I believe you just need the template flags. Unless you need some more complex behaviour I don’t think you need the component function at all

I have also noticed that you have the second ngFor loop without an index. This will cause issues because when you set the indProjects property it will have the same value for all the rows. So you need to pass the index to your expand(total.projectGroup, i) function and in the template when doing the loop you will need to read from

<tr *ngFor="let pjt of indProjects[i]" class="table-condensed">

This way you will for sure have unique list per row

Hugo Noro
  • 3,145
  • 2
  • 13
  • 19
  • Ok. I can do like this - `(click)="toggle-i[total.projectGroup]=!toggle-i[total.projectGroup]`. But how should I change the toggle() function in the component,ts file? – ljs Jan 30 '18 at 22:41
  • Where are you calling that function? Sorry but it’s a big piece of code and I’m on the phone :) – Hugo Noro Jan 30 '18 at 22:49
  • I got it from here https://stackoverflow.com/a/36874220/8513968 . Now I realise that I don't call it at all. So I commented it out. But, after adding the index, what happens is - when I click on 1 link, it expands all other links. – ljs Jan 30 '18 at 22:56
  • Correct. That’s exactly because of what I explained. Because you only have 1 reference that is repeated over and over on each row. You have to decouple them by using the index. From what I can see wouldn’t it be enough to have toggle-i=!toggle-i ? You just need to store a different reference for each of your flags, right? Why do you need the array? I would replace all the occurrences of toggle[total.projectGroup] with toggle-i. Unless I’m missing some detail. – Hugo Noro Jan 30 '18 at 23:03
  • I get this error : compiler.es5.js:21663 Uncaught Error: Cannot assign to a reference or variable! – ljs Jan 30 '18 at 23:25
  • On which line is that happening? – Hugo Noro Jan 30 '18 at 23:27
  • Sorry, this error shows in the console when the page loads. `compiler.es5.js:21663 Uncaught Error: Cannot assign to a reference or variable! at _AstToIrVisitor.webpackJsonp.../../../compiler/@angular/compiler.es5.js._AstToIrVisitor.visitPropertyWrite (compiler.es5.js:21663) at PropertyWrite.webpackJsonp.../../../compiler/@angular/compiler.es5.js.PropertyWrite.visit (compiler.es5.js:2765)` – ljs Jan 30 '18 at 23:36
  • Sorry I think I had bad syntax. The issue of coding on a text editor on a phone :). I have edited my answer. Have a look so basically the toggle variable is defined as an array and we will be storing the event references on each index of the array. Also make sure you don’t have a property with the same name on the component – Hugo Noro Jan 30 '18 at 23:48
  • Sorry, that doesnt work either. I added `toggle:any[];'` in the component file and `(click) = “toggle[i] = !toggle[i]”` in the html file. The error is ` ERROR TypeError: Cannot read property '0' of undefined` on the line ` ` I dont have other propertiers with the name toggle – ljs Jan 30 '18 at 23:59
  • Of course because you set it in the component and did not initialize it. To keep what you have just to toggle: Array = []; This will initialize the array. Or toggle: number[] = [] if you prefer – Hugo Noro Jan 31 '18 at 00:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164216/discussion-between-ljs-and-hugo-noro). – ljs Jan 31 '18 at 00:07
  • Updated my answer. There was an additional issue with the second loop – Hugo Noro Jan 31 '18 at 00:51
  • In addition to displaying all products on the page, I have a select dropdown to just show the individual product’s details. Lets say in the first page, I expanded the first product. And then I go to the dropdown and select a product, so it displays that product’s details along with the inner table expanded - but with the details of the product expanded in the first page. I need to click on the link to get the correct product details -bcoz we do the hide and show on (click) event. So my question is -Is there a way to always collapse the link when going to a new page? – ljs Feb 04 '18 at 20:01
  • I reckon this is a good enough question to a question of itself and not mix with the previous one. Reason for the suggestion is that it helps people when looking for specific problems to have them split in questions instead of one massive question solving tones of problems. – Hugo Noro Feb 04 '18 at 20:04
  • Asked here: https://stackoverflow.com/questions/48612607/hiding-an-element-on-page-load – ljs Feb 04 '18 at 20:20