title: How to implement a draggable div in Angular 2 using Rx
body: <p>I've been trying to get a draggable div working using Angular 2.  I'm using <a href="https://github.com/AngularClass/angular2-examples/blob/master/rx-draggable/directives/draggable.ts" rel="noreferrer">this example from the angular2-examples repo</a> as a starting point, only really adjusting the code to account for the removal of the <code>toRx()</code> method.  The code works, but it does not account for <code>mouseout</code> events.  This means that if I click on a Draggable div, and move the mouse <em>slowly</em>, the div will move with the mouse.  But if I move the mouse too fast, a <code>mouseout</code> event is sent instead of a <code>mousemove</code> event, and the dragging stops.</p>
  
  <p>How can I keep the drag going after the mouse is moved so far that a <code>mouseout</code> event is fired?  I've tried merging the <code>mouseout</code> event stream with the <code>mousemove</code> one, so that <code>mouseout</code> events are treated just like <code>mousemove</code> ones, but that doesn't work.</p>
  
  <p>I'm using Angular 2.0.0-beta.12.</p>
  
  <pre class="lang-js prettyprint-override"><code>import {Component, Directive, HostListener, EventEmitter, ElementRef, OnInit} from 'angular2/core';
  import {map, merge} from 'rxjs/Rx';
  
  @Directive({
      selector: '[draggable]'
  })
  export class Draggable implements OnInit {
  
      mouseup = new EventEmitter();
      mousedown = new EventEmitter();
      mousemove = new EventEmitter();
      mouseout = new EventEmitter();
  
      @HostListener('mouseup', ['$event'])
      onMouseup(event) {
          this.mouseup.emit(event);
      }
  
      @HostListener('mousedown', ['$event'])
      onMousedown(event) {
          this.mousedown.emit(event);
          return false; // Call preventDefault() on the event
      }
  
      @HostListener('mousemove', ['$event'])
      onMousemove(event) {
          this.mousemove.emit(event);
      }
  
      @HostListener('mouseout', ['$event'])
      onMouseout(event) {
          this.mouseout.emit(event);
          return false; // Call preventDefault() on the event
      }
  
      constructor(public element: ElementRef) {
          this.element.nativeElement.style.position = 'relative';
          this.element.nativeElement.style.cursor = 'pointer';
  
          map;
          merge;
          this.mousedrag = this.mousedown.map(event =&gt; {
              return {
                  top: event.clientY - this.element.nativeElement.getBoundingClientRect().top
                  left: event.clientX - this.element.nativeElement.getBoundingClientRect().left,
              };
          })
          .flatMap(
              imageOffset =&gt; this.mousemove.merge(this.mouseout).map(pos =&gt; ({
                  top: pos.clientY - imageOffset.top,
                  left: pos.clientX - imageOffset.left
              }))
              .takeUntil(this.mouseup)
          );
      }
  
      ngOnInit() {
          this.mousedrag.subscribe({
              next: pos =&gt; {
                  this.element.nativeElement.style.top = pos.top + 'px';
                  this.element.nativeElement.style.left = pos.left + 'px';
              }
          });
      }
  }
  
  @Component({
      selector: 'my-app',
      template: `
          &lt;div draggable&gt;
              &lt;h1&gt;Hello, World!&lt;/h1&gt;
          &lt;/div&gt;
          `,
      directives: [Draggable,],
  })
  export class AppComponent {
  }
  </code></pre>