Angular Newbie Question:
I have a simple AngularJS test application that shows how a controller and a directive work together. The controller sets some hardcoded values aB
and aC
on the scope and the directive then displays these values in HTML. It works. Here is the JSFiddle. The code is below. When you run it, you can see the console output is as expected:
JS line #63: this.aB = null
JS line #64: this.aC = Goodbye
JS line #63: this.aB = Hello
JS line #63: this.aC = World
However, when I change the hardcoded values to ones that are retrieved from a test API, it fails. The console output is as follows:
JS line #63: this.aB = null
JS line #64: this.aC = Goodbye
JS line #63: this.aB = undefined
JS line #63: this.aC = undefined
The only change I made (seen here in this new JSFiddle) was in the controller's myFunc
function: I replaced the hardcoded values with the following:
response = $http.post('http://jsonplaceholder.typicode.com/posts',
{
'XXXXX': 'YYYYYYY'
}
)
self.scopeAB = response.id;
self.scopeAC = response.id;
I have tested the API's response via curl
and it is working fine. So why does the directive report the values of aB
and aC
as undefined
? How do I solve this problem? I can tell that it has to do with the asynchronous nature of the HTTP call. But I don't know how to make this work correctly.
HTML:
<body ng-app="myApp">
<div ng-controller="MyCtrl as ctrl">
<div ng-view></div>
<ul>
<li>{{1+1}}</li>
<li><my-directive a-b="null" a-c="'Goodbye'"></my-directive></li>
<li><my-directive a-b="ctrl.scopeAB" a-c="ctrl.scopeAC"></my-directive></li>
ab = {{ctrl.scopeAB}}, ac = {{ctrl.scopeAC}}
</ul>
</div>
</body>
Working Javascript:
myApp = angular.module('myApp',[]);
myApp.directive('myDirective',function(){
return {
restrict:'E',
scope: {
aB: '=',
aC: '='
},
controller: 'DirectiveCtrl',
controllerAs: 'dirCtrl',
bindToController: true,
template: 'aB={{dirCtrl.aB}} aC={{dirCtrl.aC}} <input ng-model="dirCtrl.aB" />'
};
}
);
myApp.controller('DirectiveCtrl', function(){
var self = this;
console.log('this.aB = ', self.aB);
console.log('this.aC = ', self.aC);
})
myApp.controller('MyCtrl', function() {
var self = this;
self.myFunc = function() {
self.scopeAB = 'Hello';
self.scopeAC = 'World';
}();
}
);
UPDATE:
Claies suggested I use this JSFiddle. But it won't work for me because I absolutely need the values of aB
and aC
to be accessible in the directive's controller. I need to vary the template based on their values. This JS Fiddle seems to show them as always undefined in there.
Claies suggested I use this JSFiddle. But it won't work for me because I absolutely need the values of aB and aC to be accessible in the directive's controller. I need to vary the template based on their values. This JS Fiddle seems to show them as always undefined in there.
If you use @Claies methodology, you need to put a $watch
on the object that fires when the $http
request resolves.
myApp.controller('DirectiveCtrl', function($scope){
var self = this;
$scope.$watch(function() {return self.scopeObject}, function (objVal) {
console.log("watch fired");
console.log('objVal.aB = ', objVal.aB);
console.log('objVal.aC = ', objVal.aC);
},true);
});
The DEMO on JSFiddle.
Frankly I think you are better off following the advice from @jumbopap. Use the httpPromise and the .then
method and retrieve the data from the onFulfilled
function.