当$scope模型发生变化时,角度视图不会发生变化

Angular view does not change when $scope model changes

本文关键字:变化 视图 scope 模型      更新时间:2023-11-01

这是控制器的相关部分:

summaryAlertsApp.controller('FinalizedSummaryAlertsCtrl', ['$scope', 'summaryAlertsSvc', function ($scope, summaryAlertsSvc) {
        $scope.alerts = summaryAlertsSvc.getFinalizedSummaryAlerts();
        $scope.settleAlert = function (alert) {
            summaryAlertsSvc.settleAlert(alert);
            $scope.alerts = summaryAlertsSvc.getFinalizedSummaryAlerts();
        }
    }]);

我从视图调用settleAlert,$scope.alerts肯定被分配了一个新数组,但视图没有显示更改。

我已经被这件事困扰了一段时间,我似乎不明白为什么这种观点(基本上只是一种对警报的重复)没有改变。我知道警报阵列正在缩短,但这种变化并没有反映在中继器中。

以下是视图:

<div ng-app="summaryAlertsApp" ng-controller="FinalizedSummaryAlertsCtrl">
        <div ng-repeat="alert in alerts">
           stuff
</div>
</div>

这是整个服务:

summaryAlertsApp.factory('summaryAlertsSvc', ['$http', '$q', function ($http, $q) {
    var factory = {};
    var alerts;
    var deferred = $q.defer();
    $http({
        url: "SummaryAlerts.aspx/GetAlerts",
        method: "POST",
        data: {},
        headers: { 'Content-Type': 'application/json; charset=utf-8' }
    })
    .success(
        function (data) {
            deferred.resolve(data.d);
        }
    )
    alertsPromise = deferred.promise;
    alertsPromise.then(function (result) {
        alerts = result;
    }
    )
    factory.getFinalizedSummaryAlerts = function () {
        var finalizedSummaryAlerts = [];
        alertsPromise.then(function () {
            for (i = 0; i < alerts.length; i++) {
                var alert = alerts[i];
                if (alert.affectedSummaries.length > 0) {
                    finalizedSummaryAlerts.push(alert);
                }
            }
        }
        )
        return finalizedSummaryAlerts;
    }
    factory.getNewSummaryAlerts = function () {
        var newSummaryAlerts = [];
        alertsPromise.then(function () {
            for (i = 0; i < alerts.length; i++) {
                var alert = alerts[i];
                if (alert.affectedSummaries.length == 0) {
                    newSummaryAlerts.push(alert);
                }
            }
            return newSummaryAlerts;
        })
    }
    factory.settleAlert = function (alert) {
        $http({
            url: "SummaryAlerts.aspx/SettleAlert",
            method: "POST",
            data: {articlePMID: alert.PMID},
            headers: { 'Content-Type': 'application/json; charset=utf-8' }
        })
        .success(
            function (data) {
                alerts.splice(alerts.indexOf(alert), 1);
            }
        )
    }
    return factory;
}]);

问题出现在方法summaryAlertsSvc.ssettleAlert中由于它正在更改getFinalizedSummaryAlerts从中提取以进行计算的模型。由于summaryAlertsSvc.ssettleAlert正在更改成功时的模型,因此getFinalizedSummaryAlerts

解决方案是让settleAlert返回一个承诺:

factory.settleAlert = function (alert) {
        var deferred = $q.defer();
        $http({
            url: "FinalizedSummaryAlerts.aspx/SettleAlert",
            method: "POST",
            data: { articlePMID: alert.PMID },
            headers: { 'Content-Type': 'application/json; charset=utf-8' }
        })
        .success(
            function (data) {
                alerts.splice(alerts.indexOf(alert), 1);
                deferred.resolve();
            }
        )
        return deferred.promise;
    }

然后只在执行完成后调用getFinalizedSummaryAlerts:

summaryAlertsSvc.settleAlert(alert).then(function () {
            $scope.alerts = summaryAlertsSvc.getFinalizedSummaryAlerts();
        })

由于finalizedSummaryAlerts在promise内部异步更新,因此您的作用域仅在promise初始化后才获得该变量的状态,该状态本质上是一个空数组。

解决这个问题的方法是让factory.getNewSummaryAlerts返回一个promise,并更新该promise 的then子句中的作用域变量

即:

$scope.settleAlert = function (alert) {
  summaryAlertsSvc.settleAlert(alert);
  summaryAlertsSvc.getFinalizedSummaryAlerts().then(function(alerts){
    $scope.alerts = alerts;
  };
}

  factory.getFinalizedSummaryAlerts = function () {
        var finalizedSummaryAlerts = [];
        return alertsPromise.then(function () {
            for (i = 0; i < alerts.length; i++) {
                var alert = alerts[i];
                if (alert.affectedSummaries.length > 0) {
                    finalizedSummaryAlerts.push(alert);
                }
            }
           return finalizedSummaryAlerts;
        }
        );
      }

请阅读承诺,在您的服务中发生了很多奇怪的事情,特别是处理需要清理的http响应

以下是我修复您的服务的简短尝试:

summaryAlertsApp.factory('summaryAlertsSvc', ['$http', function ($http) {
    var factory = {};
    var alerts;
    // NOT NEEDED
    //var deferred = $q.defer();
    // You assumed that a promise can be executed multiple times
    // which is not the case, it can only be resolved once
    // If you want to DRY up your code, create a function that returns a new promise
    function getAlertsPromise(){
        return $http({
            url: "SummaryAlerts.aspx/GetAlerts",
            method: "POST",
            data: {},
            headers: { 'Content-Type': 'application/json; charset=utf-8' }
        })
        .then(function(response){
            // most http responses carry the data inside the response.data value
            alerts = result.data;
            // we will pass data only to the chained then functions
            return result.data;
        });
        /// Promises resolve on their own, deferred.resolve is unneccessary
        /// Also whenever you intercept a promise in a then/success clause
        /// you need to return some value to pass it on to chained then/success functions
        /// 
        /// What you did here is intercept a value, do something with it and not return anything
        /// which meant that chained 'then' functions received an undefined value
        /// 
        //.success(
        // function (data) {
        //    deferred.resolve(data.d);
        //}
    }
    // THis returns a promise which resolves with a value of finalizedSummaryAlerts
    factory.getFinalizedSummaryAlerts = function () {
        var finalizedSummaryAlerts = [];
        return getAlertsPromise().then(function (data) {
            for (i = 0; i < data.length; i++) {
                var alert = data[i];
                if (alert.affectedSummaries.length > 0) {
                    finalizedSummaryAlerts.push(alert);
                }
            }
           return finalizedSummaryAlerts;
        }
        );
      };
    // THis returns a promise which resolves with a value of newSummaryAlerts
    factory.getNewSummaryAlerts = function () {
        var newSummaryAlerts = [];
        return getAlertsPromise().then(function (data) {
            for (i = 0; i < data.length; i++) {
                var alert = data[i];
                if (alert.affectedSummaries.length === 0) {
                    newSummaryAlerts.push(alert);
                }
            }
            return newSummaryAlerts;
        });
    };
    factory.settleAlert = function (alert) {
        return $http({
            url: "SummaryAlerts.aspx/SettleAlert",
            method: "POST",
            data: {articlePMID: alert.PMID},
            headers: { 'Content-Type': 'application/json; charset=utf-8' }
        })
        .success(
            function (data) {
                alerts.splice(alerts.indexOf(alert), 1);
            }
        );
    };
    return factory;
}]);

请阅读Angular$q以及$http文档,了解常规使用示例