Hace poco publiqué este artículo donde creé una sencilla librería para drag&drop con Angular.

La solución es válida, pero tiene un problema. Recordemos su código fuente:

/** Imports y declaración de la directiva **/
export class AsbDraggableDirective implements OnChanges {
/** Bindings y listeners **/

  constructor (private element: ElementRef, @Attribute('asbDraggableType') private draggableType) {
    this.nativeElement = element.nativeElement;
  }

  ngOnChanges (changes: { [propName: string]: SimpleChange }) {
    let change: SimpleChange = changes['isDraggable'];

    if (change && change.currentValue) {
      this.nativeElement.setAttribute('draggable', 'true');
    } else {
      this.nativeElement.setAttribute('draggable', 'false');
    }
  }
}

¿Qué sucede cuando el método ngOnChanges de esta directiva se invoca en un contexto donde no hay DOM? Por ejemplo, en un Web Worker o en Angular Universal. Ya te digo yo lo que sucede: que peta. Si nos fijamos, hay un vínculo fuerte entre nuestra directiva y un elemento nativo.

Veamos pues la manera de atajar este problema. Es algo que solucionaremos mediante el uso de la clase Renderer. Ésta nos permite reducir el acoplamiento, ya que se interpone entre nuestra directiva y el DOM, y nos abstrae de la presencia o no de éste.

Entonces, la solución al problema es la siguiente:

/** Imports y declaración de la directiva **/
export class AsbDraggableDirective implements OnChanges {
  /** Bindings y listeners **/

  constructor(private element: ElementRef,
@Attribute('asbDraggableType') private draggableType,
private renderer: Renderer) {
  }

  ngOnChanges(changes: { [propName: string]: SimpleChange }) {
    let change: SimpleChange = changes['isDraggable'];

    if (change && change.currentValue) {
      this.renderer.setElementAttribute(this.element.nativeElement, 'draggable', 'true');
    } else {
      this.renderer.setElementAttribute(this.element.nativeElement, 'draggable', 'false');
    }
  }
}

Puedes ver el código fuente completo aquí. Recuerda que la librería se encuentra disponible en npm.

Anuncios