Angular directive not capturing values in local scope - angularjs

I have the following html.
<h2>{{ profile.first_name }} {{ profile.last_name }}</h2>
<p>{{ profile.organisation_name }}</p>
<p>{{ profile.email }}</p>
<p>{{ profile.phone }}</p>
<div class="row marketing">
<transform xml="{{ profile.profiles.profile }}" xslt="LawyerProfile.xslt"/>
</div>
I have an angular service that populates profile object. I have some xml data in {{ profile.profiles.profile }} that I want to transform using a directive.
So I pass in the data and xslt file to apply transform from.
my directive looks like this
'use strict';
clientApp.directive("transform", function () {
return {
restrict: "E",
scope: {
xml: "#",
xslt: "#"
},
replace: true,
transclude: false,
link: function (scope, element) {
console.log(scope);
console.log(scope.xml);
console.log(scope.xslt);
}
};
});
When I inspect the scope object, it have xml data as string in scope.xml but when I console.log it, its not there.
console.log(scope.xslt); works just fine.
Any help will be much appreciated, thanks.
UPDATED:
profileController.js
'use strict';
clientApp
.controller('profileController', function($scope, $routeParams, profileService) {
profileService.getProfile($routeParams.id, $routeParams.publication)
.then(function(profile) {
$scope.profile = profile;
});
});
profileService.js
'use strict';
clientApp.factory('profileService', function($http, $q) {
return {
getProfile: function(id, publication) {
var deferred = $q.defer();
var url = 'http://192.168.7.37:3000/lawyer/' + id + '/' + publication;
$http({ method: 'GET', url: url })
.success(function(data, status, headers, config) {
deferred.resolve(data);
})
.error(function(data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
}
};
});

The problem is that xml is bound to an interpolated value, which is from the $resource service, therefore it's a good idea to use $timeout to let angular's digest cycle finish before you do anything else.
You can try something like this:
.directive("transform", function ($timeout) {
return {
...
link: function (scope, element) {
...
$timeout(function() {
console.log(scope.xml);
}, 0);
}
};
});

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!

Angularjs passing variable to a directive's controller

I am creating Angularjs Directive. However i need to pass a paramter to the directive and use it in its controller to populate its items using $http service.
i am passing a "listId" parameter to the directive, the controller inside the directive expects this parameter to retrieve items of that list from the server.
The code in the controller embedded in the directive is commented.
<script type="text/javascript">
var app = angular.module('app', []);
app.controller('metadataCtrl', function ($scope, $http) {
});
app.directive('mydirective', function ($http) {
return {
restrict: 'AE',
template: '<div ng-repeat="model in items">{{ model.name}} </div>',
replace: true,
scope: {
listId: '='
},
controller: function ($scope) {
//console.log(scope.listId);
// console.log(listId);
//$http({ method: 'GET', url: 'http://localhost:62624/home/listvalues?listid=' }).then(function (response) {
// $scope.items = response.data;
//}, function (result) { alert("Error: No data returned"); });
},
link: function (scope, element, attrs) {
console.log(scope.listId);
}
};
});
</script>
The HTML code
<body ng-app="app">
<form name="myForm" ng-controller="metadataCtrl" class="my-form">
<mydirective list-id="99"></mydirective>
</form>
</body>
The listId can be accessed in the link() function in the directive (i am using console.log() to test that). However, this doesn't work in the controller function.
In the controller, use injected $scope.
controller: function ($scope) {
//USE $scope
console.log($scope.listId);
//
//console.log(scope.listId);

How to include JSON object in AngularJS without writing JavaScript?

I have a JSON file with this object:
{"software":[
{"name":"Eclipse", "version":"4.5"},
{"name":"Sublime Text", "version":"3.0"},
{"name":"ConEmu", "version":"1.5"}
]}
I want to get the values using the AngularJS built-in directives, I tried with ng-include and ng-repeat, but doesn't work:
<div ng-include="'software.JSON'" ng-repeat="sw in software">{{sw.name}} v{{sw.version}}</div>
Demo app:
var MyApp = angular.module("MyApp",[]); // Inject app dependencies here
Declare service to fetch JSON file:
MyApp.factory("ConstantsService", ["$http", function($http){
var ConstantsService = {};
ConstantsService.getConstants = function(){
return $http({
method: "GET",
url: "constants.json", //JSON file location
headers: {
'Content-Type': 'application/json'
}
})
.then(function(data){
return data;
});
}
return ConstantsService;
}]);
Inject ConstantsService into your controller and access JSON content:
MyApp.controller('FetchJsonController', ['$scope', 'ConstantsService', function($scope, ConstantsService){
ConstantsService.getConstants().then(function(response){
console.log(response.data.software); //Software object declared in JSON file
$scope.software = response.data.software;
});
}]);
Finally define template:
<div ng-controller="FetchJsonController">
<div ng-repeat="sw in software">{{sw.name}} v{{sw.version}}</div>
</div>
ng-include directive is not made for this purpose.
ngInclude
directive in module ng
Fetches, compiles and includes an external HTML fragment.
Try achieving it with an $http.get in your controller. But if you really need a directive for it...
http://jsfiddle.net/U3pVM/22528/
JS
(function() {
var app = angular.module('app', []);
app.controller("IncludeJsonController", IncludeJsonController);
app.directive("includeJson",[function() {
return {
template: "<div ng-repeat=\"sw in vm.software\"><p>{{ sw.name }} v{{ sw.version}}</p></div>",
controller: "IncludeJsonController",
restrict: "E",
link: function(scope, element, attr, ctrl) {
scope.vm = {};
scope.vm.filename = attr.filename;
scope.vm.software = ctrl.getSoftwares();
}
}}]);
IncludeJsonController.$inject = ['$scope', '$http'];
function IncludeJsonController($scope, $http) {
var self = this;
self.getSoftwares = getSoftwares;
function getSoftwares() {
//in your case, use $http.get('path/to' + $scope.vm.filename);
return [
{"name":"Eclipse", "version":"4.5"},
{"name":"Sublime Text", "version":"3.0"},
{"name":"ConEmu", "version":"1.5"}
];
}
}
}());
HTML
<div ng-app="app">
<include-json filename="software.json"></include-json>
</div>

Directive scope got undefined

I get an issue with passing data to angular directives inside ng-repeat, it always got undefined. Here are my code
The Controller:
angular.module('module').controller('ModuleController', ['$scope', 'MyService', function($scope, MyService) {
$scope.getData = function() {
$scope.data = MyService.myGetRequest(); // returning array of objects
};
});
View:
<div ng-controller="ModuleController" ng-init="getData()" ng-switch="data.length > 0">
<div ng-repeat="d in data" ng-switch-when="true">
<my-directive data="d.object"></my-directive>
</div>
</div>
Directive:
angular.module('module').directive('myDirective', [function() {
return {
restrict: 'E',
template: '<div></div>' // let's ignore the template for now,
scope: { data: '=' },
link: function(scope, el, attrs) {
console.log(scope.data); // always undefined
}
};
}]);
Service:
angular.module('module').factory('MyService', ['$resource', function($resource) {
return $resource('/data/:id',
{ id: '#_id' },
{
myGetRequest: { method: 'GET', isArray: true }
});
}]);
I thought it was because the $scope.data still empty when the template loaded. If yes, anyone know what is the solution? Thanks in advance. :)
EDIT: btw, if I put <my-directive data="data"></my-directive> instead of <my-directive data="d.object"></my-directive> the scope.data is not undefined anymore, it will show my array of object from resource.
EDIT2: this <my-directive data="d"></my-directive> will also resulting scope.data in my directive got undefined.
EDIT3: Add service code snippet
I think Shomz found the problem. You should use a promise with async call. Like this:
angular.module('module').controller('ModuleController', ['$scope', 'MyService',
function($scope, MyService) {
$scope.data = [];
MyService.myGetRequest().$promise.then(function(data) {
$scope.data = data;
});
}
});

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