AngularJS+Cordova APP数据无法自动刷新,点击屏幕才刷新问题求助
解决AngularJS + Cordova应用中SQLite数据加载后视图不自动刷新的问题
你遇到的核心问题是SQLite异步回调的执行上下文不在Angular的变更检测循环内,而且你的$scope.safeApply()调用时机不对——它在异步回调完成前就执行了,导致Angular完全不知道后续数据的变化。
问题拆解
你的代码里,db.transaction和executeSql都是异步操作:当你在db.transaction函数里直接调用$scope.safeApply()时,executeSql的成功回调还没开始执行,$scope.datas还是空数组。等真正从数据库拿到数据并push到数组时,Angular的变更检测已经结束了,所以视图不会自动更新;只有当你点击屏幕触发了digest循环(比如通过Angular内置的事件指令),视图才会同步最新数据。
修复方案
把触发变更检测的代码($scope.$apply()或$scope.safeApply())放到executeSql的成功回调内部——也就是数据真正被添加到$scope.datas之后。同时可以简化代码,不用把每个字段都单独赋值到$scope上:
$scope.datas = []; db.transaction(function(transaction) { transaction.executeSql('SELECT * FROM application_data', [], function (tx, results) { var len = results.rows.length; for (var i = 0; i < len; i++){ // 直接从结果中取出数据push,无需额外赋值到$scope属性 var item = results.rows.item(i); $scope.datas.push({ id: item.id, name: item.name, date: item.date }); } // 数据更新完成后,手动触发Angular变更检测 if (!$scope.$$phase) { // 先检查是否已在digest循环中,避免重复触发报错 $scope.$apply(); } // 如果用自定义的safeApply,确保它内部有类似的检测逻辑,直接调用即可 // $scope.safeApply(); }, null); });
额外补充
- 如果你使用的
safeApply是自定义函数,它的实现应该包含对$$phase的检测,避免在已经处于digest循环时调用$apply()导致错误。典型的safeApply实现如下:$scope.safeApply = function(fn) { var phase = this.$root.$$phase; if(phase === '$apply' || phase === '$digest') { if(fn && (typeof(fn) === 'function')) { fn(); } } else { this.$apply(fn); } }; - 也可以用
$timeout替代$apply,因为$timeout会自动触发Angular的变更检测,而且不需要手动检查$$phase:// 在for循环结束后替换成: $timeout(function() { // 无需额外操作,$timeout会自动触发digest循环 });
这样修改后,当数据库查询完成并更新$scope.datas后,Angular会立即检测到变化并刷新视图,不再需要手动点击屏幕触发。
内容的提问来源于stack exchange,提问作者user3740961
相关产品推荐
相关产品推荐

