问题
I'm new to Angular. I'm trying to use components (1.6). In the parent, I have an $http.get
that gets data from a service and then assigns the response to a $scope
variable. That scope variable is passed to a child component using one-way binding <
. In the JavaScript, if I alert the variable passed in, I get "undefined", however, the html template in the child does show the variable. It's like there is a race condition happening and I don't know how to tell it to wait until the data from the service is loaded.
In my parent.js:
(function (angular) {
'use strict';
$http.get("http://localhost:52422/api/PayOffYourCc")
.then(function mySucces(response) {
$scope.baseline = response.data;
}
,
function myError(respone) {
$scope.baseline = response.statusText;
}
);
})(window.angular);
In my parent HTML template:
<thermometer baseline="baseline"></thermometer>
In my child component:
(function (angular) {
'use strict';
function drawChart(baselineVal) {
alert(baselineVal);
}
function ThermometerController($scope) {
var ctrl = this;
ctrl.$onInit = function () {
drawChart(ctrl.baseline);
};
}
angular.module('payOffYourCcApp').component('thermometer', {
templateUrl: '../PayOffYourCC/partials/thermometer.html',
transclude: true,
controller: ThermometerController,
bindings: {
baseline: '<'
}
});
})(window.angular);
In my child html template:
<div>
baseline:{{$ctrl.baseline}}
</div>
In the html, {{$ctrl.baseline}}
is displayed fine, but when I alert it in the .js, it's undefined
. Why is that? How can I make sure the {{$ctrl.baseline}}
is in scope before the javascript loads?
回答1:
Use the $onChanges
life-cycle hook:
function ThermometerController($scope) {
var ctrl = this;
/* REPLACE THIS
ctrl.$onInit = function () {
drawChart(ctrl.baseline);
}; */
// WITH THIS
ctrl.$onChanges = function (changesObj) {
if (changesObj.baseline && changesObj.baseline.currentValue) {
drawChart(changesObj.baseline.currentValue);
};
};
}
The controller needs to wait for the data to come from the server. By using the $onChanges life-cycle hook, the drawChart
function will be called when the data becomes available and will be called on subsequent updates.
For more information, see AngularJS Comprehensive Directive API Reference - Life-Cycle Hooks.
回答2:
With Angular component, you should privilege communication from the child back to the parent since it allows a very cheap binding (&
)
You can communicate from the parent to the child but it is more expensive (=
).
I will give you an example on how to do it.
It is a not tested solution but you should have the idea.
You should change your parent to have a child api to transmit the data :
JS Parent :
(function (angular) {
'use strict';
$http.get("http://localhost:52422/api/PayOffYourCc")
.then(function mySucces(response) {
$scope.baseline = response.data;
$ctrl.apiChild.transmit(response.data);
}
,
function myError(respone) {
$scope.baseline = response.statusText;
}
);
})(window.angular);
HTML Parent :
<thermometer api="$ctrl.apiChild"></thermometer>
Change your child to have a function to receive the data from the parent and also change the binding to "="
:
JS Child :
(function (angular) {
'use strict';
function drawChart(baselineVal) {
alert(baselineVal);
}
function ThermometerController($scope) {
var ctrl = this;
ctrl.$onInit = function () {
drawChart(ctrl.baseline);
ctrl.api = {};
ctrl.api.transmit = ctrl.transmitData;
};
this.transmitData = function transmitData(data){
// here you get the data from the parent to the child
}
}
angular.module('payOffYourCcApp').component('thermometer', {
templateUrl: '../PayOffYourCC/partials/thermometer.html',
transclude: true,
controller: ThermometerController,
bindings: {
api : '='
}
});
})(window.angular);
回答3:
This is the result of the fact that $http requests are asynchronous. The alert that happens when the child component initializes prints undefined
, because at that instance the $http request that is retrieving the data has not returned yet. Since you're using >
binding however, the template in your child component will update with the correct value as soon as the request resolves (which is pretty darn fast), so you don't ever see undefined
actually printed in the template. In fact, I don't think angular will print undefined, I think it's just blank. So to your eye, it looks like it has the right value right away, when, in reality, it was momentarily undefined while the $http request was resolving.
来源:https://stackoverflow.com/questions/41227794/angular-component-one-time-binding-from-http-shows-undefined