Angular.js: ngClick usando ngTouch dispara duas vezes

Criado em 14 fev. 2014  ·  67Comentários  ·  Fonte: angular/angular.js

Lots of comments ngTouch moderate broken expected use bug

Comentários muito úteis

Eu também tive esse problema em que sempre que chamei uma função de escopo, ela foi disparada duas vezes e, embora você possa fazer uma solução alternativa como sugeriu @tcarlsen , ter que fazer isso para cada chamada de função seria muito tedioso, desnecessário e lento.

Felizmente, descobri que o angular-material tem um método click Hijack, e você pode desligá-lo.

Para desativar o sequestro de clique do angular-mateiral, você só precisa colocar isso em seu arquivo de configuração:

.config(function( $mdGestureProvider ) {
    $mdGestureProvider.skipClickHijack();
  });

Venho testando essa solução e ela parece resolver o problema. No entanto, só tentei com ng-click. Não tenho certeza de como isso afetará quaisquer outros gestos de material angular, mas, por enquanto, minhas funções estão sendo chamadas apenas uma vez :)

Todos 67 comentários

Também estou passando por momentos difíceis com esse problema.

Alguma ideia do que está causando isso e se há uma solução alternativa que eu possa usar?

Acho que é algo relacionado à propagação do evento, esta é minha solução alternativa:

http://jsfiddle.net/coma/2hWWa

Eu tenho um problema similar.

Meu aplicativo tem uma caixa de diálogo pop-up com um botão que o fecha. Quando o botão da caixa de diálogo está no topo de um elemento de entrada de texto, clicar no botão em dispositivos com tela de toque não apenas fecha a caixa de diálogo, mas também focaliza a entrada.

O mesmo problema aqui usando angular com toque angular 1.2.9.

Não há nenhum outro elemento clicável na árvore para o qual se propagar. O evento _very same_ click é disparado duas vezes seguidas. Isso não acontece com os furtos. Além disso, o problema de disparar eventos ngClick duas vezes desaparece quando removo o ngTouch do projeto.

Também estou tendo esse problema no ngTouch 1.2.13,

Dependendo da situação, isso é mais do que um bug ótico, mas no meu caso leva a problemas de usabilidade irritantes:

Por exemplo, eu mudo uma Visualização com ngTouch ativado e com ng-click em um dispositivo de toque para abrir um modal, que fica acima do elemento clicado. Dentro deste modal, um elemento clicável está no mesmo lugar que o elemento clicado anteriormente (agora colocado acima), então pode ocorrer que o segundo evento seja disparado e o botão no modal seja clicado / disparado.

Isso pode levar a um comportamento indesejado do aplicativo.

Olá, Richard, este é exatamente o mesmo tipo de problema que estamos enfrentando.

Faça referência a jquery (antes do angular.js) para interromper a propagação do evento e evitar disparos duplos.

Isso não parece uma solução. Não usamos jQuery em nosso aplicativo. Esta string está dizendo que isso não será tratado antes de 1.3?

Este problema está tornando ngClick inutilizável. Como as pessoas estão trabalhando em torno disso? Debounce? Fallback para o ngClick original?

Eu adicionei ngTouch para obter a funcionalidade de deslizar e agora estou com esse problema.

Estamos executando nosso próprio fork do ng-touch com as alterações em https://github.com/angular/angular.js/pull/6995
Além disso, já vi projetos fazendo depuração manual em que cliques a aproximadamente 200ms um do outro são desconsiderados.

Também estou enfrentando esse problema. A solução alternativa de @coma parece ter corrigido isso.

Acredito que esse mesmo problema já foi corrigido no fastclick: emitir e corrigir .

comecei a usar o material angular e me deparei com esse problema, pois o material inclui ária.

+1 usando material bem como tendo o mesmo problema.

alguma atualização para este problema? e há uma solução alternativa? Estou usando o ngtouch 1.3.14 e ainda estou tendo esse problema

+1

Alguma atualização sobre este problema? Desenvolver um aplicativo usando material angular e funciona muito bem no desktop, mas no celular ng-click registra duas vezes.

No meu caso, o jquery (como uma dependência do ui-calendar) causou esse problema. não consegui encontrar uma solução ...

+1

+1

Com mais de 2 commits, adicionado algum tipo de efeito de debounce. O valor limite definido corrige meus problemas de disparo do ngTouch duas vezes, por favor, teste e veja se ele também funcionou no seu caso.

No GenyMotion em um emulador Android 4.1, sempre recebo event.timeStamp undefined => nenhum salto ocorre.

@mobilabgit Você está sugerindo que a criação manual de timestamps de eventos por meio de new Date() é mais à prova de ambiente do que event.timeStamp .. ??

não sugerindo nada, apenas informando o fato de que na configuração declarada o event.timeStamp retorna undefined.

alguma atualização disso? Isso está causando estragos em meu aplicativo. Menus e botões estão disparando cliques duas vezes.

Eu também estou sofrendo desse problema. o botão disparar ng-click duas vezes .. torna a entrada de dados do aplicativo quase inutilizável no ios, muito frustrante de fato.

@mobilabgit @jgodi @rexebin Vocês estão usando Material Angular por acaso ??

@NorikDavtian sim, e a boa notícia é que eles resolveram o problema em seu branch master .. você pode verificar esses recursos para obter mais informações sobre o problema
https://github.com/angular/angular.js/pull/10766
e este codepen demonstra as diferentes versões ... você pode tentar combiná-las para saber o que está funcionando
http://codepen.io/marcysutton/pen/YPxrLd

por exemplo ngMaterial 0.7.1 com ngAria <2.1.5 não tem o bug ...
esperando por ngMaterial> 0.8.3 (atualmente no master) que também corrigiu o bug

Resolvi o problema removendo o material design 0,83.

Eu também removi bootstrap.js e em seu lugar usando apenas bootstrap ui jus. como resultado, revertendo de volta para um 1.2.28 angular. Apenas no caso de bootstrap ui não funcionar em algum lugar com 1.3.x. Bugs desconhecidos são assustadores.

Eu odiava tanto o bug que também removi o ng-touch.

Agora eu tenho 300 ms de atraso em cliques, mas parece sólido e estável, eu classifico estável em relação ao desempenho panaty pelo atraso.

A depuração de sub iOS Safari não é a melhor experiência de depuração, eu temo. O bug me custa 3 dias de trabalho. Forçou-me a refatorar o código, alterando todos os elementos de design de material para a boa e velha configuração de bootstrap. Na verdade, o Beta não se destina ao uso em produção.

Espero que o acima tenha salvado alguém algum tempo.

-
Enviado da caixa de correio

Na sexta-feira, 27 de março de 2015 à 01h13, Ahmed Abdel Razzak
notificaçõ[email protected] escreveu:

@NorikDavtian sim, e a boa notícia é que eles resolveram o problema em seu branch master .. você pode verificar esses recursos para obter mais informações sobre o problema
https://github.com/angular/angular.js/pull/10766
e este codepen demonstra as diferentes versões ... você pode tentar combiná-las para saber o que está funcionando
http://codepen.io/marcysutton/pen/YPxrLd
por exemplo, o branch master no ngMaterial funciona bem
e ngMaterial 0.7 com ngAria <2.1.5 não tem o bug ...

esperando por ngMaterial> 8.3 (atualmente no master) que também corrigiu o bug

Responda a este e-mail diretamente ou visualize-o no GitHub:
https://github.com/angular/angular.js/issues/6251#issuecomment -86781164

Obrigado @artmees .. Resolver a causa raiz do problema foi uma solução melhor do que adicionar cheques extras em ng touch .. Tudo funcionando agora.

Obrigado @rexebin pela resposta .. Posso me relacionar totalmente, mas não estamos em fase de produção, por isso podemos tolerar alguns bugs aqui e ali. Mas começando a ser mais seletivo com as atualizações de dependências de aplicativos a partir deste ponto.

Eu sou novo no angular e me deparei com esse problema hoje. Acabei de puxar pelo toque angular do caramanchão. Portanto, tenho o mais recente e não está fixo lá. Norik, você pode esclarecer o que devo fazer para que isso funcione nativamente?

@dangros Não é o Angular Touch .. como @artmees mencionou, é a biblioteca Angular Material, mais especificamente as peças de acessibilidade relacionadas ao Aria ..

Mude seu caramanchão angular-material para

"angular-material": "master" ou se você quiser ter certeza de que sua construção não irá quebrar, mude-a para a última versão do commit do mestre atual. Certifique-se de mudar para uma versão estável quando a correção for mesclada em uma nova tag, caso contrário, você sempre estar usando o master, o que pode causar outros problemas no futuro.

Boa sorte.

Não estou usando material angular. Apenas toque angular

Faça essas alterações em seu arquivo ng-touch .. sua versão do bower pode parecer um pouco diferente, mas o conteúdo deve ser o mesmo.
https://github.com/NorikDavtian/angular.js/blob/master/src/ngTouch/directive/ngClick.js

Me avise se funcionar ..
Se o seu problema persistir, terei prazer em fazer uma sessão de tela para diagnosticar seu problema.

Obrigado @NorikDavtian. Eu adorei o Material Design por seu sistema de layout de grade, diretivas, serviços e facilidade de uso e sua filosofia de design. Também adorei a ideia de me livrar do atraso de 300ms. Vou brincar com um novo projeto novamente e ver no que vai dar, mas não com meu projeto principal, pois ele tem um cronograma restrito.

Por favor, corrija-me se eu estiver errado: o atraso de 300ms existirá se usarmos ng-touch ou material design ou não. ng-touch e material design enviarão o clique imediatamente, sequestrarão e interromperão o envio do clique enviado pelo navegador. Ao fazer alterações no ngClick.js no ng-touch ou puxar o ramo principal do material design com correções do ngclick, suponho que também sequestra os hiperlinks normais para que os hiperlinks não cliquem duas vezes.

@rexebin tente usar https://github.com/ftlabs/fastclick para remover o atraso de 300ms se optar por sair do ng-touch, queira ou não queira se quiser um clique super rápido, você tem que alterar o comportamento do navegador nativo , caso contrário, você ficará preso com esse atraso.

Tentei um clique rápido. Ao usá-lo, todos os cliques-ng terão que ter uma classe especial para funcionar corretamente. Caso contrário, pode clicar duas vezes instantaneamente e, em seguida, mais dois 300 ms depois, esperançosamente, interrompido por um clique rápido e um ng-touch etc.

Parece loucura. Vale a pena percorrer todo o trabalho para parar os 300ms pelo design nas telas sensíveis ao toque? Eu acho que depende ..

-
Enviado da caixa de correio

No sábado, 28 de março de 2015 às 10:19, Norik Davtian [email protected]
escrevi:

@rexebin tente usar https://github.com/ftlabs/fastclick para remover o atraso de 300ms se optar por sair do ng-touch, queira ou não queira se quiser um clique super rápido, você tem que alterar o comportamento do navegador nativo , caso contrário, você ficará preso com esse atraso.

Responda a este e-mail diretamente ou visualize-o no GitHub:
https://github.com/angular/angular.js/issues/6251#issuecomment -87200661

Olá a todos, este problema é anterior a ngAria e Angular Material. Houve ng-click problemas com o ngAria no passado, mas eles devem ser corrigidos agora. O Angular Material está sendo atualizado para incluir o angular-ária versão 1.3.15, para que esse bug específico desapareça. Mas considerando que este problema foi aberto em fevereiro de 2014, quaisquer problemas que você possa ter tido com Angular Material não estão relacionados.

Este bug também está causando muitos estragos em meu aplicativo e eu realmente não quero recorrer à diretiva personalizada my-click para a coisa mais básica. Não estou usando bibliotecas Angular Material .. apenas ng-touch. E acabei de atualizar tudo para angular 1.4 angular-touch 1.4 e é muito triste ver que esse bug que afeta tantos não foi corrigido em um lançamento milestone :(

Também sou afetado pelo mesmo problema:

bower deps:

  "dependencies": {
    "angular-animate": "1.3.16",
    "angular-cookies": "1.3.16",
    "angular-touch": "1.3.16",
    "angular-sanitize": "1.3.16",
    "jquery": "2.1.4",
    "angular-resource": "1.3.16",
    "angular-ui-router": "0.2.15",
    "angular-material": "0.8.3",
    "angular": "1.3.16",
    "angular-leaflet-directive": "0.8.2",
    "angular-moment": "0.10.1",
    "ngDialog": "0.4.0",
    "angular-strap": "2.2.4",
    "bootstrap": "3.3.4",
    "angular-carousel": "0.3.10",
    "lodash": "3.9.3",
    "angular-validation-match": "1.5.0",
    "ng-file-upload": "5.0.1",
    "angular-sweetalert": "1.1.0",
    "Leaflet.awesome-markers": "2.0.2",
    "angulartics": "0.18.0"
  },
  "devDependencies": {
    "angular-mocks": "1.3.16"
  },
  "resolutions": {
    "angular": "~1.3.x"
  }

Corri para isso sozinho e estou odiando isso, espero que isso seja corrigido em breve.

Minha solução rápida é fazer com que ng-click use uma função com escopo e faça uma verificação de clique duplo como esta:

doubleClickCheck = false

$scope.toggleShowPct = ->
  if !doubleClickCheck
    $scope.showPct = !$scope.showPct
    doubleClickCheck = true

    $timeout ->
      doubleClickCheck = false
    , 100

@coma Obrigado por sua solução alternativa. Estou usando isso com itens de menu que usam a diretiva de atributo "menu-close". Como posso manter essa funcionalidade com sua solução alternativa?

Ei @jbeuckm! Eu não conheço essa diretiva, algo está vindo de alguma biblioteca bootstrap / material / extravagante?

Ah, sim, acho que vem de uma biblioteca chique: Ionic. Aqui está a diretiva:

https://github.com/driftyco/ionic/blob/master/js/angular/directive/menuClose.js#L1

Eu também tive esse problema em que sempre que chamei uma função de escopo, ela foi disparada duas vezes e, embora você possa fazer uma solução alternativa como sugeriu @tcarlsen , ter que fazer isso para cada chamada de função seria muito tedioso, desnecessário e lento.

Felizmente, descobri que o angular-material tem um método click Hijack, e você pode desligá-lo.

Para desativar o sequestro de clique do angular-mateiral, você só precisa colocar isso em seu arquivo de configuração:

.config(function( $mdGestureProvider ) {
    $mdGestureProvider.skipClickHijack();
  });

Venho testando essa solução e ela parece resolver o problema. No entanto, só tentei com ng-click. Não tenho certeza de como isso afetará quaisquer outros gestos de material angular, mas, por enquanto, minhas funções estão sendo chamadas apenas uma vez :)

O mesmo problema aqui também.

eu tenho um

Já tentei muitas soluções, mas não tive sorte. É um bloqueador em uma seção específica do aplicativo que estou desenvolvendo no momento :(

@DaDanny muito obrigado! Eu tentei o que você disse e funcionou !!

Depois de habilitar este plugin, eu tenho o problema no Android (testado em 4.2.2 e 4.4.4) Quando eu clico nas alterações de layout do botão, há outro evento de clique disparado que me direciona para outro local. Quando removi, o aplicativo do plugin funcionou como deveria.

@sterichards e @Grzegorzsa : Vocês tentaram minha solução que postei acima?

Se você fez isso e a função ainda está disparando duas vezes, certifique-se de não ter os dois

<ion-view ng-controller="MyCtrl">

</ion-view>

e algo como

.state('mystate', {
        url: '/myState',
        templateUrl: 'routes/myview.html',
        controller: 'MyCtrl'
      })

Isso carregará o controlador duas vezes, o que também causará esse problema.

Eu primeiro me certificaria de que não fosse o caso e, em seguida, implementaria minha solução acima.

Felicidades e deixe-me saber se isso ajuda :)

Fiz algumas alterações no ngTouch e ele funciona para meu projeto móvel.
Acho que há alguns bugs no módulo ngTouch.

Basicamente, o ngTouch tenta acionar o evento de clique com o evento touch-end e ignorar o evento de clique.
Mas no dispositivo de toque no evento de toque, ele falha na primeira verificação da posição x, y.

Além disso, se sair tocar> mover> finalizar e tocar novamente na primeira posição de toque, você obterá clique duas vezes!
Isso acontece quando você toca novamente no tempo de PREVENT_DURATION (padrão 2500 ms).
Então, adicionei o evento touchmove para redefinir isso em movimento.

De qualquer forma, espero que alguém precise de ajuda.

diff --git a/src/ngTouch/directive/ngClick.js b/src/ngTouch/directive/ngClick.js
index f352c25..ba74248 100644
--- a/src/ngTouch/directive/ngClick.js
+++ b/src/ngTouch/directive/ngClick.js
@@ -126,13 +126,14 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
     }

     var touches = event.touches && event.touches.length ? event.touches : [event];
+    var realTouch = touches != [event]; // check this is a real touch event
     var x = touches[0].clientX;
     var y = touches[0].clientY;
     // Work around desktop Webkit quirk where clicking a label will fire two clicks (on the label
     // and on the input element). Depending on the exact browser, this second click we don't want
     // to bust has either (0,0), negative coordinates, or coordinates equal to triggering label
     // click event
-    if (x < 1 && y < 1) {
+    if (!realTouch && x < 1 && y < 1) {
       return; // offscreen
     }
     if (lastLabelClickCoordinates &&
@@ -183,12 +184,18 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
     }, PREVENT_DURATION, false);
   }

+  // Global touchmove hander that removes touchcoordinates while moving
+  function onTouchMove(event) {
+    touchCoordinates = []; //reset touch zone
+  }
+
   // On the first call, attaches some event handlers. Then whenever it gets called, it creates a
   // zone around the touchstart where clicks will get busted.
   function preventGhostClick(x, y) {
     if (!touchCoordinates) {
       $rootElement[0].addEventListener('click', onClick, true);
       $rootElement[0].addEventListener('touchstart', onTouchStart, true);
+      $rootElement[0].addEventListener('touchmove', onTouchMove, true);
       touchCoordinates = [];
     }

@wormkid - Estou tendo problemas para identificar o problema aqui. É possível criar um teste de unidade para demonstrar esse problema?

@petebacondarwin - você pode testar ou baixar http://zen-dev.pl/angular-test.html
Se você clicar no texto cinza, ele desaparece, o link abaixo assume o seu lugar e é acionado.
O link está fora da vista angular. Quando o link está dentro da visualização, tudo funciona bem.

@petebacondarwin - Eu fiz jsfiddle.
https://jsfiddle.net/rfz23qgm/5/
Não consigo reproduzir "clique duas vezes na torneira" naquele violino, mas consigo reproduzir "clique duas vezes após rolar".
Estou testando com o iPhone Safari.

  1. Pressione em algum lugar.
  2. Mova para rolar a página. (continue pressionando)
  3. Liberação.
  4. Toque nessa posição liberada.
  5. Você recebe mensagem dupla.

Você deve fazer este passo 5 em 2,5 segundos.
Geralmente acontece ao ler algumas listas de fóruns.
"pressione - mova - solte - toque no artigo sob seu polegar"

A rolagem dinâmica faz isso entre artigos diferentes (quando a posição de liberação é a mesma que a nova posição de toque)

Tive um problema semelhante ao usar a folha inferior do Angular Material. Por alguma razão, eventos duplicados de touchstart estavam acontecendo nas mesmas coordenadas. Isso adicionou entradas duplicadas ao array touchCoordinates dentro de ngClick , e isso permitiu cliques "fantasmas" do meu navegador Chrome para desktop. Eu parei este problema com esta mudança no método ngClick diretiva onTouchStart :

@@ -172,6 +172,13 @@
     var y = touches[0].clientY;
     touchCoordinates.push(x, y);

+    // Test if these coordinates are already allowed. Don't stack!
+    for (var i = 0; i < touchCoordinates.length; i += 2) {
+      if (touchCoordinates[i] == x && touchCoordinates[i + 1] == y) {
+        return;
+      }
+    }
+
     $timeout(function() {
       // Remove the allowable region.
       for (var i = 0; i < touchCoordinates.length; i += 2) {

Como a solução de @DaDanny não funcionou para mim, aqui está outra solução alternativa:

function onMyClick (e) {
  if (e.type !== 'click') {
    return;
  }
  // your stuff
}

Este é um grande pé no saco porque um clique em um menu MD, em seguida, focaliza uma entrada que estava abaixo dele. Isso está me deixando louco, vamos ter uma resolução em breve?

Atualmente tentando usar o ngTouch em complemento ao carrossel de inicialização do ui.
Assim que adiciono o ngTouch ao projeto, recebo esse problema de clique duplo que torna todos os controles, como entradas ou seleções, inutilizáveis.

Existe algum trabalho em andamento que corrige esse problema?

O plano é remover o ngClick do ngTouch e recomendar o uso de fastclick.js.
Algum comentário?

Hum, o fastclick cria outros problemas.
Por exemplo, ng-places-autocomplete para de funcionar corretamente assim que fastclick.js é adicionado ao projeto.

Eu me pergunto se isso é um bug que poderia ser corrigido no ng-places-autocomplete?

Sem dúvida, pode ser corrigido no ng-places-autocomplete.
Mas, se encontrarmos um problema lá, provavelmente encontraremos a mesma coisa em outros UI libs.

Acabei de encontrar esse problema. Pode confirmar que é com o ngTouch, pois removê-lo fez com que o problema desaparecesse.

No meu caso, o clique do ng eventualmente faria com que as partes parciais fossem ocultadas e mostradas, com a entrada na nova parcial que está no mesmo local que o clique do ng que aciona o teclado.

Tentei a correção sugerida por @NorikDavtian , bem como o código aqui (https://github.com/angular/angular.js/pull/11342) sem sucesso.

No meu caso, a correção veio adicionando $ event.preventDefault () ao ng-click no botão de onde o evento estava originando.

Mesmo problema, mas corrigido com a solução fornecida por @michaelyuen

<a data-ng-click="goTo($event, 'route/path')">Link</a>

$scope.goTo = function ($event, route) {
    $event.preventDefault();
    $location.url(route);
};

Este bug estava acontecendo comigo também. Tento atualizar o ng-touch para 1.4.8, a última solução alternativa, mas não funciona.
Isso aconteceu em uma pequena janela suspensa que consertei com isso.

scope.domFn = function($event, value) {
  // hack to fix bug with angular ngTouch
  if($event.type == "touchend") {return}
  someAwsomeStuff(value);
};

Espero que isso ajude alguém.

@Narretz De onde posso obter o arquivo de biblioteca ngTouch mais recente com a correção ngClickOverride?

A mudança está em 1.5.0-rc.2. Portanto, não está em nenhum branch 1.4. Isso porque não é uma correção de bug, simplesmente decidimos desabilitar a diretiva ngClick.override. Você deve ser capaz de usar o ngTouch .5 com 1.4, embora

Esta página foi útil?
0 / 5 - 0 avaliações