【问题标题】:AngularJS $scope dropping value after it is assignedAngularJS $scope 赋值后丢弃值
【发布时间】:2016-11-06 19:50:45
【问题描述】:

我希望有人能帮助我理解我在 AngularJS 中使用 $scope 时遇到的烦人问题。请参阅下面我的代码中的 cmets:

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:发生导航。 文件:路由.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 的值?让这个问题更令人沮丧的是,如果我放了一个 alert("");在 $viewContentLoaded 代码中,$scope.data.MyObject 值不再未定义。这是怎么回事?

【问题讨论】:

  • 所以$viewContentLoaded 可能会在您收到服务器响应之前触发?
  • 有没有办法强制 $viewContentLoaded 等待服务器的响应?
  • 你可以等到http promise解决

标签: javascript angularjs


【解决方案1】:

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

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

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 成功之前执行。所以它@98​​7654327@ 仍然为空。

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

【讨论】:

  • 谢谢。这解决了我的问题。我需要阅读更多关于 romise 的内容。 $http.get /post /put /etc 是否返回一个承诺对象?
  • @Dave 将名称 promise 更改为任何其他有效的 js 变量名称,它就可以正常工作。简单来说,就像$http.get被带入一个变量,服务只有在variable_name.then()被调用时才会执行。
  • @Dave 你可以阅读$http#get 的文档,它返回一个HttpPromise,它是一个Promise 对象
【解决方案2】:

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

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

});

这会起作用:)

干杯!

【讨论】:

  • 如果$viewContentLoaded 被触发之前 $http 成功,这将不起作用
【解决方案3】:

$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 () {

    });

【讨论】:

  • 如果$http.get$viewContentLoaded 之前解决,这可能会导致错误。其中iframe 可能不存在。
【解决方案4】:

由于 http get 是异步函数。您必须使用承诺等到 http get 获取结果。 您可以通过以下代码执行此操作。 做一个服务。

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

   });

【讨论】:

    【解决方案5】:

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

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

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

    试试这个,如果还是不行,用新代码和一些日志更新你的问题。

    【讨论】:

    • 这不是必需的。大多数人都在使用ng-annotate 或类似的东西。 OP 面临的错误也与无效依赖项的行为不匹配。
    • 你来试试吧。
    • 这是为了缩小 Angular 文件而不是依赖注入。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-26
    相关资源
    最近更新 更多