2016-03-01 28 views
9

Mi chiedevo se avrei potuto ottenere aiuto in merito agli eventi per dispositivi mobili. Stavo cercando un modo per legare le funzioni allo swipe degli eventi in Angular 2. Ho visto in questo this issue su Github che menziona che Angular 2 utilizza Hammer.js per la gestione degli eventi mobile.Utilizzo di eventi mobili in Angular2

Sto avendo qualche difficoltà a trovare l'evento a lavorare perché ricevo il seguente errore:

EXCEPTION: Hammer.js is not loaded, can not bind swipeleft event

Un frammento di mio codice è qui sotto:

import {Component, View, AfterContentInit} from 'angular2/core'; 
import {HelperService} from "./helper-service"; 
import {HammerGesturesPluginCommon} from 'angular2/src/platform/dom/events/hammer_common' 

@View({ 
    template: `<div [id]="middleCircle" (swipeleft)="doThis()"></div>` 
}) 

export class ColumnDirective implements AfterContentInit { 
    constructor(private helperService:HelperService) {} 
    doThis(){ 
    console.log('This thing has been done.'); 
    } 
} 

Se aggiungo a Hammer Gesti al mio costruttore, ottengo questo errore:

constructor(private helperService:HelperService, private hammerGesturesPluginCommon: HammerGesturesPluginCommon) {} 

EXCEPTION: No provider for t! (ColumnDirective -> t)

Qualsiasi aiuto con questo problema sarebbe apprezzato!

+0

Ho appena trovato questo thread mentre sto cercando di implementare la stessa cosa. Ti farò sapere se trovo qualcosa. –

+0

Sono riuscito a superare "Hammer.js non è caricato" aggiungendo un tag script per hammer.js al mio index.html (sto usando il progetto angular 2 seed), tuttavia quando faccio scattare un colpo ottengo ora ottieni un elenco enorme di errori attivati ​​a partire da "EXCEPTION: RangeError: superata la dimensione massima dello stack di chiamate". –

+0

Sì, @BillyMayes stesso problema ora. –

risposta

13

Dopo un sacco di armeggiare, non ho avuto successo nel far HammerGesturesPluginCommon di Angular2 al lavoro (finora) . Ispirato dalla risposta di Bill Mayes, sto presentando questo come un'elaborazione della sua risposta che sono riuscito a ottenere (testato su un Ipad mini e un telefono Android).

Fondamentalmente, la mia soluzione è la seguente.

In primo luogo, fare riferimento manualmente hammer.js nei tag di script del file index.html (I Riferimento martello-tempo per eliminare il ritardo 300ms):

In secondo luogo, installare le definizioni di tipo per hammerjs (tsd install hammerjs -save). Quindi è possibile creare una direttiva attibute Angular2 come questo:

/// <reference path="./../../../typings/hammerjs/hammerjs.d.ts" /> 
import {Directive, ElementRef, AfterViewInit, Output, EventEmitter} from 'angular2/core'; 
@Directive({ 
    selector: '[hammer-gestures]' 
}) 
export class HammerGesturesDirective implements AfterViewInit { 
    @Output() onGesture = new EventEmitter(); 
    static hammerInitialized = false; 
    constructor(private el: ElementRef) { 

    } 
    ngAfterViewInit() { 

     if (!HammerGesturesDirective.hammerInitialized) { 

      let hammertime = new Hammer(this.el.nativeElement); 
      hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL }); 
      hammertime.on("swipeup", (ev) => { 
       this.onGesture.emit("swipeup"); 
      }); 
      hammertime.on("swipedown", (ev) => { 
       this.onGesture.emit("swipedown"); 
      }); 
      hammertime.on("swipeleft", (ev) => { 
       this.onGesture.emit("swipeleft"); 
      }); 
      hammertime.on("swiperight", (ev) => { 
       this.onGesture.emit("swiperight"); 
      }); 
      hammertime.on("tap", (ev) => { 
       this.onGesture.emit("tap"); 
      }); 

      HammerGesturesDirective.hammerInitialized = true; 
     } 


    } 
} 

È necessario impostare Hammer.DIRECTION_ALL se si desidera rilevare verticale (su/giù) colpi (sinistra/destra sono colpi di default, non verticale).Altre opzioni possono essere trovati sulle API martello qui: http://hammerjs.github.io/api/#hammer

Infine, nel componente genitore si può fare qualcosa di simile:

import {Component} from "angular2/core"; 
import {HammerGesturesDirective} from "./path/HammerGesturesDirective"; 

    @Component({ 
     selector: "my-ng2-component", 
     template: `<div style='width:100px; height: 100px;background-color: red' 
      (onGesture)="doSwipe($event)" hammer-gestures></div>`, 
     directives: [HammerGesturesDirective] 

    }) 
    export class MyNg2Component { 
     constructor() { } 

     doSwipe(direction: string) { 
      alert(direction); 
     } 

    } 

In questo modo è sufficiente fare riferimento all'attributo martello gesti quando vuoi abilitare i movimenti del martello su un particolare elemento. Nota: l'elemento sembra aver bisogno di un ID univoco per funzionare .

+2

Non l'ho ancora provato, ma l'idea mi piace così tanto che ho detto "cool" ad alta voce in ufficio. Sembra pulito –

+0

risposta ben spiegata :) +1 –

+0

Ho trovato che aggiungendo questa direttiva a più elementi nel mio componente, a causa della proprietà statica 'hammerInitialized', solo il primo elemento era cablato. Ho rimosso l'assegno e sembra funzionare meglio per me. (anche ad alta voce "cool") – GaryB96

0

è necessario aggiungere

HelperService e HammerGesturesPluginCommon ai fornitori da qualche parte, sia nella @Component(...) annotazione o in bootstrap(AppComponent, [...]) di sbarazzarsi di l'errore "Nessun provider per ..."

Hai aggiungere uno script tag per Hammer.js da qualche parte sulla tua pagina di ingresso?

+0

Ho aggiunto un 'provider: [HammerGesturesPluginCommon]' al mio '@ Componente' e incluso Hammer.js in un tag script da un cdn, ora sto superando la dimensione massima dello stack delle chiamate, sembra che siamo più vicini! –

+0

Forse https://github.com/angular/angular/issues/5964 o https://github.com/angular/angular/issues/5964 forniscono alcune informazioni. Da quello che ricordo è di non aggiungere esplicitamente 'zone.js' (non mi sono imbattuto in questo problema da solo, ricordo solo di aver visto le discussioni e non so se questo è ancora attuale). Potrebbe anche essere un problema con l'ordine dei tag dello script. –

2

sono stato in grado di ottenere qualcosa di lavoro bypassando il built-in di integrazione e del martello in esecuzione il mio:

import { Component, ElementRef, AfterViewInit } from 'angular2/core'; 

@Component({ 
    selector: 'redeem', 
    templateUrl: './redeem/components/redeem.html' 
}) 
export class RedeemCmp implements AfterViewInit { 

    static hammerInitialized = false; 

    constructor(private el:ElementRef) { } 

    ngAfterViewInit() { 
     console.log('in ngAfterViewInit'); 
     if (!RedeemCmp.hammerInitialized) { 
      console.log('hammer not initialised'); 

      var myElement = document.getElementById('redeemwrap'); 
      var hammertime = new Hammer(myElement); 
      hammertime.on('swiperight', function(ev) { 
       console.log('caught swipe right'); 
       console.log(ev); 
      }); 

      RedeemCmp.hammerInitialized = true; 
     } else {    
      console.log('hammer already initialised'); 
     } 
    } 
} 
+0

Sembra un'idea molto migliore. Dal momento che siamo ancora in beta, molte cose sono ancora abbastanza buggy. Grazie per l'aiuto! –

+0

@BillMayes molte grazie. Ho elaborato la tua risposta sotto – brando

+0

Usando RC1 si dice che Hammer mi dà erori alla riga 'var hammertime = new Hammer (myElement);' - Hammer non definito. Qualche idea su cosa è cambiato in RC1? – LorDex

3

Ero un po 'titubante nell'aggiungere gesti di scorrimento alla mia applicazione perché le risposte qui sembravano suggerire che sarebbe stato un po' complicato.

EXCEPTION: Hammer.js is not loaded, can not bind swipeleft event

Questo errore può essere facilmente risolto semplicemente caricando hammer.js. Nessun codice personalizzato necessario.

L'altro errore menzionato nei commenti sembra essere stato un errore risolto a rc1.

1

"ECCEZIONE: Hammer.js non è caricato, non è possibile associare l'evento di swipeleft" viene generato perché hammerjs deve essere incluso nella pagina.

Esempio: < script src = "node_modules/hammerjs/hammer.js" > </script >

Ho letto tutte le altre risposte su come utilizzare hammerjs con angolare e sembrano hacky. Per impostazione predefinita HammerJs ha disabilitato i metodi SwipeDown e SwipeUp. Tutte le risposte precedenti non sono giuste angolari2 modo dattiloscritto per risolvere i problemi di gesti o sovrascrivere le impostazioni predefinite del martello. Mi ci sono volute circa 4 ore di scavo in angular2 e hammerjs commette.

Qui sono:

La prima cosa che abbiamo bisogno sono tipizzazioni hammerjs per angular2.

typings install github:DefinitelyTyped/DefinitelyTyped/hammerjs/hammerjs.d.ts#de8e80dfe5360fef44d00c41257d5ef37add000a --global --save 

Successivamente è necessario creare la nostra classe di configurazione prioritaria personalizzata. Questa classe può essere utilizzata per sovrascrivere tutte le impostazioni di configurazione predefinite di hammerjs e angular2 hammerjs.

hammer.config.ts:

import { HammerGestureConfig } from '@angular/platform-browser'; 
import {HammerInstance} from "@angular/platform-browser/src/dom/events/hammer_gestures"; 


export class HammerConfig extends HammerGestureConfig { 

    buildHammer(element: HTMLElement): HammerInstance { 
     var mc = new Hammer(element); 

     mc.get('pinch').set({ enable: true }); 
     mc.get('rotate').set({ enable: true }); 

     mc.add(new Hammer.Swipe({ direction: Hammer.DIRECTION_ALL, threshold: 0 })); 

     for (let eventName in this.overrides) { 
      mc.get(eventName).set(this.overrides[eventName]); 
     } 

     return mc; 
    } 
} 

L'ultima cosa che dobbiamo fare, è quello di aprire il nostro file di bootstrap principale e inserire il nostro configurazione personalizzato in metodo bootstrap come questo:

// ... other imports ... 
import { HammerConfig } from './shared/hammer.config'; 

bootstrap(AppComponent, [ 
    provide(HAMMER_GESTURE_CONFIG, { useClass: HammerConfig }) 
]); 

Ora nella nostra applicazione possiamo usare swipeDown e swipeUp

<div class="some-block" (swipeDown)="onSwipeDown"></div> 

Questa richiesta di pull abilitata overr Iding di impostazioni predefinite e mi ha dato il punto di partenza per trovare modo giusto:

https://github.com/angular/angular/pull/7924

5

Bene, molto tempo dopo il PO, ma se hai solo i requisiti semplici e non si vuole fare muck con hammer.js , ecco uno swiper orizzontale di base. Basta inserire un componente e aggiungere le proprie funzioni doSwipeLeft e doSwipeRight.

touch1 = {x:0,y:0,time:0}; 

    @HostListener('touchstart', ['$event']) 
    @HostListener('touchend', ['$event']) 
    //@HostListener('touchmove', ['$event']) 
    @HostListener('touchcancel', ['$event']) 
    handleTouch(ev){ 
    var touch = ev.touches[0] || ev.changedTouches[0]; 
    if (ev.type === 'touchstart'){ 
     this.touch1.x = touch.pageX; 
     this.touch1.y = touch.pageY; 
     this.touch1.time = ev.timeStamp; 
    } else if (ev.type === 'touchend'){ 
     var dx = touch.pageX - this.touch1.x; 
     var dy = touch.pageY - this.touch1.y; 
     var dt = ev.timeStamp - this.touch1.time; 

     if (dt < 500){ 
     // swipe lasted less than 500 ms 
     if (Math.abs(dx) > 60){ 
      // delta x is at least 60 pixels 
      if (dx > 0){ 
      this.doSwipeLeft(ev); 
      } else { 
      this.doSwipeRight(ev); 
      } 
     } 
     } 
    } 
    } 
Problemi correlati