question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[bug core] *ngFor + Touch Issue

See original GitHub issue

I’m submitting a …

[x] bug report  

Current behavior

If I drag a component, bound within an *ngFor, (using a touchscreen) and an external event causes the ngFor array to update, touchmove events stop firing. This is a terrible experience on mobile. Angular 2 is nearing official release and I’m concerned how to fix the mobile experience. Mouse dragging does not have this issue.

E.g. I have a data array, currentBookings = [{..}, {..}], that is bound with an *ngFor such as

<booking *ngFor="let booking of currentBookings"></booking>

and I drag one of the generated <booking> components to the ‘nextDay’ button, which causes the currentBookings array to update. See this Plunker

  • I have dealt with this (Touch Spec / Browser Implementation) issue in the past (vanilla JS) by simply keeping the DOM element reference around until the touchend or touchcancel event fire.
  • However, Angular controls the DOM now !
  • Could this be solved by Angular implementing a canDestroy() Component guard (i.e not route guard) ???

Expected/desired behavior

A canDestroy() Component guard. Or any solution that avoids premature DOM removal of an element. Angular could keep the DOM element in memory and set a style of {display: none;}. Anything to improve the drag experience on mobile…which is pretty important in my opinion.

Reproduction of the problem

See this Plunker. Note: Touchscreen required (or Chrome Dev Tools mobile emulation)

What is the expected behavior?

In my Plunker, I expect the touchmove events to keep firing after dragging the ‘booking’ to the next/prev day. It works as expected with mouse dragging.

What is the motivation / use case for changing the behavior?

Improve the mobile experience of Angular 2.

Environment:

  • Angular version: 2.0.0-rc.4
  • Browser: [Chrome 51 (with touchscreen), iOS 9.3.2 Safari]
  • Language: Typescript@1.9.0-dev.20160409 see plunker

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:5
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
dharderscommented, Aug 16, 2016

Found a workaround:

TouchEvents do actually continue to fire after DOM removal BUT they are only targeted at the node/element that the original touchstart occurred on and don’t bubble (unlike MouseEvents, which is confusing!).

So, we cant perform a simple @HostListener('touchmove', ['$event']) and expect it to work with DOM removal (as the event listener is attached to the outer component element). We have to dynamically add event listeners to the target element of the touchstart event as they occur. Then perform cleanup on touchend or touchcancel (or ngOnDestroy()).

Solution:

@HostListener('touchstart', ['$event'])
@HostListener('mousedown', ['$event'])
  onStart(event) {
    if (event.touches) {                      // only for touch
      this.removePreviousTouchListeners();    // avoid mem leaks      
      this.touchmoveListenFunc = this.renderer.listen(event.target, 'touchmove', (e) => { this.onMove(e); });
      this.touchendListenFunc = this.renderer.listen(event.target, 'touchend', (e) => { this.removePreviousTouchListeners(); this.onEnd(e); });
      this.touchcancelListenFunc = this.renderer.listen(event.target, 'touchcancel', (e) => { this.removePreviousTouchListeners(); this.onEnd(e); });
    }
   ...
}

removePreviousTouchListeners() {
    if (this.touchmoveListenFunc !== null)
      this.touchmoveListenFunc();             // remove previous listener
    if (this.touchendListenFunc !== null)
      this.touchendListenFunc();              // remove previous listener
    if (this.touchcancelListenFunc !== null)
      this.touchcancelListenFunc();           // remove previous listener

    this.touchmoveListenFunc = null;
    this.touchendListenFunc = null;
    this.touchcancelListenFunc = null;
  }

 @HostListener('mousemove', ['$event'])
  // @HostListener('touchmove', ['$event'])    // don't declare this, as it is added dynamically
  onMove(event) {
    ...   // do stuff with event
  }

@HostListener('mouseup', ['$event'])
  // @HostListener('touchend', ['$event'])     // don't use these as they are added dynamically
  // @HostListener('touchcancel', ['$event']) // don't use these as they are added dynamically
  onEnd(event) {
    ...  // do stuff
  }

 ngOnDestroy() {
   this.removePreviousTouchListeners();

Don’t forget to inject Renderer in the constructor (import from @angular/core

Source https://plus.google.com/+RickByers/posts/GHwpqnAFATf

0reactions
dharderscommented, Oct 6, 2016

@vicb listed above http://plnkr.co/edit/QR6WDzv6NxOmn6LXTngG?p=preview

See my above workaround too.

If #10834 gets implemented, this issue would go away.

Read more comments on GitHub >

github_iconTop Results From Across the Web

ngFor nor recognizing object properties - Stack Overflow
I'm following this tutorial (I set the time to be where my problem starts). I have a problem locally when he removes all...
Read more >
Ngfor in element 'e-series-collection', data dynamic - Syncfusion
So my 'API' returns an 'Array' (1 array with N arrays inside). I tried to apply *ngFor on the 'e-series-collection' property, but without ......
Read more >
NgModule FAQ - Angular
This error often means that you haven't declared the directive "x" or ... access to the Angular directives every application needs, such as...
Read more >
Grid auto generated columns with locked checkbox column
Hi,I have this grid markup with auto generated columns by ngFor. ... But I need to make checkbox by default sticky (locked) and...
Read more >
@syncfusion/ej2-angular-base | Yarn - Package Manager
common. Bug Fixes. Grouped radio button ngModel binding. ngFor directive not working for component child directive. ... 15.4.21-preview (2017-12-08). common. Bug ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found