AngularJS $范围在分配后丢弃值

时间:2016-07-05 05:11:59

标签: javascript angularjs

我希望有人可以帮助我理解我在AngularJS中使用$ scope的烦人问题。请参阅下面代码中的评论:

app.controller('MyController', function ($scope, $routeParams, $http, $timeout) {
    $scope.id = $routeParams.id;

    $http.get("http://server/api/Blah/GetData/" + $scope.id).success(function (data) {
        $scope.data = data;
        alert($scope.data.MyObject.Property); //displays the expected value. - Not Undefined or null
    }).error(function (data) {
        alert(data);
    });

    $scope.$on('$viewContentLoaded', function () {
        $timeout(function () {
            var d = document.getElementById("iframe");

            d.contentDocument.documentElement.innerHTML = $scope.data.MyObject.Property; //Now MyObject is magically undefined.           

        }, 0);
    });
});

对WEB API的调用返回一个分配给$ scope.data的有效对象。我显示一个警报,以确保$ scope.data.MyObject.Property存在,它确实存在。显示预期值。

现在,当我尝试访问$ viewContentLoaded代码中的$ scope.data.MyObject.Property时,$ scope.data.MyObject不再位于$ scope中。控制台报告以下内容:

  

HTML1300:导航已发生。   文件:route.html   TypeError:无法获取属性' MyObject'未定义或空引用      在匿名函数(http://server/script/route.js:43:13)      在匿名函数(https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js:158:234)      在e(https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js:45:348)      在匿名函数(https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js:48:275

为什么$ scope会删除$ scope.data.MyObject的值?让这个问题更令人沮丧的是,如果我发出警报("");在$ viewContentLoaded代码中,$ scope.data.MyObject值不再是未定义的。这是怎么回事?

5 个答案:

答案 0 :(得分:2)

您需要知道代码执行的时间。

这是带有一些日志记录的固定代码:

app.controller('MyController', function ($scope, $routeParams, $http, $timeout) {
    $scope.id = $routeParams.id;

    console.log(1);

    var promise = $http.get("http://server/api/Blah/GetData/" + $scope.id).success(function (data) {
        $scope.data = data;
        console.log(2);
        alert($scope.data.MyObject.Property); //displays the expected value. - Not Undefined or null
    }).error(function (data) {
        alert(data);
    });

    $scope.$on('$viewContentLoaded', function () {
        $timeout(function () {
            var d = document.getElementById("iframe");

            console.log(3);
            // d.contentDocument.documentElement.innerHTML = $scope.data.MyObject.Property;

            promise.then(function () {
                console.log(4);
                d.contentDocument.documentElement.innerHTML = $scope.data.MyObject.Property;
            });

        }, 0);
    });
});

您可能希望结果日志为1234,但实际上可能是1324。在后一种情况下,$viewContentLoaded中的代码在 $http.get成功之前执行。所以它$scope.data仍为空。

解决方案是在角度世界中使用Promise(或$q)。这样您就可以等待$http.get的结果。您可以保证在 4之后2始终执行(假设成功)。

答案 1 :(得分:0)

嗯,这种行为是因为JavaScript代码被执行async。一旦承诺得到解决,最好包括该代码。

$http.get("http://server/api/Blah/GetData/" + $scope.id).success(function (data) {
    $scope.data = data;
    alert($scope.data.MyObject.Property); //displays the expected value. - Not Undefined or null

    $scope.$on('$viewContentLoaded', function () {
        $timeout(function () {
            var d = document.getElementById("iframe");

            d.contentDocument.documentElement.innerHTML = $scope.data.MyObject.Property; //Now MyObject is magically undefined.           

        }, 0);
    }).error(function (data) {
    alert(data);
    });

});

这将有效:)

干杯!

答案 2 :(得分:0)

$ http请求是异步的。在触发$ viewContentLoaded事件之前,它可能无法完成。 (我想这个事件在加载DOM之后触发,并且不等待http请求完成,我可能是错的)。 为什么不这样做:

    app.controller('MyController', function ($scope, $routeParams, $http, $timeout) {
    $scope.id = $routeParams.id;

    $http.get("http://server/api/Blah/GetData/" + $scope.id).success(function (data) {
        $scope.data = data;
        alert($scope.data.MyObject.Property); //displays the expected value. - Not Undefined or null
        $timeout(function () {
            var d = document.getElementById("iframe");

            d.contentDocument.documentElement.innerHTML = $scope.data.MyObject.Property; //Now MyObject is magically undefined.           

        }, 0);
    }).error(function (data) {
        alert(data);
    });

    $scope.$on('$viewContentLoaded', function () {

    });

答案 3 :(得分:0)

由于http get是异步功能。你必须使用promises等到http获取结果。 你可以通过以下代码来做到这一点。 提供服务。

app.factory('myService', function($http) {

var getData = function(id) {

    // Angular $http() and then() both return promises themselves 
    return $http({method:"GET", url:"http://server/api/Blah/GetData/" + id}).then(function(result){

        // What we return here is the data that will be accessible 
        // to us after the promise resolves
        return result.data; //or may be return result only.
    });
    };
     return { getData: getData };
      });
控制器中的

app.controller('MyController', function ($scope, $routeParams, $http, $timeout,myService) {
$scope.id = $routeParams.id;
var Data=myService.getData($scope.id);
   Data.then(function(result){
    $scope.data.MyObject.Property=result;//or result.data may be
    $scope.$on('$viewContentLoaded', function () {
    $timeout(function () {
        var d = document.getElementById("iframe");

        d.contentDocument.documentElement.innerHTML = $scope.data.MyObject.Property; //Now MyObject is magically undefined.           

    }, 0);
});

   });

答案 4 :(得分:-2)

首先,控制器的声明缺少元素。它应该是:

app.controller('MyController', ["$scope" , "$routeParams" , "$http" , function ($scope, $routeParams, $http, $timeout) {...

检查Angular文档中的依赖注入。

尝试此操作,如果仍然无效,请使用新代码和一些记录更新您的问题。