Google的新reCaptcha使用ui-router打破角度

时间:2015-04-10 22:20:28

标签: angularjs angular-ui-router recaptcha

当我在recaptcha框中打勾时,ui-router似乎崩溃了。页面上具有ui-sref属性的所有链接都停止工作,但我没有收到任何错误消息。请查看我已设置的this plunker。你知道原因可能是什么吗?

的script.js

var app = angular.module('app', ['ui.router'])

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
  .state('home', {
    url: '/',
    templateUrl: 'home.html',
    controller: function() {
      grecaptcha.render('captcha', {
        sitekey: "--sitekey--"
      })
    }
  })
  .state('other', {
    templateUrl: 'other.html'
  });

  $urlRouterProvider.otherwise('/');
})

的index.html

<!DOCTYPE html>
<html ng-app="app">

<head>
  <script data-require="angular.js@*" data-semver="1.4.0-rc.0" src="https://code.angularjs.org/1.4.0-rc.0/angular.js"></script>
  <script data-require="ui-router@*" data-semver="0.2.13" src="//rawgit.com/angular-ui/ui-router/0.2.13/release/angular-ui-router.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
  <script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
  <ui-view></ui-view>
</body>

home.html的

<h1>Home</h1>

<p>Click the re-captcha, then try to change state by clicking the link below.</p>

<p><a ui-sref="other">Go to other state</a></p>

<div id="captcha"></div>

other.html无关紧要。

更新 我注意到状态转换仅在目标状态定义了url时失败,并且我设法将其缩小到ui-router源代码中的下一段代码(ui-sref指令) :

element.bind("click", function(e) {
    var button = e.which || e.button;
    if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) {
      // HACK: This is to allow ng-clicks to be processed before the transition is initiated:
      var transition = $timeout(function() {
        $state.go(ref.state, params, options);
      });
      e.preventDefault();

      // if the state has no URL, ignore one preventDefault from the <a> directive.
      var ignorePreventDefaultCount = isAnchor && !newHref ? 1: 0;
      e.preventDefault = function() {
        if (ignorePreventDefaultCount-- <= 0)
          $timeout.cancel(transition);
      };
    }
  });

正如您所看到的,正在重写e.preventDefault函数以取消将触发状态更改的超时。如果你在上面的活页夹中注释掉这段代码,状态转换就会起作用:

//e.preventDefault = function() {
//    if (ignorePreventDefaultCount-- <= 0)
//        $timeout.cancel(transition);
//};

通常ui-router在每个锚链接上每次点击都会调用e.preventDefault()一次,但是当勾选reCaptcha时,它似乎被调用了两次。我猜这可能与问题有关,但我并非100%肯定。也许拥有更好调试技能的人可以理解正在发生的事情。 Here's a plunker证明了这种行为。

2 个答案:

答案 0 :(得分:4)

我找到了一种简单的方法来解决角度上任何类型的路由器的问题。当grecaptha未定义时,这意味着我们遇到了同步问题。因此,在我/您的控制器中,您应该使用例如&lt;&lt;来加载脚本。 $ .getScript(“URL”)&gt;&gt;

SO:
在HTML中 <div class="g-recaptcha" data-sitekey="YourSiteKey"></div>

在你的控制器中: $.getScript("https://www.google.com/recaptcha/api.js");

在这里,你的grecaplecha就像你第一次加载页面一样。

答案 1 :(得分:1)

使用角度路由时出现相同的错误。

您可以通过下列代码解决此问题:

index.html中的

  

<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"></script>

你的script.js中的

var app = angular.module('app', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('home', 
        {
            url: '/',
            templateUrl: 'home.html',
            controller: function() {
                 function onloadCallback() {
                     grecaptcha.render('yourHTMLElementId', {
                          'sitekey' : 'yourSiteKey'
                     });
                 }
                 onloadCallback();
           }
        })
    .state('other', {
        templateUrl: 'other.html'
    });
    $urlRouterProvider.otherwise('/');
})