2016-07-05 49 views
0

我希望有人能夠幫助我理解我在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: Navigation occurred. File: route.html TypeError: Unable to get property 'MyObject' of undefined or null reference at Anonymous function (http://server/script/route.js:43:13) at Anonymous function (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js:158:234) at e (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js:45:348) at Anonymous function (https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js:48:275)

爲什麼$ scope刪除$ scope.data.MyObject的值?是什麼讓這個問題更令人沮喪的是,如果我把警報(「」);在$ viewContentLoaded代碼中,$ scope.data.MyObject值不再是未定義的。這裏發生了什麼?

+0

所以也許'$ viewContentLoaded'火災你得到來自服務器的響應之前? –

+0

有沒有辦法強制$ viewContentLoaded等待服務器的響應? – Dave

+0

你可以等到http承諾解決 –

回答

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(假設它成功)。

+0

謝謝。這已經解決了我的問題。我需要閱讀更多關於romises。 $ http.get/post/put/etc是否返回一個promise對象? – Dave

+0

@Dave繼續前進,將名稱'promise'改爲任何其他有效的js變量名稱,它都能正常工作。簡而言之,它就像'$ http.get'在一個變量中一樣,只有當調用'variable_name.then()'時,服務纔會執行。 –

+0

@Dave您可以閱讀['http http#get']的文檔(https://docs.angularjs.org/api/ng/service/$http#get),它會返回一個'HttpPromise',它是一個Promise對象 –

-2

首先,控制器的聲明缺少元素。它應該是:

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

在Angular的文檔中檢查依賴注入。

試試這個,如果還沒有工作,用新的代碼和一些記錄更新你的問題。

+1

這是沒有必要的。大多數人正在使用'ng-annotate'或類似的東西。 OP所面臨的錯誤也與無效依賴關係的行爲不匹配。 –

+0

由您來嘗試。 – FDavidov

+0

這是爲了縮小角文件而不是依賴注入。 –

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

}); 

這將工作:)

乾杯!

+0

如果'$ viewContentLoaded'被觸發_before_'$ http'成功,這將不起作用 –

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

    }); 
+0

如果'$ http.get'在$ viewContentLoaded之前已解析,則可能會導致錯誤。哪個'iframe'可能不存在。 –

0

因爲http get是異步函數。你必須使用承諾等到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); 
}); 

    });