1

I am having trouble trying to convert or translate a native js script to calculate number of days between two dates from two scopes ('work_start' and 'work_end') but did not have any success.

Here is the code, actually it works, but an alert is fired in the console.log and I am not achieving to solve this.

$scope.$watchGroup(['work_start', 'work_end'], function() {
var date1 = $scope.work_start;
var date2 = $scope.work_end;

// First we split the values to arrays date1[0] is the year, [1] the month and [2] the day
date1 = date1.split('-');
date2 = date2.split('-');

// Now we convert the array to a Date object, which has several helpful methods
date1 = new Date(date1[0], date1[1], date1[2]);
date2 = new Date(date2[0], date2[1], date2[2]);

// We use the getTime() method and get the unixtime (in milliseconds, but we want seconds, therefore we divide it through 1000)
date1_unixtime = parseInt(date1.getTime() / 1000);
date2_unixtime = parseInt(date2.getTime() / 1000);

// This is the calculated difference in seconds
var timeDifference = date2_unixtime - date1_unixtime;

// in Hours
var timeDifferenceInHours = timeDifference / 60 / 60;

// and finaly, in days :)
var timeDifferenceInDays = timeDifferenceInHours  / 24;

// alert(timeDifferenceInDays);
$scope.total_days = timeDifferenceInDays;

});

And this is the alert I am receiving:

angular.js:13283 TypeError: Cannot read property 'split' of null
at app.js:3997
at c (angular.js:16419)
at m.$eval (angular.js:16884)
at m.$digest (angular.js:16700)
at m.$apply (angular.js:16992)
at g (angular.js:11313)
at y (angular.js:11511)
at XMLHttpRequest.t.onload (angular.js:11452)(anonymous function) @ angular.js:13283(anonymous function) @ angular.js:9996m.$digest @ angular.js:16702m.$apply @ angular.js:16992g @ angular.js:11313y @ angular.js:11511t.onload @ angular.js:11452 

I changed some things but this is the far I can get. Any help will be welcome

Abiel Muren
  • 365
  • 1
  • 18
  • 2
    Looks like `work_start` or `work_end` are not always set. You can add a simple condition `if (!work_start || !work_end) { total_days=null; return; }` and see if it helps. – csharpfolk Nov 17 '16 at 21:07
  • Sorry @Claies, this error is due to a console.log from an other block, the value is not yet defined, thats why it gets undifined. But this has nothing to do with code pasted above (days between two dates) – Abiel Muren Nov 17 '16 at 21:07
  • Also notice that your callback can have form `function(newValues, oldValues, scope)` so instead of reading values from scope you can readthem from `newValues` e.g. `work_start = newValues[0]; work_end = newValues[1]` (I mean just add parameter `newValue` to your function) – csharpfolk Nov 17 '16 at 21:09
  • This code will work fine if the values of `$scope.work_start` and `$scope.work_end` are dates formatted as strings in the format "MM-dd-yyyy". That error seems pretty self-explanatory; one of those scope properties is `null`. So, what's the question here? – Heretic Monkey Nov 17 '16 at 21:22
  • I solved this considering the empty values, giving them a value of 0 if they didn't exist. This is a temporal fix, I will be working on this as @Travis suggest, to make a more compact code, with the proper angular markup. – Abiel Muren Nov 18 '16 at 01:39

1 Answers1

1
Cannot read property 'split' of null

This means you're trying to use the split function on something that is not a String. So where are you using the split function?

date1 = date1.split('-');
date2 = date2.split('-');

So where are date1/2 defined?

var date1 = $scope.work_start;
var date2 = $scope.work_end;

So where are $scope.work_start/end defined? Not sure, but probably in html. To simply fix this issue, do something like this:

if(date1 === null || date2 === null){
  alert("no dates given")
} else {
  date1 = date1.split('-');
  date2 = date2.split('-');
  ... // rest of your code
}


Updating this section based on the discussion below...

Dates can be a pain in JS. A newly initialized date object is simply the number of milliseconds since January 1st, 1970 (UTC). If you're going to play with dates and times, look into a js library that makes Dates easier to work with like Moment or Sugar.

$watchGroup watches those two dates and runs the 'days between' functionality if either changes. This is fine, however you must compensate for a range of issues, such as

the user changes work_start before work_end, and work_start is after work_end

the user enters a date that is not in the correct format

and a bunch of other stuff that can come up. You might want to think about incorporating a button to allow the user to update the dates after they're finished editing both. This will also allow your form to error-check the input, and not allow a submission if it's not in the correct format.

HTML

<div ng-controller="workCont">
  <input ng-model="$scope.work_start"></input>
  <input ng-model="$scope.work_end"></input>
  <button ng-click="$scope.getDaysBetween()">Get Days Between</button>
  <p>Days Between: {{$scope.daysBetween}}</p>
</div>

JS

var workApp = angular.module('workApp', []);

workApp.controller('workCont', function workCont($scope) {
  $scope.work_start = new Date();
  $scope.work_end = new Date();
  $scope.daysBetween = 0;
  $scope.getDaysBetween = function(){
    var date1 = $scope.work_start
    var date2 = $scope.work_end
    var timeDiff = Math.abs(date2.getTime() - date1.getTime());
    var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24)); 
    $scope.daysBetween = diffDays
  }
});

Thanks to "Get difference between 2 dates in javascript?" for the getDaysBetween logic.

Community
  • 1
  • 1
Travis Heeter
  • 13,002
  • 13
  • 87
  • 129
  • 1
    Thank you, this seems to solve the problem for now, but what I definitely need to do is something equal to what you suggest as angular typical markup. For my inputs in the html I have: `` and for the end: `` values are taken from here. – Abiel Muren Nov 18 '16 at 01:32
  • Glad to help, be sure to click the check if I answered your question. **Also**, if you're unaware, `Date` objects are a total pain in js - they have a steep learning curve. If you're doing a lot with dates/times check out [Sugar](https://sugarjs.com/dates/) or [Moment](http://momentjs.com/). **Also**, it looks like [$watchGroup](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watchGroup) is a listener, so when one of the values change, it runs the function. A fine way to do it, however, again, Dates can be a bitch. – Travis Heeter Nov 18 '16 at 17:22
  • 1
    **Thank you**, I'll be taking a look to those, (to Sugar and Moment), by the way, regarding to learning JS and Angular, I have a long journey on front. I will be posting more questions and doubts for sure! – Abiel Muren Nov 18 '16 at 18:48