I have an element on the page that has been rendered by the server. Let's call it a playlist. It's going to be a directive.<div playlist></div>
A playlist contains a number of tracks before Angular compile time.<div class="Track" data-track-name="Pompeii" data-*="etc">...</div>
Once the page is loaded I'm including AngularJS and parsing playlist and a directive.
When I initialise the playlist directive, I'd like to loop through it's contents before compiling it's template and using the data collected to draw track directives in an ng-repeat
directive belonging to the playlist directive.
Questions:
Is there native functionality for parsing content before the template replaces any content within the directive tag? Once I'm in the directive controller the content has already been replaced.
Is there a better solution to my problem? I unfortunately have to use content already rendered on the page as a data-source as a solution to a whole bunch of requirements for this project
Could I use a track directive within my content from the server to avoid DOM manipulation?
Extra explanation
Before compile:
<div playlist>
<div class="Track" data-track-name="Pompeii">Pompeii</div>
<div class="Track" data-track-name="Weight of living">Weight of living</div>
</div>
After compile:
<div playlist>
<!-- from playlist template -->
<div class="Playlist">
<div class="Playlist-controls">....</div>
<div class="Playlist-tracks">
<div track ng-repeat="track in tracks">
<!-- from track template -->
<div class="Track">...</div>
</div>
</div>
</div>
</div>
Assuming this is your data structure, you could easily do this all without a directive:
Data Structure/Controller
function ctrl($scope) {
$scope.Playlists = [
{ name: 'Playlist 1', tracks: [ 'Track 1', 'Track 2', ..., 'Track n'] },
{ name: 'Playlist 2', tracks: [ 'Track 1', 'Track 2', ..., 'Track n'] },
...
{ name: 'Playlist n', tracks: [ 'Track 1', 'Track 2', ..., 'Track n'] }
];
}
Template:
<div ng-controller="ctrl">
<div ng-repeat="playlist in Playlists">
<div> {{ playlist.name }} </div>
<div ng-repeat="track in playlist.tracks">
{{ track }}
</div>
</div>
</div>
[edits]
Since you need to parse the DOM, you can use this directive to do it. It will parse the DOM and place it into a controller scope array. You can then pass this scope into a template or template URL. Use any jQuery you need to wipe the original DOM. jsFiddle
var myApp = angular.module('myApp',[]);
myApp.directive('playlist', function() {
return {
restrict: 'A',
scope: false,
link: {
pre: function(scope, element) {
$('.Track').each(function(index, ele) {
scope.tracks.push($(ele).attr('data-track-name'));
});
console.log(scope.tracks);
},
post: function(scope, element) {
// do any compiling, etc...
}
},
controller: function($scope, $element) {
$scope.tracks = [];
}
}
});
[edit #2] Including Beyer's suggestions. Adding this in case someone finds this useful in the future. jsFiddle
Template:
<div ng-app="myApp">
<script type="text/ng-template" id="tpl.html">
<div>My playlist controls</div>
<div ng-repeat="track in tracks">
{{ track }}
</div>
</script>
<div playlist>
<div class="Track" data-track-name="Pompeii">Pompeii</div>
<div class="Track" data-track-name="Weight of living">Weight of living</div>
</div>
</div>
Directive:
var myApp = angular.module('myApp',[]);
myApp.directive('playlist', function($compile, $templateCache) {
var extractData = function(scope) {
$('.Track').each(function(index, ele) {
scope.tracks.push($(ele).attr('data-track-name'));
});
}
return {
replace: true,
restrict: 'A',
compile: function(ele, attr, ctrl) {
return {
pre: function preLink(scope, ele, attr, ctrl) {
extractData(scope);
},
post: function postLink(scope, ele, attr, ctrl) {
ele.html($templateCache.get("tpl.html"));
$compile(ele.contents())(scope);
}
}
},
controller: function($scope, $element) {
$scope.tracks = [];
}
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With