-1

I have the following html snippets

<ul>
    <li *ngFor="let report of searchResult.reports let i = index;">
       <input type="checkbox" [(ngModel)]="report.reportChecked" (click)="selectedReport(report, i)">
       <p kf-text weight="heavy" [ngClass]="{'bgColor': showBgd}">{{ report.name }}</p>
    </li>
</ul>

And

<ul>
  <li *ngFor="let language of languages" (click)="selectedLang(language)">
     {{ language.name }}
  <li>
<ul>

When I click on a particular report or reports and then select a language, I need to add the class bgColor to the report or reports which does not have that language.

Example: I have 3 reports: Report 1(english) , Report 2(spanish) , Report 3(english, french)

And 3 languages: English, Spanish, French

If i check Report 1 and Report 2 which are available only in English and Spanish respectively and from the drop down I choose the language English, the class bgColor needs to be added to Report 2 as it is not available in the chosen language, in this case english. If I check Report 1 and Report 3 and language spanish is chosen, the class bgcolor needs to be added to both Report 1 and Report 3 elements. If English was chosen, the class will not be added to any element since both are available in english. Bottom line, whichever report is checked, if it is not available in the chosen language, the class bgColor is to be added. If it is available class will not be added. Reports can be checked or unchecked at will.

The following is the typescript snippet

selectedReport(report, index) {
    if(report.reportChecked) {
        this.selectedReports.push({
            type: report.type,
            name: report.name,
            reportChecked: report.reportChecked
        });
        this.indexItems.push(index);
    } else {
        this.selectedReports = _.reject(this.selectedReports, (el) => {
            return el.type === report.type;
        });
        let indexRemove = this.indexItems.indexOf(index);
        if(indexRemove > -1) {
            this.indexItems.splice(indexRemove, 1);
        }
    }
}

selectedLang(language) {
        let reportType;
        let reportLanguage;
        this.selectedLanguage = language;
        this.selectedReports.forEach((report) => {
            if (report.reportChecked) {
                reportType = this.reportsWithLang.find((checkedReport) => {
                    return checkedReport.type === report.type;
                });
                reportLanguage = reportType.languages.find((language) => {
                    return language.id === this.selectedLanguage.id;
                });
                if(!reportLanguage) {
                    this.showBgd= true;
                } else {
                    this.showBgd= false;
                }
            }
        });
    }

In my current implementation, When Report 1 is checked and language English is chosen the bgColor class is not added. But if language other than English, example, spanish is chosen the bgColor class is added to all report elements even though only Report 1 is checked. Again keeping Report 1 checked and language chosen as spanish, if Report 2 is now checked, the class bgColor is removed from all elements although the class should be added to Report 1 element. I tried a lot of different ways but still could not come up with a solution. Any help on this will be mightily appreciated.

yugrac
  • 73
  • 1
  • 5

1 Answers1

0

The main problem is that showBgd is a component function, so it is a single value that is the same for all instances in the list. Ideally, you would assign a showBgd for each report in the selectedLang function and selectedReport function, but you are not referencing the same objects (which might also be true with the reportsWithLang and searchObject.reports.

So the best way to do this is probably to use a reportHasLanguage function to calculate for each listItem where the background color should show.

In your view, change

[ngClass]="{'bgColor': showBgd}"

to

[ngClass]="{'bgColor': reportHasLanguage(report, selectedLanguage)}"

then, in your component, add a function:

reportHasLanguage(report, language) {
    // logic that can determine from a specific report object and the 
    // component level selectedLanguage object whether the BG Color
    // should be on
    return true; // for BG color on, false for off
}

I would fill in that logic for you, but I'm not sure what it is -- I don't know how the objects are constructed or how you have built the reportsWithLang object or the searchObject.reports object.

RE Comments Below: It might be easier to simplify the internal logic with something that tracks the selected objects by collection (rather than a flag on the object. If you do that, you can do something like:

toggleReportSelected(report) {
    let idx = this.selectedReports.indexOf(report);
    if (idx < 0) this.selectedReports.push(report)
    else this.selectedReports.splice(idx,1)
}
findReports(searchParams) {
    this.foundReports = this.reports.find( report) => {
         return // logic matching report to searchParams
    });
}
reportIsSelected(report) {
    return this.selectedReports.indexOf(report) >= 0;
}

This approach allows you to use whatever trigger you want to toggle a report selected or not and you can always access all the properties of the selected report within the collections that your application is using. You can also tie a checkbox value to reportIsSelected if you want, or you can use other fancier ways of showing that it is selected.

Beartums
  • 1,340
  • 1
  • 10
  • 15
  • I made the changes you suggested in the if else condition and in the view, but not the bgColor class is not added under any situation. The reason being i think, the report.showBgd property cannot be binded to the view. If you see the selectedLang function, notice that I am looping through the object this.selectedReports which was created in the selectedReport function. But to list the reports in the view, the object used is this.SearchResult.reports. – yugrac Jun 14 '18 at 09:39
  • You are absolutely correct. I missed that. You can fix that by either simply pusing the reports into selectedReports (rather than creating a new object). I will update the answer. – Beartums Jun 14 '18 at 10:03
  • @yugrac, I'm not sure if this will work either, since you also have a collection of `reportsWithLang` and that might be using either type of object. In fact, it looks like it is using the object created in the selectedReport function, which will render this answer invalid. I will create another one – Beartums Jun 14 '18 at 10:12
  • I am thinking I might not even need to create the selectedReports object and instead, I can completely rely on searchResult.reports. I am already using the condition report.reportChecked which will verify which reports i select anyway.If that is so I think selectedReports object might not be needed. – yugrac Jun 14 '18 at 10:19
  • I think you are right, though I'm not sure from your comment. There are a lot of ways to do this. Ideally, I find it best to have a base reports collection, which will reference all the available reports, a foundReports collection which reference all the reports that match this current search, a selectedReports collection which references all the selected reports (without having to worry about a check-box value. I'll add some to the answer to elucidate – Beartums Jun 14 '18 at 10:37
  • The solution you provided partially worked but it gave me the proper ideas as to how to approach this problem. You were right when you mentioned that it is best practice to have a base collection of the items i am trying to get and loop through. Using part of the answer you provided and also getting some ideas from your comments, I was able to solve this problem. Thanks a lot. Would not have been able to solve it without your ideas. :) – yugrac Jun 25 '18 at 02:42
  • @yugrac, glad I could help! – Beartums Jun 25 '18 at 09:51