Dynamically displaying template in ng-repeat directive in AngularJS? - angularjs

I am attempting to dynamically display one of several templates within an ng-repeat directive, based on the current item.
My JSON data looks like this:
data: {
groups: [
{
name: "Group 1",
sections: [
{ name: "Section A" },
{ name: "Section B" }
]
},
{
name: "Group 2",
sections: [
{ name: "Section A" },
{ name: "Section B" }
]
}
]
}
My goal is to render the tree of data dynamically, with each group containing multiple sections. The groups will all have the same template, but each section should have its own template, based on the name field.
Assuming the top level HTML is:
<div ng-repeat="group in groups">
{{ group.name }}
<div ng-repeat="section in sections">
<!-- Dynamic section template used -->
</div>
</div>
Ideally, each section would also need to have its own scoped data and controller associated with it. I've had good luck building this type of system with Knockout but am trying to understand the Angular way of doing things.

You could do something like this:
<div ng-repeat="group in groups">
{{ group.name }}
<div ng-repeat="section in sections" ng-include="getIncludeFile(section)">
<!-- Dynamic section template used -->
</div>
</div>
Then in your controller:
$scope.getIncludeFile = function(section) {
// Make this more dynamic, but you get the idea
switch (section) {
case "Section A":
return 'partials/sectiona.html';
case "Section B":
return 'partials/sectionb.html';
}
}
Then your sectiona.html could look like this (to have a controller specific to that file):
<div ng-controller="SectionAController">
<!-- HTML in here, and can bind straight to your SectionAController -->
</div>

In the past month there was a checkin to angular for supporting dynamic templates in a directive however I wasn't able to find very much information with regards to its use. Here is the reference. https://github.com/angular/angular.js/pull/1849
Although this still uses the the same nginclude it is all encapsulated in two directives:
Demo: http://plnkr.co/edit/4DIlHMNlHQ8Wm9XHNycH?p=preview
HTML:
<groups-control groupdata="groups"></groups-control>
Controller:
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
var json = {data: {
groups: [
{
name: "Group 1",
sections: [
{ name: "Section A" },
{ name: "Section B" }
]
},
{
name: "Group 2",
sections: [
{ name: "Section A" },
{ name: "Section B" }
]
}
]
}};
$scope.groups = json.data.groups;
});
Directive split into two:
app.directive('groupsControl', function(){
return {
restrict: 'E',
replace: true,
transclude: false,
scope: { items:'=groupdata'},
template: '<div ng-repeat="group in items">' +
'{{ group.name }}' +
'<section-control sections="group.sections" />'+
'</div>',
// The linking function will add behavior to the template
link: function(scope, element, attrs) {
}
}
}).directive('sectionControl', function(){
return {
restrict: 'E',
replace: true,
transclude: false,
scope: { items:'=sections'},
template: '<div ng-repeat="section in items" ng-include="getIncludeFile(section)">'+
'</div>',
link: function(scope, element, attrs) {
scope.getIncludeFile = function(section) {
return section.name.toLowerCase().replace('section ','') + ".html";
}
}
}
});
I'd actually like to see someone post an answer using a function for the templateUrl based on some of the scope data.

Related

How to show bootstrap tooltip dynamic data where tooltip has html content

I am trying to load data from the grid inside tooltip. This tooltip is generated once the user hovers on first column inside ui-grid. I want to use bootstrap and html of tooltip is displaying as required. I have tried several ways but now the data is not showing.
Please see the attached picture. I want actual value of {{row.entity.Status}}
Please see the current code for reference
https://codepen.io/brainzest/pen/bmqgLy?editors=0011
angular.module('GridDemo', ['ngTouch', 'ui.grid', 'ui.grid.cellNav', 'ui.grid.pinning']).controller('MainCtrl', function($scope,uiGridConstants,$sce){
$scope.equipData = [
{ Status: "Maintenance",
PackageName: "Package 1",
Hours: "15,000",
},
{ Status: "Running",
PackageName: " Package 2",
Hours: "15,000",
},
{ Status: "Running",
PackageName: "Package 3",
Hours: "15,000",
},
{ Status: "Running",
PackageName: "Package 4",
Hours: "15,000",
},
];
$scope.gridOptions = {
enableSorting: true,
enableColumnResizing : true,
enableColumnMenus:false,
columnDefs: [{ field: 'PackageName', cellTemplate:'<div data-toggle="tooltip" title="\<table class=table-borderless><tbody><tr><td class=gray>Status</td><td class=yell>Data 2</td></tr><tr><td class=gray>Status</td><td class=yell>{{row.entity.Status}}</td></tr></tbody></table>" data-html="true" data-placement="right" ><div class="ui-grid-cell-contents">{{ COL_FIELD }}</div></div>'},
{ field: 'Hours'}],
data:$scope.equipData
};
}).directive('toggle', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
if (attrs.toggle=="tooltip"){
$(element).tooltip();
}
}
};
});
if you are looking for something more angular you should do it this way:
<div class="grid-tooltip" tooltip="{{row.entity.Status}}" tooltip-placement="left">
<div class="ui-grid-cell-contents">
{{ COL_FIELD }}
</div>
</div>

accessing values from a controller to directive which is having local scope

i have a directive(with local scope) and a controller. If i want to access the students data from the controller to the directive, how do i need to do it ? below is the code.
My purpose is to build a chart which shows the details of students who were absent and present and when the user clicks on the absent/present i should be able to show a table with the details of it.
JS
app.directive('hcPieChart', function () {
return {
restrict: 'E',
template: '<div></div>',
scope: {
title: '#',
data: '='
},
link: function (scope, element,attrs) {
Highcharts.chart(element[0], {
chart: {
type: 'pie',
spacingTop: 30,
width: 300,
height: 250,
},
title: {
text: ''
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
showInLegend: true,
dataLabels: {
enabled: false,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
},
events: {
click: function(event)
{
how can i access the student details from the controller to this function ? i want to use the click to call a rest service (inside the controller ).
},
series: [{
data: scope.data
}]
});
}
};
})
app.controller('myCtrl', ['$scope','$http','DTOptionsBuilder', 'DTColumnBuilder',function($scope,$http,DTOptionsBuilder, DTColumnBuilder)
{
$scope.showTableDetails=function(x,typeOfData){
$scope.showTableDetailsData="";
$scope.showTableName="";
$scope.checkAnomaly= false;
if(typeOfData==1){
dataCatagory="total";
$scope.checkAnomaly==false;
}else if(typeOfData==2){
dataCatagory="present";
$scope.checkAnomaly==false;
}else if(typeOfData==3){
dataCatagory="absent";
$scope.checkAnomaly==false;
}
$http.get('http://localhost/rest/tripsStatus/studentdetails/'+x.tripDetails.tripId+'/'+dataCatagory+'/am').
then(function(result) {
$scope.showTableDetailsData = result.data.messages[0].data.studentDetails;
$scope.showTableName=x.tripDetails.tripName;
});
HTML
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="x in data track by $index" style="float:left";>
<div class="wrapper">
<trip-details></trip-details>
<div class="chartdiv">
<hc-pie-chart data="showPieChart(x)"></hc-pie-chart>
</div>
</div>
</div>
</div>
If you use the directive at "first level", i.e not a directive within a directive you can use $parent:
link: function (scope, element, attrs) {
...
scope.$parent.showTableDetails(...)
}
If you use a directive within another directive it would be $scope.$parent.$parent and so on.

How to get all checked checkboxes value by ng-model in Angular?

here is the jsfiddle.
HTML:
<div ng-app="app">
<div ng-controller="ctrl">
<div ng-repeat="item in list">
<div mycb group="{{item.group}}" title="{{item.title}}" is-checked="item.isChecked" value="{{item.value}}" update="callMe()"></div>
</div>
<p>{{result}}</p>
</div>
</div>
JS:
angular.module("app",[])
.controller("ctrl", ["$scope", function($scope){
$scope.list = [
{ group: "pet", title: "dog", isChecked: true, value: "dog" },
{ group: "pet", title: "cat", isChecked: true, value: "cat" },
{ group: "pet", title: "bird", isChecked: true, value: "bird" },
{ group: "pet", title: "snake", isChecked: true, value: "snake" },
{ group: "pet", title: "boy", isChecked: true, value: "boy" },
{ group: "pet", title: "cup", isChecked: true, value: "cup" }
];
$scope.callMe = function(){
var collection = [];
for(var i=0;i<$scope.list.length;i++){
var isChecked = $scope.list[i].isChecked;
if(isChecked){
collection.push($scope.list[i].value);
}
}
$scope.result = collection.join(" ");
}
}])
.directive("mycb", function(){
return{
restrict: "A",
scope: {
title: "#",
isChecked: "=",
group: "#",
value: "#",
update: "&"
},
template: "<input type='checkbox' ng-model='isChecked' name='{{group}}' value='value' ng-change='update()'>{{title}}"
};
})
I created a group of checkbox and it will be updated when each of them is clicked.
By default, all checkboxes are checked. When I click the first one, it will be turned to status unchecked. The value of other checked boxes will show up.
For example:
dog,cat,bird,snake,boy,cup
When I click dog, the checkbox of dog will be turned to unchecked and "cat,bird,snake,boy,cup" will show up. Actually, it not happened like that. It shows "dog,cat,bird,snake,boy,cup".
Please check it out and give me a hand. Many thanks!
You can use an arrray to keep track of the boxes that are checked.
$scope.selectedCheckboxes = [];
$scope.callMe=function(item){
var idx = $scope.selectedCheckboxes.indexOf(item);
// is currently selected
if (idx > -1) {
$scope.selectedCheckboxes.splice(idx, 1);
}
// is newly selected
else {
$scope.selectedCheckboxes.push(item);
}
};
And in html pass item.value to callMe function. You wil have all the value that are checked in $scope.selectedCheckboxes
<div ng-repeat="item in list">
<div mycb group="{{item.group}}" title="{{item.title}}" is-checked="item.isChecked" value="{{item.value}}" update="callMe(item.value)"></div>
</div>
HTML
<div ng-repeat="item in list">
<div mycb group="{{item.group}}" title="{{item.title}}" is-checked="item.isChecked" value="{{item.value}}" ng-change="callMe()"></div>
</div>
Use ng-change event. Call Me function called when the user clicked on the checkbox. you can easily track all the checked checkbox in the controller.
Let me know if you need help more. Thanks.

Angular UI Bootstrap's Radio Button inside a directive with ng-repeat does not show default value properly

Essentially, I have a directive that is used as a 3 way filter using a radio button. Unfortunately, it needs to have a default state and that default state has to actually be shown in the UI, the problem is that although the model is updated properly, the UI is not. Here is a plunkr that demonstrates the issue:
http://plnkr.co/edit/8pljDFyRfInI4Q0qSTmL?p=preview
The directive is used the following way:
<filter model="model"/>
Where the model is defined as this.model = { value: {} } in the controller
Here is an updated code.
At first I want to say what ng-model directive works only with input elements,
and also I changed the isActive: 'Yes/No' to true/false
// Code goes here
var filters = angular.module('filters', ['ui.bootstrap']);
filters.controller('FilterCtrl', function() {
this.model = { value: {} };
});
filters.directive('filter', function () {
return {
restrict: 'E',
scope: {
model: '='
},
template: '<div class="btn-group">' +
'<label ng-repeat="choice in choices" class="btn btn-{{ choice.buttonClass }}" ng-class="{active: choice.value.isActive}"' +
'btn-radio="{{ choice.value }}"><i class="fa {{ choice.icon }}"></i> {{ choice.name }}</label>' +
'</div>',
link: function (scope, element, attrs) {
scope.choices = [
{ value: { isActive: true }, name: 'Active', buttonClass: 'default', icon: 'fa-circle' },
{ value: null, name: 'Both', buttonClass: 'primary', icon: 'fa-arrows-h' },
{ value: { isActive: false}, name: 'Inactive', buttonClass: 'danger', icon: 'fa-circle-o' },
];
scope.model.value = _.first(_.filter(scope.choices, { value: { isActive: 'Yes' } })).value;
}
}
});

AngularJS : Custom directive scope not being initialized properly when used with ng-repeat

I have a problem with passing object information to my custom directive, which has an isolate scope. I have boiled my problem down to this simple plnkr to demonstrate the wall I am hitting:
http://plnkr.co/edit/oqRa5pU9kqvOLrMWQx1u
Am I just using ng-repeat and directives incorrectly? Again, my goal is to pass the object information from the ng-repeat loop into my directive which will have its own scope.
HTML
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="i in items", my-directive="i">
<span>{{$index}}</span>
<p>{{item.name}}</p>
<p>{{item.value}}</p>
</li>
</ul>
</body>
JS
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.items = [
{name: "Name #1", value: "Value #1"},
{name: "Name #2", value: "Value #2"},
{name: "Name #3", value: "Value #3"}
];
});
app.directive('myDirective', function($scope) {
return {
restrict: "A",
scope: { item: "=myDirective" },
link: function(scope, elem, attrs) {
}
}
});
Thank you.
Issues:
remove $scope from directive function
remove comma from HTML after ng-repeat
Provide element with new attribute, for example value but my-directive="i" will work as well.
HTML
<ul>
<li ng-repeat="i in items" my-directive value="i">
<span>{{$index}}</span>
<p>{{item.name}}</p>
<p>{{item.value}}</p>
</li>
</ul>
JS
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.items = [
{name: "Name #1", value: "Value #1"},
{name: "Name #2", value: "Value #2"},
{name: "Name #3", value: "Value #3"}
];
});
app.directive('myDirective', function() {
return {
restrict: "A",
scope: { item: "=value" },
link: function(scope, elem, attrs) {
console.log(scope.item);
}
}
});
Demo Plunker

Resources