Reputation: 12428
In my app, I have got different tasks, each having a due date thay may be like following:
Jun 6, 2014
Apr 12, 2014 @ 1pm
Daily @ 1pm
In my view, I am using ng-repeat
to show the tasks and their related information. My ng-repeat
looks like below:
<ul class="tasks">
<li class="single-task">
<span class="task-title">{{task.title}}</span>
<span class="task-duedate">{{task.dueDate}}</span>
</li>
What I want, is to show the dates differently i.e. instead of showing them the way that they are stored, I want the date to be rendered inside the <span class="task-duedate"></span>
like the following:
<span class="task-duedate">
<span class="date-daymon">Apr 12</span>
<span class="date-year">2014</span>
<span class="date-time">1 pm</span>
</span>
So, I have creatd and applied a filter
called NormalizeDateTime
<span class="task-duedate">{{task.dueDate | NormalizeDateTime }}</span>
that generates the desired html and returns it.
app.filter('NormalizeDate', function(){
return function( input ) {
...
...
return '<span..>' + date + '</span><span..>' + year + '</span><span..>' + time + '</span>';
};
});
Now the problem I am having is angular, instead of making the browser render the returned html, is showing the date part returned by the filter as it is i.e. in the form of plain text. Now the question is, how may I make it render the text returned by the NormalizeDateTime
filter as html?
P.S I have also tried triple braces {{{task.dueDate | NormalizeDateTime}}}
, as we do in HandlebarsJS
, but that doesn't work either.
UPDATE I have tried to achieve the same using a custom directive:
<span class="task-content group cursor-text group left">
<span class="task-text cursor-text">{{task.title}}</span>
<span class="task-trackedtime right">{{task.trackedTime}}</span>
<span class="task-datetime right" duedate="{{task.dueDate}}"></span>
</span>
Below is how my directive looks like:
app.directive('duedate', [function () {
return {
restrict: 'A',
// transclude: true,
replace: true,
template: '<span class="task-datetime right">{{dat}}</span>',
link: function (scope, iElement, iAttrs) {
// scope.dat = 'Testing Date';
console.log(iAttrs.duedate);
}
};
}])
But I'm unable to access iAttrs
.duedate
inside the link
of my directive. Why is it so?
Upvotes: 1
Views: 605
Reputation: 7292
Here ya go! http://jsfiddle.net/Uv6CP/
The trick with getting interpolated values in attributes to work is that you have to call iAttrs.$observe to get the interpolated value.
myApp.directive('duedate', function() {
return {
restrict: 'A',
replace: true,
template: '<div><span class="date-daymon">{{day}}</span><br><span class="date-year">{{year}}</span><br><span class="date-time">{{time}}</span><br><hr></div>',
link: function (scope, iElement, iAttrs) {
iAttrs.$observe('duedate', function(val) {
console.log("duedate = " + val);
var parts = val.split('@');
if (parts.length > 1) {
scope.time = parts[1];
} else {
scope.time = "";
}
var moreParts = parts[0].split(',');
if (moreParts.length > 1) {
scope.year = moreParts[1];
} else {
scope.year = "";
}
scope.day = moreParts[0];
});
}
};
});
Upvotes: 1
Reputation: 27976
DOM manipulation should only be done in a directive, so using a filter is not appropriate.
You don't include an example of a task so I'll assume that it looks something like:
{
id: 1,
dueDate: new Date( 2014, 5, 13, 13, 30, 0 ),
daily: false
}
A task should be passed to the directive rather than the dueDate because the directive needs to know when to show the word Daily, which it can't do given just a date.
Here's a directive that should hopefully do what you want:
.directive('dueDate', function($filter) {
return {
restrict: 'E',
scope: {
task: '='
},
replace: true,
template: '<span class="task-duedate"> \
<span class="date-daymon">{{daymon}}</span> \
<span class="date-year">{{year}}</span> \
<span class="date-time">@ {{time}}</span> \
</span>',
link: function(scope){
if( scope.task.daily ){
scope.daymon = 'Daily';
}
else {
scope.daymon = $filter('date')(scope.task.dueDate, 'MMM d');
scope.year = $filter('date')(scope.task.dueDate, 'yyyy');
}
scope.time = $filter('date')(scope.task.dueDate, 'h a');
}
};
})
Usage:
<div ng-repeat='task in tasks'>
<due-date task='task'></due-date>
</div>
Upvotes: 1
Reputation: 5634
You should use the ng-bind-html directive documented here
For your code it should look like:
<span ng-bind-html='task.dueDate | NormalizeDateTime'></span>
You controller should also have 'ngSanitize' as dependency, else you will have an exception.
Upvotes: 1
Reputation: 7820
I also had problems with the filter not being able to generate HTML and reverted back to a directive, too.
I would suggest a small change to your directive, i.e. add a scope definition as seen below:
app.directive('duedate', [function () {
return {
restrict: 'A',
replace: true,
scope: {
dat: '@duedate'
},
template: '<span class="task-datetime right">{{dat}}</span>',
link: function (scope, iElement, iAttrs) {
// scope.dat = 'Testing Date';
console.log(scope.dat);
}
};
}])
By adding scope: { dat: '@duedate' }
you specify that the directive's scope dat
property should be set to the interpreted value of the duedate
attribute.
Upvotes: 2
Reputation: 42669
Not sure but try something in the lines of using ngBindHtml directive in your span
<span class="task-duedate" ng-bind-html='task.dueDate | NormalizeDateTime'></span>
and see if it works. Remember to include the ngSanitize
module.
See documentation http://docs.angularjs.org/api/ng/directive/ngBindHtml
Upvotes: 1