How can I use both $http and $timeout in AngularJS directive? - angularjs

This is a part of my codes
Object_Angular.directive("ntgChangeScanInnerHtmlWorkshop", ["$timeout", function($timeout){ ...
But I need to also get access to $http since I want to load things from my API. How can I do this?
What I have is a display of _ids in a <p></p>. Let say I have <p>{{collections._id}}</p>. I want that <p></p> to display the name field (collections.String_Name) not the _id. So I think to take the inner HTML of the <p>{{collections._id}}</p> after the value loads and then GET the String_Name from the API via { _id: innerHTMLValueOfP } then in .success I do set back the inner value with result.String_Name. Hence I need to have $http and $timeout in my directive to achieve this.

Example of using $http in directive
app.directive('myTag', ['$http', function($http) {
return {
restrict: 'E',
transclude: true,
replace: true,
scope:{
src:"="
},
controller:function($scope){
console.info("enter directive controller");
$scope.gallery = [];
console.log($scope.src);
$http({method: 'GET', url:$scope.src}).then(function (result) {
console.log(result);
}, function (result) {
alert("Error: No data returned");
});
}
}
}]);
or
app.directive('example', function( $http){
return {
restrict:'E',
link: function($scope,$element,$timeout){
$http.post('/example', {
data
}).success(function(data){
}).error(function(data){});
}
});

Related

AngularJS show result of HTTP request inside directive in template

I'm trying to make GET request the first time I load an AngularJS (1.6) directive and show its result in the directive's template.
What I am trying so far is the following:
JS:
app.directive("myDirective", ['$http', function($http) {
return {
restrict: 'AE',
attrs: {
foo : String,
onResponse : function(response){
this.foo = response.data;
}
},
templateUrl: 'templates/my-directive.html',
compile: function(scope, element, attrs) {
$http({
method: 'GET',
url: 'my/url'
}).then(
attrs.onResponse
);
}
}
}]);
the HTML template:
<div id="my-directive">
foo: <span>attrs.foo</span>
</div>
Is there a way to do this properly?
Thanks in advance!
Well, I managed to do what I wanted by adding a controller:
app.directive("myDirective", ['$http', function($http) {
return {
restrict: 'AE',
controller: "myDirectiveController",
templateUrl: 'templates/my-directive.html'
}
}]);
where
app.controller('myDirectiveController', function ($scope, $http) {
$scope.foo;
$scope.onResponse = function(response){
$scope.foo= response.data;
}
$http({
method: 'GET',
url: 'my/url'
}).then(
$scope.onResponse
);
});
and the template looks like this:
<div id="my-directive">
foo: <span>{{foo}}</span>
</div>
Probably this is not the proper way to do it but it works.. Any suggestions are welcome!

How to pass the $http service result from directive's controller to link function

trying to access the $http service response in controller part of the directive and store in $scope object of controller which is not happening,
and I want to access this scope variable in directive's link function
Below is the directive code
angular.module('baseapp')
.directive('renderTable',['loadService',function(loadService){
return{
scope:{},
replace:true,
controller:['$scope',function($scope){
$scope.productsList={};
$scope.init=function(){
//$scope.productsList = loadService.productList;
$scope.getAllProducts();
}
$scope.getAllProducts=function(){
loadService.getData().then(function(response){ ---
*//here I am getting the response and trying to store it in $scope which is not happening*
$scope.productsList = response.products;
});
}
$scope.init();
console.log("$scope.productsList"+JSON.stringify($scope.productsList));
}],
link:function(scope,elem,attrs){
console.log("scope.productsList"+JSON.stringify(scope.productsList));
}
}
}]);
After debugging the code what I found is before the $http code call is executing, the entire code of the directive is getting executed (asynchronous), so I am not able to store it in the variable.
For this checked some posts in the same blog found suggestions to use like promises, implemented them also, but facing the same problem, some posts showed some timers which is not working....
changed the code in all the ways I could do yet not working
Could you please suggest me some workouts for the solution
Below is the service code which is working fine I am able to inject the dependency in directive
angular.module('baseapp')
.service('loadService',function($http, $q){
var loadService = this;
loadService.productList = {};
return{
getData : function(){
return $http.get('./resources/js/products.json')
}
}
});
You can do it with $rootScope and NgModelController.
Your directive could look like:
app.directive('renderTable', function () {
return {
restrict: 'EA',
replace: true,
scope: {},
require: 'ngModel',
controller: function ($rootScope, $http) {
$http.get('products.json').success(function(resp) {
$rootScope.products = resp;
console.log("directive's controller: " + JSON.stringify($rootScope.products));
});
},
link: function (scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(modelValue) {
return modelValue;
});
ngModelCtrl.$render = function () {
var products = ngModelCtrl.$viewValue;
console.log("link function: " + JSON.stringify(products));
}
}
}
});
Working plunk here
See NgModelController docs
Try $scope.productsList = response.data;

pass service variables to directive

I am trying to fetch data from json file in a service fetchJsonDir and want to use response in a directive mcsaForm to count the total number of options in json file and create radio buttons depend on the number of options by using DOM. I can access the json file inside $http.get() method but not able to access outside of it.
How can I access the getObj variable in mcsaForm directive and where do I write the code for creating radio buttons dynamically in directive so that it all happens on form load?
json file
{
"Options" :
{
"Option1" : "Option one",
"Option2" : "Option two",
"Option3" : "Option three",
"Option4" : "Option four"
}
}
service:
myApp.service("fetchJsonDir", function($http){
var getObj;
var myJsonFilePath = "json/myNewJson.json";
$http.get(myJsonFilePath)
.success(function(response){
getObj = response;
console.log(getObj); // output: json file object
});
console.log(getObj); // output: undefined
return{
getObjOne : getObj
}
});
directive:
myApp.directive("mcsaForm",['fetchJsonDir', function(fetchJsonDir){
return{
restrict: "C",
templateUrl: "templateBlocks/multChoiceSingleSel.html",
compile: function(element, attrs)
{
$("#mcss_option_list").append("How are you?");
},
controller: function($scope){
$scope.getObjs = fetchJsonDir.getObjOne;
console.log(fetchJsonDir.getObjOne); //output: undefined
console.log($scope.getObjs); //output: undefined
$scope.onSubmitHidePanel = function()
{
$(".mcsa_form").fadeOut("slow", function(){
$(this).remove();
});
}
}
}
}]);
You get json from the server-side so you need to wait untill the server returnes response. Change the service to:
myApp.service("fetchJsonDir", function($http){
var myJsonFilePath = "json/myNewJson.json";
return $http.get(myJsonFilePath)
});
And directive to:
myApp.directive("mcsaForm",['fetchJsonDir', function(fetchJsonDir){
return{
restrict: "C",
templateUrl: "templateBlocks/multChoiceSingleSel.html",
compile: function(element, attrs)
{
$("#mcss_option_list").append("How are you?");
},
controller: function($scope){
fetchJsonDir.then( function( data ){
$scope.getObjs = data.data;
});
$scope.onSubmitHidePanel = function()
{
$(".mcsa_form").fadeOut("slow", function(){
$(this).remove();
});
}
}
}
}]);
Your service should return a promise rather then the object like this
myApp.factory("fetchJsonDir", function($http){
var myJsonFilePath = "json/myNewJson.json";
return{
getObjOne : $http.get(myJsonFilePath)
}
});
Then you can use it in the directive as follows:
myApp.directive("mcsaForm",['fetchJsonDir', function(fetchJsonDir){
return{
restrict: "C",
templateUrl: "templateBlocks/multChoiceSingleSel.html",
compile: function(element, attrs)
{
$("#mcss_option_list").append("How are you?");
},
controller: function($scope){
fetchJsonDir.getObjOne().then(function(response){
$scope.getObjs = response.data;
console.log($scope.getObjs);
});
$scope.onSubmitHidePanel = function()
{
$(".mcsa_form").fadeOut("slow", function(){
$(this).remove();
});
}
}
}
}]);
Remember, you are sending an asynchronous ajax request,you need to handle asynchronous operations through promises.
Also note that since you are returning an object from you service, it should be decalred as a factory.

angular directive handles http request

I have angular directive that accept url to obtain remote data:
<my-tag src="http://127.0.0.1/srv1">...
Directive itself:
app.directive('myTag', ['$http', function($http) {
return {
restrict: 'E',
transclude: true,
replace: true,
//template: '<div ng-repeat="imgres in gallery">{{imgres.isUrl}}\'/></div>',
scope:{
src:"#", //source AJAX url to dir pictures
},
controller:function($scope){
console.info("enter directive controller");
$scope.gallery = [];
$http.get($scope.src).success(function(data){
console.info("got data");
$scope.gallery.length = 0;
$scope.gallery = data;
});
}
}
In general it works and I can see in FireBug console:
enter directive controller
GET http://127.0.0.1/srv1
got data
But If I'm placing second instance of directive bind to another url:
<my-tag src="http://127.0.0.1/srv2">...
Works only one with following log:
enter directive controller
GET http://127.0.0.1/srv1
enter directive controller
GET http://127.0.0.1/srv2
got data <-- as usual it relates to first directive
Couldn't you help me what is wrong with 2 directive nstances
First of all I don't see any problem. You use directive several times therefore isolate scope is right way.
I just changed src:"#" to src:"=".
Demo Fiddle
HTML
<div ng-controller = "fessCntrl">
<my-tag src="'http://maps.googleapis.com/maps/api/geocode/json?address=Singapore, SG, Singapore, 153 Bukit Batok Street 1&sensor=true'"></my-tag>
<my-tag src="'http://maps.googleapis.com/maps/api/geocode/json?address=Singapore, SG, Singapore, 3 Bukit Batok Street 1&sensor=true'"></my-tag>
</div>
JS
app.directive('myTag', ['$http', function($http) {
return {
restrict: 'E',
transclude: true,
replace: true,
scope:{
src:"="
},
controller:function($scope){
console.info("enter directive controller");
$scope.gallery = [];
console.log($scope.src);
$http({method: 'GET', url:$scope.src}).then(function (result) {
console.log(result);
}, function (result) {
alert("Error: No data returned");
});
}
}
}]);

AngularJS pass $resource as a directive parameter

I have just came up with a directive that loads a dropdown box according to a list coming from an API call ($resource).
Controller:
App.controller(
'TestCtrl', [
'$scope', 'countriesFactory',
function($scope, countriesFactory){
/* Call API */
countriesFactory().then(function(data){
$scope.countryList = data;
});
}])
The API call returns:
{"country":[{"code":"ABW","label":"Aruba"},{"code":"AFG","label":"Afghanistan"},{"code":"AGO","label":"Angola"}]}
Template:
<input-select model-ref-list="countryList"></input-select>
Directive:
App
.directive("inputSelect"
, function() {
var Template =
'<select ng-options="item.label for item in modelRefList" required></select>';
return {
restrict: 'EA',
template: Template,
scope: {
modelRefList: '='
},
link: function(scope){
console.log(scope.modelRefList);
}
};
}
);
First of all: I simplified a lot the overall issue, so that it looks that the directive is completely overkill in that situation, but in the end, it is not :D.
Problem: My console.log is always undefined.
I made a bit of research and realized that I needed to play with promises to wait for my country list to appear to be actually given to the directive.
So I tried modifying my controller and not use the result of the API call promise, but directly the resource itself:
New Controller:
App.controller(
'TestCtrl', [
'$scope', 'countriesFactory',
function($scope, countriesFactory){
/* Call API */
$scope.countryList = resourceAPICall();
}])
But still undefined :/.
How can I pass direclty the resource (containing the promise I can then use to defer the load of the select) to the directive?
SOLUTION FOR ANGULARJS 1.2:
Directive:
App
.directive("inputSelect"
, function() {
var Template =
'<select ng-options="item.label for item in modelRefList" required></select>';
return {
restrict: 'EA',
template: Template,
scope: {
modelRefList: '='
},
link: function(scope){
scope.modelRefList.$promise.then(function(data){
console.log(data);
}
};
}
);
To pass a API call result to a directive, you need to pass its resource and play with its promise inside the directive itself.
Thanks everybody for the help.
Here we simulated async call factory by using wrapper with $q.
We changed modelReflist to modelRefList
added ng-model="item" to template
HTML
<div ng-controller="TestCtrl">
<input-select model-ref-list="countryList"></input-select>
</div>
JS
var App = angular.module('myModule', ['ngResource']);
App.controller(
'TestCtrl', [
'$scope', 'countriesFactory',
function ($scope, countriesFactory) {
/* Call API */
countriesFactory.resourceAPICall().then(function (data) {
$scope.countryList = data.country;
console.log($scope.countryList);
});
}])
App.$inject = ['$scope', 'countriesFactory'];
App.directive("inputSelect", function () {
var Template = '<select ng-model="item" ng-options="item.label as item.label for item in modelRefList" required></select>';
return {
restrict: 'EA',
template: Template,
scope: {
modelRefList: '='
},
link: function (scope) {
console.log(scope.countryList);
}
};
});
App.factory('countriesFactory', ['$resource', '$q', function ($resource, $q) {
var data = {
"country": [{
"code": "ABW",
"label": "Aruba"
}, {
"code": "AFG",
"label": "Afghanistan"
}, {
"code": "AGO",
"label": "Angola"
}]
};
var factory = {
resourceAPICall: function () {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
}]);
Demo Fiddle
modelReflist needs to be fully camel-cased in your directive scope. modelRefList.

Resources