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>
Related
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);
I am trying to create template dynamically. When I inject the hard coded value through directives attribute it works fine. But when I assign it using angular variable it does not seem to work. Below is the js code
(function(angular) {
'use strict';
angular.module('docsTemplateUrlDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
$scope.nameTempl = 'customer-name.html';
$scope.addressTempl = 'customer-address.html';
}])
.directive('myCustomer', function() {
return {
templateUrl: function(elem, attr){
return attr.type;
}
};
});
})(window.angular);
this is html part
<body ng-app="docsTemplateUrlDirective">
<div ng-controller="Controller">
<div my-customer type="{{nameTempl}}"></div>
<div my-customer type="{{addressTempl}}"></div>
</div>
</body>
Instead of using variables if i directly use values it seems to be working fine.
I dont understand why is this happening?
Plunker code
Your problem is that angular first process the template and then the DOM. So when he gets to the attr.type, it's still {{nameTemp1}}, angular has yet manipulated the DOM. My suggestion is, try to pass the address in another way. This plunker shows how you can try creating a service that would hold an object, and then bind the url to the object. Then, inject the service to the directive and use the url. Just make sure to put an "ng-if" on the directive the checks if the scope had created that object and bound it to the service's object
Here is the service
service('service', [function() {
return {
template: {}
};
}])
And this is the controller:
controller('Controller', ['$scope', 'service', function($scope, service) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
$scope.addressTempl = 'customer-address.html';
service.template.url = $scope.addressTempl;
}])
and the directive looks like this:
directive('myCustomer', function(service) {
return {
templateUrl: function(elem, attr){
return service.template.url;
}
};
})
You can use different templates as follows:
Live example on plunker.
(function(angular) {
'use strict';
angular.module('docsTemplateUrlDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
$scope.nameTempl = 'customer-name.html';
$scope.addressTempl = 'customer-address.html';
}])
.directive('myCustomer', function() {
return {
scope: {
type: "#",
customer:"=myCustomer",
},
template: '<div ng-include="type"></div>'
};
});
})(window.angular);
And html part
<body ng-app="docsTemplateUrlDirective">
<div ng-controller="Controller">
<div my-customer="customer" type="{{nameTempl}}"></div>
<div my-customer="customer" type="{{addressTempl}}"></div>
</div>
</body>
You cannot access scope in templateURL function however there is a way to load template at run time. Plunker - http://plnkr.co/edit/n20Sxq?p=preview
app.directive("cellItem", ["$compile", '$http', '$templateCache', '$parse', function ($compile, $http, $templateCache, $parse) {
return {
restrict: 'A',
link: function(scope , element, attrs) {
scope.$watch(attrs.template, function (value) {
if (value) {
loadTemplate(value);
}
});
function loadTemplate(template) {
$http.get(template, { cache: $templateCache })
.success(function(templateContent) {
element.replaceWith($compile(templateContent)(scope));
});
}
}
}
}]);
Hope this solve your issue.
I am facing a small problem during the compilation of html code in angularjs. Here is the brief description of my problem :
$scope.report= reportdata;
reportdata is the html code that contains angularcontents like : {{name}} , {{firstname}} etc.
so, I am searching for a function that can compile the above html in my controller just like this :
$scope.compiledReportdata = function() {
$scope.compildeHtml = somefunction(reportdata);
}
Is there any function that can do the trick for me , Please suggest.
This is what i have tried i works for HTML but not for Controller
angular.module('myapp')
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
ele.bind('blur', function () {
scope.$apply(attrs.uiBlur);
debugger
});
scope.$watch(attrs.dynamic, function (html) {
ele.html(html);
var data1 = ele.html(html);
var data2 = $compile(ele.contents())(scope);
$compile(ele.contents())(scope);
});
}
};
});
You can use the $interpolate service in the controller to interpolate the string...
var app = angular.module('app', ['ngSanitize']);
app.controller('controller', function ($scope, $interpolate) {
$scope.name = 'Costanza';
$scope.firstname = 'George';
$scope.report = '<strong>{{name}}</strong> , {{firstname}}';
$scope.compiledReportdata = function () {
return $interpolate($scope.report)($scope);
};
});
And you can use ngBindHtml with ngSanitize to display it...
<div ng-app="app" ng-controller="controller">
<div ng-bind-html="compiledReportdata()"></div>
</div>
JSFiddle
I have an html file with a controller and a directive with a template url. I want to load/compile the directive conditionally in the controller:
Controller:
app.controller('TestController', function TestController($http, $scope, $compile) {
$scope.loadData = function (pageId) {
var pUrl = <some url>
$http({
method: 'GET',
url: pUrl
}).success(function (data, status) {
$scope.pData = data;
var htm = '<test-directive></test-directive>';
var elm = angular.element("#id").append(htm);
$compile(elm)($scope);
}).error(function (data, status) {
alert('error');
});
};
$scope.loadData();
});
Directive:
'use strict';
app.directive('testdirective', function ($http) {
var uDirective = {};
uDirective.restrict = 'E';
uDirective.templateUrl = 'js/directives/testdirective.html';
uDirective.controller = function ($scope, $element, $attrs) {
$scope.showDirectiveData();
$scope.showDirectiveData = function () {
$scope.directiveDataCollection = <get data>;
};
};
uDirective.compile = function (element, attributes) {
// do one-time configuration of element.
var linkFunction = function ($scope, element, atttributes) {
};
return linkFunction;
};
return uDirective;
});
Template used in Directive
<div>
<div ng-repeat="directiveData in directiveDataCollection">
<span><h4>{{directiveData.Title}}</h4></span>
</div>
</div>
How do i get to compile the code in the TestController, load the directive dynamically, and finally load the content and append the content in scope?
Here is a general template for you to reference that abstracts and also demonstrates a few Angular concepts:
JS
.directive('parentDirective', function(Resource, $compile){
return {
restrict: 'E',
link: function(scope, elem, attrs){
Resource.loadData().then(function(result){
scope.data = result.data;
var htm = '<child-directive></child-directive>';
var compiled = $compile(htm)(scope);
elem.append(compiled);
});
}
}
})
.directive('childDirective', function(){
return {
restrict: 'E',
template: '<div>Content: {{data.key}}</div>'
}
})
.factory('Resource', function($http){
var Resource = {};
Resource.loadData = function(){
return $http.get('test.json');
}
return Resource;
})
HTML
<body ng-app="myApp">
<parent-directive></parent-directive>
</body>
Notice that there is no controller code. This is because controllers should never manipulate the DOM - one reason is that it will make your code a PITA to test. So, I put everything in directives, where it should probably be in your case as well.
I also moved the $http service into a factory. Anything state/model related should be in a service. Among other reasons, by doing this, you can inject it almost anywhere (including inside of directives) to access your data without worrying about it disappearing when a controller unloads.
EDIT
You should also consider the dissenting view of the dynamic loading approach in general in the accepted answer of Dynamically adding Angular directives
I am trying to create a directive that would load a template. The template will then be cached so the second time you click on the element it would not try to load it but instead get recently loaded value from $templateCache.
I am noticing that in case of the cache hit I don't get any response from $http.get() method.
<html ng-app="website">
<body ng-controller="MyController">
Click Event
<a href='#' click-load>Click Directive</a>
</body>
</html>
angular.module('website', []).directive('clickLoad', function($q, $http, $templateCache) {
return function(scope, element, attrs) {
function loadData() {
$http.get('http://fiddle.jshell.net', {
cache: $templateCache
}).then(function(result) {
alert('loaded ' + result.data.length + " bytes");
});
}
element.bind('click', loadData);
};
});
function MyController($scope, $http, $templateCache) {
$scope.load = function() {
$http.get('http://fiddle.jshell.net', {
cache: $templateCache
}).then(function(result) {
alert('loaded ' + result.data.length + " bytes");
});
}
}
I've created a fiddle simulating my scenario:
http://jsfiddle.net/3ea64/
Note that you can click Click Event link as many times as you want, however "Click Directive" link only works once if you clicked it first, it doesn't work at all if you click "Click Event" link first.
Any ideas are greatly appreciated.
I've played a bit around and used caching of AngularJS (describes here: http://docs.angularjs.org/api/ng.$http)
Here is a live demo: http://jsfiddle.net/4SsgA/
I've basically adjusted the $http syntax and use an ng-click directive instead of registering an event listener inside of the directive (just because I like it more :))
HTML:
<html ng-app="website">
<body ng-controller="MyController">
Click Event
Click Directive
</body>
</html>
JS:
angular.module('website', []).directive('clickLoad', function($q, $http, $templateCache) {
return function(scope, element, attrs) {
scope.loadData = function() {
$http({method: 'GET', url: 'http://fiddle.jshell.net', cache: true}).then(function(result) {
alert('loaded ' + result.data.length + " bytes");
});
}
};
});
function MyController($scope, $http, $templateCache) {
$scope.load = function() {
$http({method: 'GET', url: 'http://fiddle.jshell.net', cache: true}).then(function(result) {
alert('loaded ' + result.data.length + " bytes");
});
}
}
I would suggest creating a separate service that will do the job:
YourModule.factory('Utils', ['$q', '$http', '$templateCache', function ($q, $http, $templateCache) {
var Service = function() {
};
Service.prototype.TemplatePromise = function (keyOrUrl) {
var data = $templateCache.get(keyOrUrl);
if (data) {
return $.when(data);
} else {
var deferred = $.defer();
$http.get(keyOrUrl, { cache: true }).success(function (html) {
$templateCache.put(keyOrUrl, html);
deferred.resolve(html);
});
return deferred.promise;
}
};
return new Service();
}]);
Using this approach will add flexibility and isolation to the way you get templates, most probably you would want it to be done your own independent way...