Reputation: 13583
Say one have a list of multiple type of data defined in a controller as follows:
$scope.list = [
{text: "Remember BASIC?"},
{code: "10 a = a+1"},
// many additional lines…
];
Which we want to interpolate in the view depending on each individual type as follows:
<p>Remember BASIC?</p>
<code>10 a = a+1</code>
How would you do that?
[edit] Clarification about what to obtain
List is a descriptionof an arbitrary number of "paragraph" of arbitrary types. Here is an more extensive list:
$scope.list = [
{text: "Remember BASIC?"},
{code: "10 a = a+1"},
{text: "Bla bla"},
{text: "Bla bla"},
{text: "Bla bla"},
{text: "Bla bla"},
{text: "Bla bla"},
{text: "Bla bla"},
{code: "20 b = a+1"},
{code: "30 c = b+1"},
{text: "Bla bla"},
// many additional lines…
];
And the expected result:
<p>Remember BASIC?</p>
<code>10 a = a+1</code>
<p>Bla bla</p>
<p>Bla bla</p>
<p>Bla bla</p>
<p>Bla bla</p>
<p>Bla bla</p>
<p>Bla bla</p>
<code>20 b = a+1</code>
<code>30 c = b+1</code>
etc.
It's not an issue to have an englobing tag, but I don't want an englobing tag for every single "paragraph".
Upvotes: 3
Views: 3397
Reputation: 10153
Yes you can do this with a directive that loads a dynamic template:
var myApp = angular.module('myApp',[]);
function getTemplate(type) {
if(type === 'text') {
return '<p>{{item.contents}}</p>';
}
else if(type === 'code') {
return '<pre>{{item.contents}}</pre>';
}
return '{{item.contents}}';
}
myApp.directive("customListItem", function($compile) {
return {
restrict: 'E',
scope: {
item: '='
},
link: function($scope, $element) {
$element.html(getTemplate($scope.item.type));
$compile($element.contents())($scope);
}
};
});
function MyCtrl($scope) {
$scope.list = [
{type: 'text', contents: "Remember BASIC?"},
{type: 'code', contents: "10 a = a+1"}
];
}
You could probably write that ng-repeat
so that you can use your original list
structure.
The key here is $element.html
that injects the correct template into the original and $compile
that interprets the bindings in it.
Note that the original custom-list-item
element will still be present in the DOM. No way you can eliminate that with ng-repeat
.
Upvotes: 2
Reputation: 16498
I'm not 100% sure what do you mean by
// many additional lines…
but if your list looks like
$scope.list = [
{text: "Remember BASIC?"},
{code: "10 a = a+1"},
{text: "Remember Loundy?"},
{code: "10 a = a+3"}
....
];
you can use ng-repeat-start /end
please see here http://jsbin.com/zawige/3/edit
<p ng-repeat-start="i in list" ng-if="i.text">{{i.text}}</p>
<code ng-repeat-end ng-if="i.code">{{i.code}}</code>
Upvotes: 6
Reputation: 211
Change your object model:
$scope.list = [
{
text: "Remember BASIC?",
code: "10 a = a+1"},
// many additional lines…
},
{
text: "Remember Test?",
code: "10 a = a+4"},
// many additional lines…
}];
Then in your template:
<div ng-repeat="item in list">
<p>{{item.text}}</p>
<code>{{item.code}}</code>
</div>
Upvotes: 0
Reputation: 191749
I would change the structure like so:
{
content: "Remember BASIC?",
type: "text",
}
Then you could do
<div ng-repeat="item in list">
<div ng-switch="item.type">
<div ng-switch-when="text"><p>{{item.content}}</p></div>
<div ng-switch-when="code"><code>{{item.content}}</code></div>
If you must/want to stick with the structure as it is now, you could nest ng-repeat
:
<div ng-repeat="item in list">
<div ng-repeat="(type, text) in item">
<div ng-switch="type"> ...
Upvotes: 1