AngularJS与Rails集成时$scope未识别及剩余时间获取异常问题
Hey there! Let's work through this problem step by step—we'll fix that "undefined" issue and sort out the negative remaining time too.
First: Why does $scope.remainingTime show as undefined in your controller, but appear in console.log($scope)?
This almost always boils down to timing or how you're passing data from Rails to Angular:
- If you're initializing
remainingTimeasynchronously (like via an API call, or relying on Rails to inject the value after the controller loads), your controller might be trying to access the variable before it's been assigned. Theconsole.log($scope)shows it later because browser dev tools display live references—by the time you check the log, the value has been set. - Double-check how you're passing Rails'
@resourcedata to Angular. If you're usingng-init, make sure it's attached to the same element (or a parent) of your controller, so the value lands in the correct scope. For example:<div ng-controller="TaskController" ng-init="taskEndTime = '<%= @resource.end_time.utc.iso8601 %>'"> <!-- Your view content here --> </div>
Second: Fixing the negative remainingTime value
Negative time usually means one of two things:
- Backwards calculation: You might be subtracting the end time from the current time, instead of the other way around. It should be
end_time - current_timeto get positive time left (or negative if the task is done). - Timezone mismatch: Rails often stores times in UTC, while Angular uses your local timezone by default. This can skew calculations. Always use UTC for both backend and frontend calculations to avoid this.
Step-by-Step Solution
Let's rewrite the controller logic to handle both issues cleanly:
1. Update the Rails-to-Angular data pass
Instead of passing a pre-calculated remaining time, pass the raw UTC end time from Rails. This lets Angular handle the calculation, avoiding timezone gaps.
2. Rewrite your Angular controller
angular.module('yourAppName').controller('TaskController', function($scope, $interval) { // Convert the Rails-provided UTC time to a Date object const taskEndUtc = new Date($scope.taskEndTime); // Function to calculate remaining time (in seconds) function updateRemainingTime() { // Get current time in UTC to match Rails' timezone const now = new Date(); const nowUtc = new Date(Date.UTC( now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds() )); // Calculate difference in seconds (end time minus current time) $scope.remainingTime = Math.floor((taskEndUtc - nowUtc) / 1000); } // Initialize the value immediately updateRemainingTime(); // Refresh every second for real-time updates $interval(updateRemainingTime, 1000); // Access the value safely with $watch (avoids undefined on load) $scope.$watch('remainingTime', (newVal) => { if (newVal !== undefined) { console.log('Current remaining time:', newVal); // Add your logic here once the value is available } }); });
3. Improve the view display
Hide negative time and show user-friendly text instead, plus a filter to format seconds into readable time:
<!-- Display formatted time if task is ongoing --> <div ng-if="remainingTime > 0"> Time remaining: {{ remainingTime | secondsToDhms }} </div> <!-- Show completion message if task is done --> <div ng-if="remainingTime <= 0"> Task X has been completed! </div>
4. Add the time-formatting filter
angular.module('yourAppName').filter('secondsToDhms', () => { return (seconds) => { seconds = Number(seconds); const days = Math.floor(seconds / (3600 * 24)); const hours = Math.floor((seconds % (3600 * 24)) / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); return [ days > 0 ? `${days}d` : '', hours > 0 ? `${hours}h` : '', minutes > 0 ? `${minutes}m` : '', `${secs}s` ].filter(Boolean).join(' '); }; });
Quick Checks to Verify
- Make sure Rails is outputting the end time in UTC ISO format (like
2024-05-20T14:30:00Z)—this is the most reliable format for Date objects in JS. - If you're still seeing undefined, check the browser's element inspector to confirm the
ng-initvalue is being rendered correctly in the HTML.
内容的提问来源于stack exchange,提问作者José Antonio Camus Godoy
相关产品推荐
相关产品推荐

