我经常遇到问题,我在父控制器中设置了范围变量,子控制器调用此范围变量。但是,它在函数能够设置范围元素之前调用它,导致它返回undefined。例如:
家长控制器:
module.controller('parent', '$scope', '$http', function ($scope, $http) {
$scope.init = function(profileID, profileViewStatus) {
//Initiiaze user properities
$http.get(requestUserInformationGetURL + profileID)
.success(function(profile) {
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
console.log($scope.userID);
})
.error(function() {
exit();
});
}
儿童控制器:
module.controller('child', function($scope, $http, fetchInfo) {
console.log($scope.userID);
//Fetch the HTTP POST data for the user profile
var promise = $http({
method: "post",
url: fetchInfo,
data: {
user_id: $scope.userID //From the parent controller
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
promise.then(function(successResponse) {
//Populate the scope, log the data
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
HTML:
<div ng-controller="parent" init="init('<?php $user_id;?>')">
<div ng-controller="child">
</div>
</div>
经常发生的情况是,userID将在子控制器中报告为未定义,但之后,它将按照父控制器中的定义报告回来。显然,在父控制器中的init函数完成之前,正在调用使用$ scope.userID的子控制器。在init函数完成之前,如何强制AngularJS在子控制器中等待?我尝试过类似的事情:
if (!$scope.userID) {
$scope.$digest();
}
但它没有用,我不认为它是正确的语法。我想,我不完全理解AngularJS的Asycn性质,这种情况多次发生。你如何控制DOM加载元素来解决这个问题呢?
答案 0 :(得分:1)
在这种情况下,正确的方法是使用专用服务来处理异步操作,请求,数据缓存等。但由于您还没有服务层,我将使用控制器范围提出简单的基于Promise的解决方案承诺对象。
检查修改后的代码:
module.controller('parent', ['$scope', '$http', function ($scope, $http) {
$scope.init = function (profileID, profileViewStatus) {
$scope.profilePromise = $http.get(requestUserInformationGetURL + profileID).success(function (profile) {
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
})
.error(exit);
}
}]);
module.controller('child', function($scope, $http, fetchInfo) {
// Fetch the HTTP POST data for the user profile
$scope.profilePromise.then(function() {
return $http({
method: "post",
url: fetchInfo,
data: { user_id: $scope.userID },
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
})
.then(function(successResponse) {
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
});
如您所见,仍然调用父控制器init
方法,但现在它立即设置范围属性profilePromise
,可以在子控制器中访问。
子控制器使用父控制器then
对象的profilePromise
方法,该方法保证在配置文件可用后,$http
使用$scope.userID
请求将会触发。
答案 1 :(得分:1)
通常,您将使用UI路由器解析路由,以确保在构建任一控制器之前完成工作。子状态自动可以访问其父级的结果。
//Router configuration
.state('app.inspections.list', {
url: '',
templateUrl: 'Template/parent',
controller: "Parent as vm",
resolve: {
profile: ['$http', function ($http) {
return $http.get(requestUserInformationGetURL + profileID)
.success(function(profile) {
console.log(profile.userID);
return profile;
})
.error(function() {
exit();
});
}]
}
}).state('parent.child', {
url: 'child',
templateUrl: 'Template/child',
controller: "Child as vm"
})
//parent controller
module.controller('parent', '$scope', 'profile', function ($scope, profile){
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
}
//child controller
module.controller('child', 'profile', function($scope, $http, fetchInfo, profile){
console.log(profile.userID);
//Fetch the HTTP POST data for the user profile
var promise = $http({
method: "post",
url: fetchInfo,
data: {
user_id: profile.userID //From the parent controller
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
promise.then(function(successResponse) {
//Populate the scope, log the data
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
答案 2 :(得分:1)
你可以使用promise($ q service):尝试使用这段代码:
父控制器:
$scope.init = function(profileID, profileViewStatus) {
var deferred = $q.defer();
$http.get(requestUserInformationGetURL + profileID)
.success(function(profile) {
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
deferred.resolve($scope.userID);
console.log($scope.userID);
})
.error(function() {
deferred.reject('error');
exit();
});
return deferred.promise;
}
不要在父控制器中调用init方法。
子控制器中的:
$scope.init().then(function(userID){
var promise = $http({
method: "post",
url: fetchInfo,
data: {
user_id: userID //From the parent controller
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
promise.then(function(successResponse) {
//Populate the scope, log the data
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
})
.catch(function(error){
console.log('error');
})
答案 3 :(得分:0)
您的问题可能是异步调用$.get
,这是默认行为。您的init
方法实际上可能按照您预期的顺序进行调用,但发生的是:
init
被称为$.get
被调用,但服务器的响应是非瞬时的init
的儿童$.get(..).success(function(data){...});
被调用来处理数据我建议其他人使用承诺推迟执行。