I want to create a div which loads different templates dynamically, based on a context parameter:
My "search-results-container" directive:
app.directive("searchResultsContainer", function() {
restrict: "E",
templateUrl: "search-results-container.html",
controller: function($scope) {
$scope.templates = [
{ viewmode: "list", url: "search-results-list-view.html" },
{ viewmode: "grid", url: "search-results-grid-view.html" },
{ viewmode: "table", url: "search-results-table-view.html" }
]
},
link: function(scope) {
scope.toggleView = function() {
scope.templates.push(scope.templates.shift());
}
}
}
My "search-results-container.html" file:
<div ng-include="templates[0].url"></div>
My "search-results-table-view.html" file:
<table>
<tr ng-repeat="item in ctrl.items">
<td>{{ item.title }}</td>
<tr>
</table>
Loading the templates dynamically works without a problem. However, I want these templates to run some "callback" function, once they are done loading.
I know there is the "onload" attribute, which I could add to the like so:
<div ng-include="templates[0].url" onload="onLoadFunction()"></div>
This means that I need to populate my original "search-results-container" directive with an "onLoadFunction" in the scope, which would have to use a switch (or similar technique) to distinguish between the template files and run a specific function depending on the currently active one - I want to prevent that because it is not clean.
I want to have separate directives for each template, like:
app.directive("searchResultsTableView", function() {
return {
restrict: "E",
templateUrl: "search-results-table-view.html",
controller: function($scope) {
...
},
link: function(scope) {
scope.someOnLoadFunction = function() {
/* Stuff to execute when template has loaded */
}
}
}
});
If I do that, and I change my "search-results-table-view.html" accordingly to this:
<search-results-table-view>
<table>
<tr ng-repeat="item in ctrl.items">
<td>{{ item.title }}</td>
<tr>
</table>
</search-results-table-view>
...I run into some sort of infinite loop or something and Angular / the browser crashes (becomes unresponsive). Is there a way to achieve what I plan, without filling up the container's directive with a ton of "onLoad" functions, one for each nested template?
What we ended up doing is this:
we have one directive:
app.directive("searchResultsContainer", function() {
restrict: "E",
templateUrl: "search-results-container.html",
controller: function($scope) {
$scope.templates = [
{ viewmode: "list", url: "search-results-list-view.html" },
{ viewmode: "grid", url: "search-results-grid-view.html" },
{ viewmode: "table", url: "search-results-table-view.html" }
]
},
link: function(scope) {
scope.toggleView = function() {
scope.templates.push(scope.templates.shift());
}
}
}
This directive is instantiated by using an ng-include directive:
<search-results-container ng-include="views/result-list.html"></search-results-container>
The used result-list.html file has this passage:
<div ng-switch on="templates[0].viewmode">
<search-results-list-view ng-switch-default></gs-search-results-list-view>
<search-results-grid-view ng-switch-when="grid"></gs-search-results-grid-view>
<search-results-table-view ng-switch-when="table"></gs-search-results-table-view>
</div>
And it has a button to toggle between views, using a simple ng-click directive:
<button ng-click="toggleViewMode()">Toggle View</button>
This button triggers the searchResultsContainer's toggleView method, described in the directive above, moving the elements of the templates array around:
scope.toggleView = function() {
scope.templates.push(scope.templates.shift());
}
The ng-switch directive listens for changes in the "viewmode" property of the first element of the templates array:
ng-switch on="templates[0].viewmode"
Such a change happens when clicking the button, thus changing the first element in the array entirely, which naturally also results in a change of the "viewmode" property, monitored by ng-switch.
The nested ng-switch-default and ng-switch-when directives react to the change and display the according element, which has the appropriate value set in "ng-switch-when".
The three children of the ng-switch each use a separate directive, here is one of them:
app.directive("searchResultsListView", function() {
return {
restrict: "E",
require: "^searchResultsContainer",
template: "<div ng-include=\"'views/list-view.html'\"></div>",
controller: function($scope) {
/* $scope stuff goes here */
},
link: function(scope, element, attrs, searchResultsCtrl) {
/* link stuff goes here */
}
}
});
Note the very important escaped quotation marks, followed by high-commas in the template's ng-include directive, as required by the ng-include directive (more info on ng-include).