Reputation: 3359
I'm trying to use Angular in a more web-component style. So I have created an http-request directive that has a url and a response attribute. It works quite well but my directive is reliant on a template and I would like to remove that as it is hacky and the directive doesn't need a template. Here is my code
<div>
<http-request url="http://jsonplaceholder.typicode.com/posts" response="items"></http-request>
<ul>
<li ng-repeat="item in items">{{ item.id }}</li>
</ul>
</div>
var myApp = angular.module('myApp', []);
myApp.directive('httpRequest', ['$http', function ($http) {
return {
restrict: 'E',
replace: true,
scope: {
response: '='
},
template: '<input type="text" ng-model="response" style="display:none"/>',
link: function (scope, element, attributes) {
$http.get(attributes.url)
.then(function (response) {
scope.response = response.data;
});
}
}
}]);
Fiddle: http://jsfiddle.net/HB7LU/9558/
Upvotes: 0
Views: 31
Reputation: 6958
Update your directive to the following:
myApp.directive('httpRequest', ['$http', function ($http) {
return {
restrict: 'E',
replace: true,
scope: {
response: '='
},
link: function (scope, element, attributes) {
//create response object if it doesn't exist
scope.response = scope.response || {};
$http.get(attributes.url)
.then(function (response) {
//write to items property of response object
scope.response.items = response.data;
});
}
}
}]);
Then loop over your response.items where you use the directive:
<http-request url="http://jsonplaceholder.typicode.com/posts" response="response">
</http-request>
<ul>
<li ng-repeat="item in response.items">{{ item.id }}</li>
</ul>
Updated fiddle.
The way you were doing it (with the template inside the directive) was reassigning the reference inside the isolate scope to be the $http data. This was then being bound to the ng-model="response"
(through the watch) and published back out through the two way binding. You are also using an old version of angular. Newer versions look like you don't need to do this work around, just remove the template.
Edit:
Since you said you didn't like binding to an items property. You can change your directive to look like this (uses $parse service to set the value on scope). This works with the older version of angular too:
myApp.directive('httpRequest', ['$http', '$parse', function ($http, $parse) {
return {
restrict: 'E',
replace: true,
link: function (scope, element, attributes) {
//use $parse to assign this value to scope
var responseSetter = $parse(attributes.response).assign;
$http.get(attributes.url)
.then(function (response) {
//call the "setter" against scope with the data
responseSetter(scope, response.data);
});
}
}
}]);
Demo.
Upvotes: 1
Reputation: 1651
Your directive doesn't have to have a template, since there's nothing you need to render visually. All you're doing is setting scope variables to encapsulate the state of the request as it's being made and then reacting to the response status and data.
Have a look at https://github.com/coding-js/directives/tree/solutions/datasource from a recent JS meetup I helped run.
Upvotes: 0