So I'm trying to use directive amTimeAgo of momment JS in Angular, like this:
<span class="work-duration" ng-bind="item.startedAt | amTimeAgo: item.finishedAt: 'years' "></span>
I'm usting angular-moment (https://github.com/urish/angular-moment)
well, I want to show an date like, from: 02/09/2013 - to: 02/09/2015 - (2 years) or in different cases, 1 year and 3 months
Okay, in some cases the directive makes crazy calc,
some dates like this:
01/05/2012 - 30/09/2012 results in (3 years) why? Someone have any experiencie with this directive?
I tried to use the amFrom, but appears that this directive is not available in angularMoment,
in pure momment.JS:
var a = moment([2007, 0, 28]);
var b = moment([2007, 0, 29]);
a.from(b) // "a day ago"
Probably, this "from" method should works better than amTimeAgo.
Obs: in console, I got a lot of warnings about the finishedAt value:
angular-moment: Ignoring unsupported value for preprocess: 2015-10-01T03:00:00.000+0000
Related
I am trying to implement a date-sorting method for a news list that works across browsers. However, the one method I have tried that works well, only works in Chrome:
origArt.sort(function(a, b) {
var dateA = new Date(a.date), dateB = new Date(b.date);
return dateB - dateA;
});
I also tried this code, suggested in other sorting questions as a possible solution:
origArt.sort(function(a,b){
return (b.date > a.date) ? 1 : (b.date < a.date) ? -1 : 0;
});
But, because the dates in my JSON vary from year; month & year; and month, year and day; the news list sorts in reverse
alphabetical order, not reverse chronological order.
They are strings such as: "2018.", "April 8, 2015.", and "September 2015."
Your problem is that those aren't valid date strings. From some quick testing, Chrome appears to be doing a bit of guesswork as to what you mean, but the other browsers aren't.
Chrome:
new Date("2018.")
// Mon Jan 01 2018 00:00:00 GMT-0800 (Pacific Standard Time)
Firefox:
new Date("2018.")
// Invalid Date
And since Invalid Date > Invalid Date is always false, it isn't sorting anything. It's not just a matter of removing the period either, since "September 2015" also works in Chrome but fails in Firefox.
Ideally, you should fix your JSON or whatever code it's being generated from to use parseable date strings. If that's not an option, you'll probably have to write a custom parsing function that handles all the possible formats you might get, or see if a library like Moment.js can handle it for you.
Using ng-pluralize with this template:
Your subscription <span ng-pluralize count="::vm.account.subscription.expirationDays"
when="{ '-1': 'has expired!',
'0': 'expires today!',
'one': 'expires tomorrow.',
'other': 'expires in {} days.'}"></span>
Yields the following result:
Expiration Days Label
-1 Your subscription has expired!
0 Your subscription expires today!
1 Your subscription expires tomorrow!
X Your subscription expires in X days.
However, this breaks as soon as a subscription expires 2 days ago.
Is it possible to define a boolean expression as a when clause so that
vm.account.subscription.expirationDays < 0 === 'has expired!'
Currently I'm having to handle expired labels in a different element which kind of defeats the purpose of using ng-pluralize.
It looks like your scenario is, albeit perhaps a common one, too complex for ngPluralize. I also doubt it will change, because ngPluralize is based on "plural categories":
http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
The problem being that en-US, Angular's default locale, defines only the categories "one" and "other". Anything that doesn't fall into those categories is explicitly defined (or inferred by $locale.pluralCat).
The three best options for your scenario that immediately come to me are:
1) Simplest would be to have two objects:
when="count >=0 ? positivePlurals : negativePlurals"
where, of course $scope.count = vm.account.subscription.expirationDays, positivePlurals is your positive phrases and negativePlurals is your negative phrases.
2) Wrap a localization library that supports many-or-custom plural rules (such as i18next) in a directive, and use that instead. I'm not very familiar with the popular angular-translate, but at first glance it doesn't seem to support custom pluralization rules. It does, however, allow logic in interpolation, so you might get away with that.
3) Write a directive similar to ngPluralize that supports ("-other", "x", "other"). The source for ngPluralize is available here. It would probably be as simple as modifying the statement at L211 in a way similar to:
var countIsNaN = isNaN(count);
var countIsNegative = count < 0;
if (!countIsNaN && !(count in whens)) {
// If an explicit number rule such as 1, 2, 3... is defined, just use it.
// Otherwise, check it against pluralization rules in $locale service.
count = $locale.pluralCat(count - offset);
if(countIsNegative){
count = '-'+count; // "-one", "-other"
}
}
Why the following code produces strange output (looks like moment().valueOf() returns 0)
Since 7 days ago : {{(moment().valueOf() - 7*24*60*60*1000) | date:'yyyy-MM-dd' }}
returns
Since 7 days ago : 1969-12-25
You can do it with moment API :
moment().subtract('days', 7).format("YYYY-MM-DD")
Working jsfiddle : http://jsfiddle.net/D9UCF/1/
This is because:
moment#valueOf simply outputs the number of milliseconds since the
Unix Epoch, just like Date#valueOf.
[http://momentjs.com/docs/]
One way to achieve what you want is as follows:
Since 7 days ago: <span ng-bind="sevenDaysAgo"></span>
$scope.sevenDaysAgo = moment(new Date(new Date().setDate(new Date().getDate() - 7))).format('YYYY-MM-DD');
I am using angular js and trying to display a text ie 'recent' if the order was placed within 5 days ago from today. So if the difference in days between todaysDate and the Order.dateCreated <= 5 then I want to display 'recent' otherwise blank:
orderid | dateCreated | status
1 | 27-2-2014 | recent
2 | 27-1-2014 |
angular script fragment:
<table>
<tr data-ng-repeat="order in orders" >
<td>{{order.id}}</td>
<td>{{order.dateCreated}}</td>
<td><span ng-show="(getDate()-order.dateCreated)<=5">recent</span></td>
</tr>
</table>
You just need to do this in standard JavaScript and expose a method to your scope to allow the orders to use:
Something like this, however, if your dates are currently stored in a UK format as they appear to be in your question. You will not be able to parse them like this, consider having your server-side code spit out a standard format that JavaScript can parse.
If you find you are having problems doing that, cannot change the server-side response from that format, or want to keep the format, you could use a library to parse it, such as: http://momentjs.com/docs/#/parsing/string-format/ This also has some decent tools for checking the difference: http://momentjs.com/docs/#/displaying/difference/
$scope.isRecentOrder = function(date) {
// Assuming date is a string of parsable format: ie. "2014-01-27T01:00:00+00:00"
var diff = new Date() - new Date(date);
// Calculate from milliseconds
var days = ((((diff / 1000) / 60) / 60) / 24);
return days >= 5;
}
Then you can use the directive ng-show="isRecentOrder(order.dateCreated)"
UPDATE 4/19/2012 12PM PST: Gotta eat crow on this one. The problem was not with Angular's databinding but with math errors in how I was calculating the dates. I wasn't properly taking into account the minutes and seconds in my time calculations. I was just subtracting the timestamps from each other expecting the hours to come out nicely.
I've gotten myself into trouble with AngularJS databinding in which my different inputs need to be reciprocally bound to each other.
The form needs to contain the following:
A start date (this is a given, not an input)
An input to add hours on to the start date
Two inputs with the result: 1) a date picker and 2) an hour picker
If you change any of the inputs, it should update the others. So, the following would be desirable results:
(with original date-time as April 19th at 10pm). User enters '1 hour'. The result date becomes April 19th and the result time becomes 11pm.
Building on the above example, the user changes the date input to April 20th. The 'hours' now become 25 hours.
I've placed set up watchers, using $scope.$watch on each of these variables:
$scope.$watch('hours', function (newHours, oldHours, scope) {
if (newHours) {
var newEndDate = new Date(scope.origDate),
offHours = newEndDate.getHours();
newEndDate.setHours(offHours + newHours);
scope.endDate = newEndDate;
scope.endHours = newEndDate.getHours();
}
});
$scope.$watch('endHours', function (newEndHours, oldEndHours, scope) {
if (newEndHours) {
var newEndDate = new Date(scope.endDate);
newEndDate.setHours(newEndHours);
scope.endDate = newEndDate;
}
});
$scope.$watch('endDate', function (newEndDate, oldEndDate, scope) {
if (newEndDate) {
scope.hours = (newEndDate - scope.origDate) / (1000 * 60 * 60);
}
});
Each of these works fine on their own, but in tandem they cause a big fat mess. From my understanding of Angular, it seems that they're creating a 'feedback loop.' Edit: To wit, model 'A' will be updated and trigger a change on model 'B'. Model 'B' will then trigger a change on model 'A'.
Now, is it possible to temporarily suspend data-binding so that I can just update the models without firing the watchers? In some other contexts I've worked in (UITableView on Cocao comes to mind), one can ask to "stop updates," make some changes to the model, and then "resume updates."
Is there anything like this in AngularJS? If not, what am I not getting here, and how could I set up my project to achieve the desired functionality?
Here's a plunkr of my example.