2015-04-17 12 views
23

Mam kod, którego używam do sprawdzania połączenia z serwerem. Mój kod jest uruchamiany co 60 sekund. Po uruchomieniu kodu tworzy on wiadomość, która pojawia się na stronie. Oto co mam do tej pory:Jak mogę wyświetlić komunikat odliczający co sekundę z AngularJS?

Kod, który sprawdza:

$interval(function() { 
     us.isConnected().then(closeConnect, openConnect); 
    }, 60 * 1000); 

Kod, który robi Skontrolować

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; 
}; 

Co chciałbym zrobić, to mieć prostą funkcję zwaną retryMessage(), które pozwolą mi przekazać wiadomość:

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. 

Zliczanie sekund w dół do 0, kiedy nastąpi ponowne sprawdzenie.

Czy ktoś może zaproponować sposób w AngularJS, że mogę osiągnąć to odliczanie?

+0

Zapoznaj się z Link, to prawie wszystkie liczniki można chcieć: http://siddii.github.io/angular-timer/ – eitanfar

Odpowiedz

4

Nie sądzę, używając dyrektywy jest konieczne, prawdopodobnie można zrobić wszystko wewnątrz sterownika. Jednak zaimplementowałeś closeConnection i openConnection powinieneś edytować te metody dodając "start" i "stop" $interval.

Należy również pamiętać, że $interval przyjmuje maksymalną liczbę rekursji, które w tym przypadku są bardzo przydatne.

https://docs.angularjs.org/api/ng/service/ $ przedział

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'; 
    } 
} 

Formatowanie Wiadomość

$scope.message to zwykły ciąg w tym przypadku tak nie dostaniesz żadnego formatowania, ale można umieścić go wewnątrz dyrektywy ng-bind-html a następnie dodać dowolny znacznik html do ciągu wiadomości.

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

<div ng-bind-html="message"></div> 

I tak zmieniając js

$scope.message += '<p>Connection will be retried in '+ retry +' seconds</p>'; 
1
$interval(function() { 
    us.isConnected().then(closeConnect, openConnect); 
}, 1000); 

Nie

$interval(function() { 
    us.isConnected().then(closeConnect, openConnect); 
}, 20 * 1000); 

Ten ostatni Czy kontrola co 20 SEK (20 * 1000ms), więc chyba rzeczywisty kod sprawdzanie jest wadliwy, należy go uruchomić w każdej sekundzie.

+0

Dzięki za wskazanie, że było 20. Zmieniłem pytanie. Czek jest dokonywany co 60 sekund, ale chciałbym również zmodyfikować komunikat tak, aby pokazywał odliczanie malejące co sekundę. –

6

Można zrobić odliczanie od 60 sekund tak:

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); 
    } 

codepen

polecam umieszczenie komunikatu o błędzie w html i ukrywanie go z ng-show lub ng-if a potem po prostu zmieniając numer, aby nie trzeba było dodawać całego tego tekstu w kółko.

1

Tak więc w zależności od tego, w jaki sposób chcesz wyprowadzić szczegóły dla użytkownika, prawdopodobnie najlepiej byłoby uczynić to pewnym rodzajem dyrektywy i kontrolować wszystko w tym zakresie.

Kluczem do robienia tego, co chcesz zrobić, to skorzystać z usługi przedział $, która zwraca ID:

$scope.intervalId = $interval(retryMessage, 1000); 

Następnie można anulować w zależności od warunków jakiegokolwiek zestawu.

zrobiłem plnkr wykazując, czego szukasz do osiągnięcia:

http://plnkr.co/edit/RmADu1aiOUO5o4k4pnqE?p=preview

1

Napisałem ten czasomierz niedawno, z którego może być w stanie poświęcić trochę logiki - Plunker. Liczy się i może zakończyć się w ustalonym czasie

JS

(function() { 

    'use strict'; 

    var angularTimerApp = angular.module('angularTimerApp', []); 

    angularTimerApp.directive("angularTimer", function() { 
     return { 
      restrict: "E", 
      templateUrl: "angular-timer.html", 
      scope: {endTime: "@"}, 
      controllerAs: "at", 
      bindToController: true, 
      controller: ["$scope", "$interval", function ($scope, $interval) { 
       var at = this; 
       at.secondsInAYear = 31536000; 
       at.secondsInADay = 86400; 
       at.secondsInAnHour = 3600; 
       at.secondsInAMinute = 60; 
       at.endTimeValue = null; 

       $scope.$watch("at.endTime", function(newValue) { 
        if (angular.isDefined(newValue)) { 
        at.endTimeValue = parseInt(newValue); // No test for int 
        } 
       }); 

       at.getTimeDisplay = function(seconds) { 
        var hoursTxt = Math.floor(((seconds % at.secondsInAYear) % at.secondsInADay)/at.secondsInAnHour); 
        var minutesTxt = Math.floor((((seconds % at.secondsInAYear) % at.secondsInADay) % at.secondsInAnHour)/at.secondsInAMinute); 
        var secondsTxt = (((seconds % at.secondsInAYear) % at.secondsInADay) % at.secondsInAnHour) % at.secondsInAMinute; 
        return ("Hours: " + hoursTxt + ", Minutes: " + minutesTxt + ", Seconds: " + secondsTxt); 
       }; 

       at.reset = function() { 
        at.timeOffset = 0; 
        at.timeDisplay = at.getTimeDisplay(0); 
       }; 
       at.reset(); 

       at.stop = function() { 
        $interval.cancel(at.timer); 
        at.timeOffset = at.time; 
       }; 

       at.start = function() { 
        at.timeStart = (new Date()).getTime(); 

        at.timer = $interval(function() { 
         at.time = Math.floor(((new Date()).getTime() - at.timeStart)/1000) + at.timeOffset; 
         if ((at.endTimeSet) && (at.endTimeValue !== null)) { 
          if (at.time > at.endTimeValue) { 
           at.stop(); 
          } 
          else { 
           at.timeDisplay = at.getTimeDisplay(at.time); 
          } 
         } 
         else { 
          at.timeDisplay = at.getTimeDisplay(at.time); 
         } 
        }, 1000); 
       }; 
      }] 
     }; 
    }); 
})(); 

Markup

<body> 
    <angular-timer end-time="10"></angular-timer> 
</body> 

kątowe-timera.html

{{at.timeDisplay}} 
<br><br> 
<button ng-click="at.start()">Start</button> 
<br><br> 
<button ng-click="at.stop()">Stop</button> 
<br><br> 
<button ng-click="at.reset()">Reset</button> 
<br><br> 
<input type="checkbox" ng-model="at.endTimeSet"> End at 27 seconds 
9

Jednym z możliwych sposobów robienia tego, co próbujesz jest użycie $q.notify w połączeniu z $interval.

Inne wiadomości można przekazywać za pomocą funkcji rozstrzygania i odrzucania. Oczywiście, każde miejsce, w którym się to robi, można wydrukować bezpośrednio do usługi rejestrowania, ale pomyślałem, że może być właściwe, aby zwrócić te wiadomości z zachowaniem obietnicy (gdzie, jeśli chcesz, możesz nawet zwrócić obiekt z kod statusu i inne dane wraz z wiadomością).

W poniższym przykładzie pozwoliłem kontrolerowi zarządzać rejestrowaniem i ograniczyłem jego wyjście do 12 wierszy. Podałem również parametry do testowania połączenia, więc próbuję połączyć się co 60 sekund, 20 razy (te parametry można zmienić, aby próbować w różnych interwałach, inną ilość razy lub w nieskończoność). Jeśli test jest porażką, wypisuje komunikat restartu (s) co sekundę aż do zamachu powtórzenie:

(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; 
 
    } 
 
    } 
 

 
})();
<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>

2

mam dyrektywę o bardzo podobnym celu, można sprawdzić to here on plunker

zasadniczo używa (1) timera & (2) odświeżania, można go również skonfigurować tak, jak w przypadku braku limitu czasu dla sekund, przeczytać z atrybutu dyrektywy.

Wywołuje daną funkcję po podanym interwale, a także niszczy #interval na zmianie zakresu $.

Poniżej znajduje się kod na to

app.directive("csAutoRefresh", ["$interval", function ($interval) { 

    var templateFn = function() { 
     var template = '<div class="text-left alert alert-success nopadding"'; 
     template += 'style="margin-bottom: 0; margin-right: 0"> '; 
     template += ' <button class="btn btn-link" data-ng-click="factory.refresh.toggle()">'; 
     template += '{{factory.refresh.refreshText()}}</button>'; 
     template += '<span>...Refreshing upload status in '; 
     template += ' {{state.timer.timePending}} seconds</span>'; 
     template += ' </div>'; 
     return template; 
    }; 

    var linkFn = function (scope) { 
     scope.pauseOn = scope.pauseOn === true; 
     scope.isprocessing = false; 

     scope.state = { 
      refresh : { 
       suspend : false 
      }, 
      timer : { 
       timePending: 0, 
       refreshInterval : 60 
      } 
     } 

     function doRefresh() { 
      var refresh = { 
       pause: function() { scope.state.refresh.suspend = true; }, 
       cont: function() { scope.state.refresh.suspend = false; }, 
       toggle: function() { scope.state.refresh.suspend = !scope.state.refresh.suspend; }, 
       refreshText: function() { return scope.state.refresh.suspend ? "Resume Refresh" : "Pause Refresh"; } 
      }; 
      return refresh; 
     } 

     function doTimer() { 
      var timer = { 
       reset: function() { scope.state.timer.timePending = scope.state.timer.refreshInterval; }, 
       update: function() { 
        if (scope.state.timer.timePending < 0) timer.reset(); 
        scope.state.timer.timePending--; 
       }, 
       done: function() { return scope.state.timer.timePending <= 0; }, 
       force: function() { scope.state.timer.timePending = 0; } 
      }; 
      return timer; 
     }; 

     scope.factory = { 
      refresh: doRefresh(), 
      timer: doTimer() 
     }; 

     if (angular.isDefined(scope.interval) && parseInt(scope.interval) > 0) { 
      scope.state.timer.refreshInterval = scope.interval; 
     } 
     scope.factory.timer.reset(); 

     scope.$watch(function() { 
      return scope.state.timer.timePending; 
     }, function() { 
      if (!scope.factory.timer.done()) return; 
      var result = scope.$eval(scope.onTimeout); 
      if (angular.isObject(result) && angular.isFunction(result.then)) { 
       scope.isprocessing = false; 
       scope.factory.timer.reset(); 
       result.finally(function() { scope.factory.timer.reset(); }); 
      } else { 
       scope.isprocessing = false; 
       scope.factory.timer.reset(); 
      } 
     }); 

     scope.$watch('pauseOn', function() { 
      if (scope.pauseOn) { 
       scope.factory.refresh.pause(); 
      } else { 
       scope.factory.timer.reset(); 
       scope.factory.refresh.cont(); 
      } 
     }); 

     var updateTimer = function() { 
      if (scope.isprocessing) return; 
      if (scope.state.refresh.suspend) return; 
      scope.factory.timer.update(); 
     }; 

     var interval = $interval(updateTimer, 1000); 
     scope.$on('$destroy', function() { 
      $interval.cancel(interval); 
     }); 
    }; 

    return { 
     restrict: 'E', 
     scope: { onTimeout: '&', pauseOn: '=', interval: '@' }, 
     template: templateFn, 
     link: linkFn, 
    }; 
}]); 
1

myślę, co naprawdę chcesz to usługa, która zwraca obietnicę, obietnicę, która wysyła powiadomienia z powrotem do kontrolera.Here's przykładem takiej usługi:

<!DOCTYPE html> 
<html> 
<head> 
<script data-require="[email protected]" data-semver="1.4.0-rc.0" src="https://code.angularjs.org/1.4.0-rc.0/angular.js"></script> 
</head> 
<body ng-app="myapp" ng-controller="main"> 

<h1>Task Retry Example</h1> 
<p>Task condition: {{value}}</p> 
<button ng-click="value = true">Set task condition to true</button> 
<button ng-click="reset()">Reset Task</button> 
<p>{{msg}}</p> 

<script> 
    var app = angular.module('myapp', []); 
    app.controller('main', function($scope, task){ 
    var myTask = function(){ 
     return $scope.value; 
    } 

    function success(result){ 
     $scope.msg = result; 
    } 
    function failure(reason){ 
     $scope.msg = reason; 
    } 
    function notify(value){ 
     $scope.msg = value.message; 
    } 

    $scope.reset = function(){ 
     $scope.value = false; 
     $scope.msg = "Loading..."; 
     task.go(myTask, {maxAttempts: 3, waitTime: 3}) 
     .then(success, failure, notify); 
    } 

    $scope.reset(); 

    }); 

    app.service('task', function($q, $timeout){ 

    var DEFAULT_OPTIONS = { 
     maxAttempts: 1, 
     waitTime: 10 
    }; 
    var thisOptions = {}; 

    function _countDownStep(secondsLeft, attemptsLeft, countDownProgress, taskAttemptProgress){ 
     if(secondsLeft <= 0){ 
     countDownProgress.resolve(true); 
     return; 
     } 
     var attempt = thisOptions.maxAttempts - attemptsLeft, 
      msg = "Attempt failed; retrying (" + attempt + " of " + thisOptions.maxAttempts + ") in " + secondsLeft + " seconds..."; 
     taskAttemptProgress.notify({ 
     "state": "WAITING", 
     "message": msg 
     }) 
     $timeout(function(){ 
     _countDownStep(secondsLeft-1, attemptsLeft, countDownProgress, taskAttemptProgress); 
     }, 1000); 
    } 

    function _countDown(secondsLeft, attemptsLeft, progress){ 
     var deferred = $q.defer(); 
     _countDownStep(secondsLeft, attemptsLeft, deferred, progress); 
     return deferred.promise; 
    } 

    function _attempt(task, attemptsLeft, progress){ 
     if(!angular.isFunction(task)) { 
     progress.reject("Task is not a function."); 
     return; 
     } 
     if(attemptsLeft <= 0){ 
     progress.reject("Max attempts reached."); 
     } 
     var result = task(); 
     if(result){ 
     progress.resolve("Successfully completed task."); 
     }else { 
     --attemptsLeft; 
     if(attemptsLeft <= 0){ 
      progress.reject("Max attempts reached."); 
     } 
     _countDown(thisOptions.waitTime, attemptsLeft, progress).then(function(){ 
      var attempt = thisOptions.maxAttempts - attemptsLeft, 
      msg = "Making another attempt (" + attempt + " of " + thisOptions.maxAttempts + ")..."; 
      progress.notify({ 
      "state": "TRYING", 
      "message": msg 
      }) 
      _attempt(task, attemptsLeft, progress); 
     }); 
     } 
    } 

    function _go(task, options){ 
     var deferred = $q.defer(); 
     thisOptions = options || DEFAULT_OPTIONS; 
     _attempt(task, thisOptions.maxAttempts, deferred); 
     return deferred.promise; 
    } 

    return { 
     go: _go 
    } 

    }); 

</script> 

Powiązane problemy