How to render mixed json results for different templates (with different variables) using angularjs
I wonder what is best when I have an answer that has many different object types and looks like this:
[
{"nodeClass":"Entity", "text":"foo","entityfield":"booz"},
{"nodeClass":"User","username":"bar","userfield":"baz"}
]
and I have different templates for everyone:
for objects:
<div class="{{nodeClass}} capsule">{{entity.text}}:{{entity.entityfield}}</div>
for users:
<div class="{{nodeClass}} capsule">{{user.username}}:{{user.userfield}}</div>
how would you structure your code and which corner element (ng-repeat, etc.) on (re) use the correct templates based on the "nodeClass" value. Keep in mind that I don't want to create a new conditional template, except that this is the only solution.
Edit: I found these approaches: http://onehungrymind.com/angularjs-dynamic-templates/ and if else statement in AngularJS templates and Dynamic template rendering in ng-repeat directive in AngularJS? but they are very different from my requirements. Especially the last one is closest to what I want, but my templates tend to have different variable names in them.
thank
source to share
You can try pulling template.html
in the background with $http
, parse the pattern, and replace instances of the variable name that doesn't match your variable name ng-repeat
. Then send this html
from template.html
in a directive (or controller template) that has ng-repeat
in your template, insert the newly edited html through $('#elem').html(newHtml);
and call $compile
on the changed element.
The template you are pulling might look like this:
controller1/template1.html
<h1>{{item.data}} - {{item.name}}</h1>
Here is the pattern where the repeater is in
controller1.html
<p>This is the view for controller 1.</p>
<div id="repeater" ng-repeat="thing in vm.items">
</div>
Extracting the template, replacing the desired string, and recompiling the template can be done as follows:
controller1.js
function Controller1($scope, $http) {
var vm = this;
vm.items = [{name: 'item1', data: 123}, {name: 'item2', data: 456}];
var templateReplacement = '{{thing.';
$http.get('controller1/template1.html')
.then(function success(response) {
var newHtml = response.data.replace(/{{item./g, templateReplacement);
var repeaterElem = $('#repeater');
$(repeaterElem[0]).html(newHtml);
$compile(repeaterElem)($scope);
}, function failure(reason) {
console.log(reason);
});
}
Here is a plunk of this action in action
source to share
One way is to use dynamically generated ng-include
url
Html
<div ng-repeat="item in data">
<div ng-include="getContentUrl(item.nodeClass)"></div>
</div>
Templates
<script type="text/ng-template" id="partials/Entity.html">
<h3>Entity Template , text= {{item.text}}</h3>
</script>
<script type="text/ng-template" id="partials/User.html">
<h3>User Template , username ={{item.username}}</h3>
</script>
Js
app.controller('MainCtrl', function($scope) {
$scope.data=[{"nodeClass":"Entity", "text":"foo"},{"nodeClass":"User","username":"bar"}];
$scope.getContentUrl = function(nodeClass){
return 'partials/'+nodeClass +'.html';
}
});
source to share
I built a directive that takes two attributes, one for the template and the other for whatever data you need to pass to the template.
Pass the value of the template selector using a switch statement, which will then apply the correct template and sort your data accordingly. Plunker
Directive
app.directive('templateSelector', function($compile) {
return {
restrict: 'A',
scope: {},
link: function(scope, el, attr) {
console.log(attr.tClass, attr.tVals)
var template ='';
scope.data = angular.fromJson(attr.tVals);
switch (attr.tClass) {
case 'Entity':
template = '<div><h1>Entity Class Template</h1>{{data.text}}</div><hr/>';
break;
case 'User':
template = '<div><h1>User Class Template</h1>{{data.username}}</div><hr/>';
break;
}
$template = angular.element(template);
$compile($template)(scope);
el.append($template);
}
}
})
HTML:
<div ng-repeat="d in dataset">
<div template-selector t-class="{{d.nodeClass}}" t-vals="{{d}}"></div>
</div>
source to share
I can change data from the service before it ever reaches the view. This works with ng-if to determine which HTML to display:
<div ng-repeat="data in dataset">
<div
class="capsule"
ng-class="data.nodeClass"
ng-bind="data.text"
ng-if="data.nodeClass==='Entity'"></div>
<div
class="capsule"
ng-class="data.nodeClass"
ng-bind="data.username"
ng-if="data.nodeClass==='User'"></div>
</div>
Plunger fork made of tpie
source to share