1

I am having an issue that under a specific scenario, I need to click twice in order to trigger the (click) event on a DIV in my Angualar 6 component.

I realize that it would probably be more helpful to provide some example code. But the number of code segments needed to properly convey and the need to sanitize would just be too much to include and I fear too much to digest and may not even prove to be reproducible for anyone anyhow. So I am going to try to describe what I am doing and the things that I have tried so far in hopes that someone might be able to point me in the right direction or give me some additional ideas on what to look for.

My application is a search engine which upon returning and displaying the results also displays a list of facets to further narrow the results by. For example, a facet might include a list of relevant categories with a checkbox next to each one. When a user selects the checkbox the search results are narrowed to only show the results that meat the selected category. The facet lists are only built once with the initial search and remain constant until a brand new search is done. A user can then click on a result item to navigate to a details page showing a finer level of detail about the result item they have selected.

The facets are displayed with the following HTML template snippet:

<div class="facet-spacer-top"></div>
            <ng-container *ngIf="facets">
                <ng-container *ngFor="let facet of facets; let index = index">
                    <ng-container *ngIf="facet.isFacetList()">
                        <facet-list-comp [facet]="facet" [facetIndex]="index" (facetChangeEvent)='onFacetChange($event)'></facet-list-comp>
                    </ng-container>
                    <ng-container *ngIf="facet.isFacetDateRange()">
                        <facet-date-range-comp [facet]="facet" (facetChangeEvent)='onFacetChange($event)'></facet-date-range-comp>
                    </ng-container>
                </ng-container>
            </ng-container>

The search results are displayed with the following HTML template snippet:

 <div *ngFor="let rowNum of results | rows:3; let idx=index;" class="row result-row no-gutter">
                    <div *ngFor="let result of results | slice:(idx*3):((idx+1)*3); let jdx=index;" class="col-md-4">
                        <ng-container *ngComponentOutlet="getResultComponent(); injector: getProvider(result, (idx * 3) + jdx);"></ng-container>
                    </div>
                </div>

The results are added dynamically so that the correct component type for the particular result can be used to display the result. For example our results might include bicycles and cars. The component that we use to display the bicycle result would be different than the component we use to display the car result.

The interesting thing is that this all works wonderfully and when no facet value is selected to pair down the results a single click on a search result item will open the detail as expected. However, if a user selects a facet (such as selecting a category). Then when a user clicks on a resultant result the first time nothing happens. However if the user persists and clicks again, the detail opens as expected. Testing has revealed that if user actually clicks anywhere on the page and then clicks on the result then detail will open as expected. So it is almost like the page needs to regain "focus". It is odd.

So far, I have tried to abandon the Angular (click) event binding for getting a handle DOM HTML element and attaching the event myself. I have tried to programmaticly set the focus to an element on the page after the results have loaded. I have tried to programmaticly click on a DIV element on the page after the search results have loaded. All of these things resulted in the same behavior.

I have attempted to debug, but it is a nightmare trying to step through this Angular and zone.js code!!! I have set break points on the function that gets called in my code when a user clicks on the search result. It is never reached on that first click. Only on the second click. So it seems like this issue is happening somewhere in Angular or maybe zone.js. This might be a red herring, but it does seem like when I try to walk through the code in the debugger that the event is getting lost in zone.js. But I am not for certain.

I know this is not ideal and possibly too abstract, but I am out of ideas. So please any ideas you have would be greatly appreciated!

khpremier
  • 83
  • 1
  • 2
  • 8
  • 6
    Just some possible issues. The `*ngFor` elements get reset when you click, therefore not registering. See this [answer](https://stackoverflow.com/a/45391247/3106920) to add a `trackBy` to both your `*ngFor`. Another issue is that the handler is somehow running outside the zone. Use `ngZone.run()` to get it back in the zone. Check with `NgZone.isInAngularZone()` – Poul Kruijt Jul 10 '18 at 17:51
  • Thank you so much for taking the time to read my question and providing some places to look. I forgot to mention that I did look at the NgZone.isInAngularZone() and ngZone.run(). I was a little confused by them, Where would I call ngZone.run()? Would I put that in my component or in the child serahc result components and when in the lifecycle would I want to call that? Would I call it with no parameters? Thank you! – khpremier Jul 10 '18 at 18:05
  • It could be that the facetChangeEvent is running outside of angular.. or somehow your click event is. But in your html snippet I see no click event handling. The ngZone.run() should be called with an anonymous function handling the click event, and what you want to do after. There are a lot of examples on Google how to :) but I should start with the ngFor, my guess is that the issue is there – Poul Kruijt Jul 10 '18 at 18:15
  • I tried trackBy to see if it would fix my problem, but I had the same issue after implementing. I tried to just use the id from the result I was displaying as the trackBy value. Then I attempted to append a date timestamp for the search that generated the results to see if that made a difference. Neither worked and both resulted in the same issue with having to click twice. BTW.. For anyone following along, the trackBy function does not bind to the component object so "this" is might not be what you think :-). I will read up on Zones next and see if that fixes my problem. Thank You! – khpremier Jul 11 '18 at 12:46
  • I had the same problem and trackBy method fixed it – Rom1 Dec 13 '19 at 12:55

1 Answers1

0

It appears that this has been a complete red herring. The issue does not appear to have anything to do with the dynamically added components, but with the facet, which is a checkbox, itself.

I am still not sure what the issue is but this question and thread does not appear to relevant any longer to the issue that I am having.

Thanks everyone!

khpremier
  • 83
  • 1
  • 2
  • 8