如何使用AngularJS显示每秒倒计时的消息?

Sam*_*tar 23 angularjs

我有用于检查与服务器的连接的代码.我的代码每60秒运行一次.代码运行后,它会创建一条消息,并显示在页面上.这是我到目前为止所拥有的:

检查的代码:

$interval(function () {
        us.isConnected().then(closeConnect, openConnect);
    }, 60 * 1000);
Run Code Online (Sandbox Code Playgroud)

执行检查的代码

isConnected = (): ng.IPromise<any> => {
    var self = this;
    var deferred = this.$q.defer();
    this.$http({
        method: 'GET',
        url: self.ac.baseUrl + '/api/Connect/Verify'
    })
        .success(() => {
            self.connects = 0;
            self.connectMessage = null;
            deferred.resolve();
        })
        .error(() => {  
            if (self.connects == 0) {
                self.connectMessage = "Unable to establish a connection to the server. " + retryMessage();
            } else if (self.connects == 1) {
                self.connectMessage = "Unable to establish a connection to the server for " + self.connects + " minute" + retryMessage();
            } else {
                self.connectMessage = "Unable to establish a connection to the server for " + self.connects + " minutes." + retryMessage();
            }
            self.connects++; 
            deferred.reject();
        });
    return deferred.promise;
};
Run Code Online (Sandbox Code Playgroud)

我想做的是有一个名为retryMessage()的简单函数,它允许我给出这样的消息:

 Unable to establish a connection to the server for 164 minutes. 
 Connection will be retried in 59 seconds.
 Unable to establish a connection to the server for 164 minutes. 
 Connection will be retried in 58 seconds.
 Unable to establish a connection to the server for 164 minutes. 
 Connection will be retried in 57 seconds.
 ...
 Unable to establish a connection to the server for 164 minutes. 
 Connection will be retried in 1 seconds.
 Unable to establish a connection to the server for 164 minutes. 
 Retrying connection now.
 Unable to establish a connection to the server for 165 minutes. 
 Connection will be retried in 59 seconds.
Run Code Online (Sandbox Code Playgroud)

当重新检查时,向下计数秒数直到0.

任何人都可以在AngularJS中建议我可以实现这个倒计时吗?

JcT*_*JcT 9

做你正在尝试的一种可能的方法是与... $q.notify一起使用$interval.

其他消息可以通过解析和拒绝传递.当然,任何这样做的地方你都可以直接打印到日志服务,但我认为将这些消息与promise行为一起返回可能是合适的(如果你愿意的话,你甚至可以返回一个完整的对象)状态代码和其他数据以及消息).

在下面的示例中,我让控制器管理日志记录并将其输出限制为12行.我还指定了连接测试的参数,因此它尝试连接每60秒,20次(这些参数可以更改为尝试不同的间隔,不同的次数,或无限期).如果测试失败,它会每秒打印重试消息,直到重试尝试:

(function() {
  "use strict";

  var myApp = angular.module('myApp', []);
  myApp.controller('MainController', ['$scope', 'us', '$log', MainController]);
  myApp.service('us', ['$interval', '$q', '$http', '$log', usService]);

  /* Controller */
  function MainController($scope, us, $log) {

    var _data = {
        connectLog: null
      },
      _connectMessages = [],
      _MAX_LOG_LINES = 12;

    $scope.data = _data;

    _log("Starting connection test...");
    us.testConnection(60, 20) //60 seconds between tests, 20 tests (if no max specified, could run forever...)
      .then(onTestsSuccessful, onTestsFailed, onNotifying);

    function onTestsSuccessful(result) {
      _log(result);
      // do success stuff...
    }

    function onTestsFailed(result) {
      _log(result);
      // do failed stuff...
    }

    function onNotifying(result) {
      _log(result);
      //do retrying stuff...
    }

    function _log(message, deferOutput) {
      //$log.debug(message);

      _connectMessages.push(message);

      if (_MAX_LOG_LINES && _connectMessages.length > _MAX_LOG_LINES) {
        _connectMessages.splice(0, _connectMessages.length - _MAX_LOG_LINES);
      }

      if (!deferOutput) {
        _data.connectLog = _connectMessages.join('\n');
      }
    }
  }

  /* Service */
  function usService($interval, $q, $http, $log) {

    var _testConnectionInterval,
      _testsRun;

    return {
      testConnection: _startTestConnection
    };

    function _startTestConnection(secondsBetweenTests, maxTests) {
      var deferred = $q.defer(),
        connectAttempts = 0;

      _cancelConnectionTest();

      _connectionTest().then(onConnectionTestSuccess, onConnectionTestFail); //immediately do first test
      _testsRun++;

      if (secondsBetweenTests > 0) {
        _testConnectionInterval = $interval(
          function repeatConnectionTest() {
            if (maxTests && _testsRun >= maxTests) {
              return _cancelConnectionTest();
            }
            deferred.notify("Retrying connection now.");
            _connectionTest().then(onConnectionTestSuccess, onConnectionTestFail);
            _testsRun++;
          },
          secondsBetweenTests * 1000); //start the countdown to the next
      }

      function onConnectionTestSuccess(result) {
        connectAttempts = 0;

        if ((maxTests && _testsRun >= maxTests) || !secondsBetweenTests) {
          deferred.resolve("Last connection test success, " + _testsRun + " tests complete.");
        } else {
          deferred.notify("Connection test success.");
        }
      }

      function onConnectionTestFail(result) {
        var minutesPassed = connectAttempts * secondsBetweenTests / 60,
            minutesRoundedToTwoDec = +(Math.round(minutesPassed + "e+2")  + "e-2");
        
        var connectMessage = "Unable to establish a connection to the server" + (connectAttempts === 0 ? "." : " for " + minutesRoundedToTwoDec + " minute" + (minutesPassed > 1 ? "s." : "."));

        connectAttempts++;

        if ((maxTests && _testsRun >= maxTests) || !secondsBetweenTests) {
          deferred.reject("Last connection test failed, " + _testsRun + " tests completed.");
        } else {
          deferred.notify(connectMessage);
          deferred.notify("Connection will be retried in " + secondsBetweenTests + " seconds.");

          var retryInterval = $interval(
            function retryMessage(counter) {
              deferred.notify(connectMessage);

              var secondsLeft = (secondsBetweenTests - 1) - counter;
              deferred.notify("Connection will be retried in " + secondsLeft + " second" + (secondsLeft > 1 ? "s." : "."));

              if (!secondsLeft) {
                $interval.cancel(retryInterval);
                retryInterval = null;
              }
            },
            1000, (secondsBetweenTests - 1));
        }
      }

      return deferred.promise;
    }

    function _connectionTest() {
      var deferred = $q.defer(),
        getBroken = {
          method: 'GET',
          url: '/api/never/gonna/give/you/up'
        };

      $http(getBroken)
        .success(function onSuccess() {
          deferred.resolve('Success!');
        })
        .error(function onError() {
          deferred.reject('Failure!');
        });

      return deferred.promise;
    }

    function _cancelConnectionTest() {
      _testsRun = 0;
      if (!_testConnectionInterval) {
        $log.debug("No previously running connection test to cancel.");
        return;
      }
      $log.debug("Cancelling connection test.");
      $interval.cancel(_testConnectionInterval);
      _testConnectionInterval = null;
    }
  }

})();
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
  <pre ng-controller="MainController">{{data.connectLog}}</pre>
</div>
Run Code Online (Sandbox Code Playgroud)


小智 6

您可以在60秒内完成倒计时,如下所示:

countdown(60);

  function countdown(current_time){
    if(current_time === 0){
      //call function to connect to server
      return;
    }
    else{
      current_time--;
    }
    $scope.time = current_time;
    $timeout(function(){countdown(current_time)}, 1000);
  }
Run Code Online (Sandbox Code Playgroud)

codepen

我建议将错误消息放在html中并用一个ng-show或隐藏它,ng-if然后只需更改数字,这样就不需要反复追加所有文本了.


Bol*_*lza 4

我认为没有必要使用指令,您可能可以在控制器内执行所有操作。但是您实现了closeConnectionopenConnection您应该编辑这些方法添加 'start' 和 'stop' $interval

还要记住,$interval需要最大递归次数,在这种情况下非常有用。

https://docs.angularjs.org/api/ng/service/ $interval

function controllerFunc($scope, $interval) {
    var timer;
    var lastConnection = 0;
    $scope.message = '';

    //this is what you already have
    $interval(function () {
        us.isConnected().then(closeConnect, openConnect);
    }, 60 * 1000);
    //...

    function closeConnect() {
        //...
        $interval.cancel(timer);
        lastConnection = 0;
    }

    function openConnect() {
        //...
        timer = $interval(timerCall, 1000, 60);
        lastConnection++;
    }

    function timerCall(times) {
        $scope.message += 'Unable to establish a connection to the server for ' + lastConnection + ' minutes. ';

        var retry = 60 - times;
        $scope.message += 'Connection will be retried in '+ retry +' seconds';
    }
}
Run Code Online (Sandbox Code Playgroud)

格式化消息

$scope.message在此示例中是一个纯字符串,因此您不会获得任何格式,但您可以将其放入ng-bind-html指令中,然后将任何 html 标记添加到消息字符串中。

https://docs.angularjs.org/api/ng/directive/ngBindHtml

<div ng-bind-html="message"></div>
Run Code Online (Sandbox Code Playgroud)

所以改变js

$scope.message += '<p>Connection will be retried in '+ retry +' seconds</p>';
Run Code Online (Sandbox Code Playgroud)