<!DOCTYPE html>
<html ng-app="app">
<head>
<link data-require="jasmine@1.3.1" data-semver="1.3.1" rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" />
<link rel="stylesheet" href="style.css">
<script data-require="moment.js@*" data-semver="2.8.3" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
<script data-require="underscore.js@*" data-semver="1.6.0" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script data-require="angular-messages@*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular-messages.js"></script>
<script data-require="jasmine@1.3.1" data-semver="1.3.1" src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
<script data-require="jasmine@1.3.1" data-semver="1.3.1" src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
<script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.0-rc.2/angular.js" data-semver="1.4.0-rc.2"></script>
<script data-require="angular-mocks@*" data-semver="1.4.0-rc.2" src="https://code.angularjs.org/1.4.0-rc.2/angular-mocks.js"></script>
<script src="app.js"></script>
<!-- <script src="appSpec.js"></script>
<script src="jasmineBootstrap.js"></script> -->
</head>
<body ng-controller="MainController as main">
<form name='dateForm' ng-submit='main.submit()'>
<date-range-form-directive ng-model="main.date"></date-range-form-directive>
<input type='submit' />
</form>
<div ng-include="main.templateUrl"></div>
</body>
</html>
// Code goes here
var app = angular.module('app', []);
app.controller('MainController', MainController);
app.directive('monthYearPickerDirective', monthYearPickerDirective);
app.directive('dateRangeFormDirective', dateRangeFormDirective);
app.directive('monthDirective', monthDirective);
function MainController($scope) {
var vm = this;
vm.date = {};
vm.date.from = {month: null, year: null};
vm.date.to = {month: null, year: null, ongoing: false};
$scope.test = 'string:1';
vm.submit = function() {
vm.templateUrl = 'happy-booking-template.html';
}
}
function dateRangeFormDirective() {
var directive = {
restrict: 'E',
templateUrl: 'date-range-form-template.html',
require: 'ngModel',
transclude: true,
link: link
};
return directive;
function link(scope, elem, attrs, ctrl) {
scope.formCtrl = ctrl; //Errors will be on the form - NOT on individual fields
scope.isValid = function() {
if(gotToAndFromDates()) {
becomeDates();
if(datesAreValid()) ctrl.$validate();
}
}
ctrl.$validators.startDateAfterEndDate = function() {
return (scope.ngModel &&
scope.ngModel.date.from.moment &&
scope.ngModel.date.to.moment &&
scope.ngModel.date.from.moment.isBefore(scope.ngModel.date.to.moment) )
}
function toDate(stage) {
var e = scope.ngModel.date[stage];
return new Date(e.year, e.month)
}
function becomeDates() {
scope.ngModel.date.to.moment = moment(new Date(scope.ngModel.date.to.year + '-' + scope.ngModel.date.to.month)).endOf('month');
if(scope.main.date) {
scope.main.date.from.moment = scope.ngModel.date.from.moment;
scope.main.date.to.moment = scope.ngModel.date.to.moment;
}
}
function datesAreValid() {
return scope.ngModel.date.from.moment.isValid() && scope.ngModel.date.to.moment.isValid();
}
function gotToAndFromDates() {
return scope.ngModel && scope.ngModel.date.from && scope.ngModel.date.to;
}
}
}
function monthYearPickerDirective() {
var directive = {
restrict: 'E',
templateUrl: 'month-year-template.html',
//template: '<select name="{{label}}month" ng-model="ngModel.month" ng-options="c as c for c in months" required></select><select name="{{label}}year" ng-model="ngModel.year" ng-options="c as c for c in years" required ></select>',
require: 'ngModel',
scope: {
label: '@', //label for us to differntiate if 'FROM' or 'TO' date
ngModel: '=', //Object {month: null, year: null}
onSelected: '&' //is the function we will call on the parent directive
},
transclude: true,
link: link
};
return directive;
function link(scope, elem, attrs, ctrl) {
scope.label = attrs.label;
scope.months = returnMonths();
scope.years = returnYears();
scope.fromLabel = scope.label === 'from' ? true : false;
scope.$watch('ngModel.month', newValueTrigger);
scope.$watch('ngModel.year', newValueTrigger);
function newValueTrigger() {
if(isFormEvenValid()) {
scope.onSelected();
}
}
function isFormEvenValid() {
return (scope.ngModel && scope.ngModel.month && scope.ngModel.year);
}
/* Helper Functions */
function returnMonths() {
var array = [];
for (var i = 1; i < 12; i++) {
//var monthName = moment('2014 ' + i + ' 25').format('MMMM'); //TODO Add locale('fr') - tie it to ng-translate
var selectOptionValue = moment('2014 ' + i + ' 25').format('M');
array.push(selectOptionValue);
}
return array;
}
function returnYears() {
var array = [];
for (var i = 1950; i < 2050; i++) {
var date = moment(i + ' 1 25').format('YYYY'); //TODO Add locale('fr') - tie it to ng-translate
array.push(date);
}
return array;
}
}
}
/* Styles go here */
.box {
width: 100%;
height: 200px;
background: red;
border: 5px solid green;
color: white;
}
<div>
<label>{{label | uppercase}}</label>
<div>
<select
name="{{label}}month"
ng-model="ngModel.month"
ng-options="c as c for c in months"
month-directive
required
></select>
<select
name="{{label}}year"
ng-model="ngModel.year"
ng-options="c as c for c in years"
required
></select>
{{$parent.formCtrl}}
<div ng-messages="$parent.formCtrl.$error" ng-if="fromLabel && $parent.formCtrl.$invalid">
<div ng-message="startDateAfterEndDate">Start Date is before endDate</div>
</div>
</div>
</div>
<ng-form name='childForm'>
<month-year-picker-directive label='from' on-selected='isValid()' ng-model='ngModel.date.from'></month-year-picker-directive>
<month-year-picker-directive label='to' on-selected='isValid()' ng-model='ngModel.date.to'></month-year-picker-directive>
<input type="checkbox" />
</ng-form>
<div class='box'>
<h1>Hurray - we booked your flight</h1>
Your vacation starts on: {{main.date.from.moment}}
<br />
Your vacation ends on: {{main.date.to.moment}}
<br />
No worries - I am sure you will go again next year :)
</div>
describe('App Test', function() {
var $scope = null;
var $rootScope = null;
var ctrl = null;
var compileFn = null;
var $httpBackend = null;
//you need to indicate your module in a test
beforeEach(module('app'));
beforeEach(inject(function(_$rootScope_, $controller, $compile, _$httpBackend_) {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
ctrl = $controller('MainController', {
$scope: $scope
});
// compileFn = $compile(
// '<ng-form name="child-form"><month-year-picker-directive label="from" on-selected="isValid()" ng-model="ngModel.date.from"></month-year-picker-directive>' +
// '<month-year-picker-directive label="from" on-selected="isValid()" ng-model="ngModel.date.from"></month-year-picker-directive></ng-form>'
// );
compileFn = $compile(
'<month-year-picker-directive label="from" on-selected="isValid()" ng-model="date.from"></month-year-picker-directive>'
);
}));
describe('MainController', function() {
it('should have date object inside controller', function() {
expect(ctrl.date.from.month).toBe(null);
});
});
describe('dateRangeForm Directive', function() {
var to, from, fillDirective;
beforeEach(function() {
to = {
month: 'string:03',
year: 'string:2013'
};
from = {
month: 'string:01',
year: 'string:2013'
};
fillDirective = function() {
var e = compileFn($scope);
$rootScope.$digest();
return e;
}
ctrl.date.from = from;
ctrl.date.to = to;
});
it('should pass validation on an element', function(){
fillDirective();
ctrl.date.from.month = 'string:07';
fillDirective();
expect(ctrl.date.from.month).toBe('string:07');
});
it('should re-map dates correctly - if available on the Controller', function() {
//Here if we stored some date on the server - and they are in EDIT mode
// ctrl.date.from = '2015-03-01';
// ctrl.date.from.month = 'string:3';
// var element = compileFn($scope);
// $rootScope.$digest();
// console.log('element', element);
// console.log('select', element[0].children[0]);
// expect(ctrl.date.from.month).toBe('2015-03-01');
});
it('should produce a valid date from moment format MMM for cross browser', function() {
// $scope.from = '2015-March-01'; //Invalid in IE/FF
// var element = compileFn($scope);
// $rootScope.$digest();
// expect(ctrl.date.from.date.isValid()).toBe(true);
});
it('should produce a valid UTC date if non UTC date given', function() {
//UTC inconsistencies - ('2015-03-01') - really -- ('2015-02-28')
});
it('should produce an end of month date in UTC', function() {
//new Date ('2015-03').endOf('month') - will not work
var date = moment(new Date(Date.UTC(2015, 12, 0, 0, 0, 0)));
//var computedDate = moment(new Date("2015-12-31")).utcOffset(-240);
expect(date.isSame(date)).toBe(true);
});
});
// it('should return a valid map URL if markers are NOT available', function() {
// var url = myService.getMapUrl(undefined, {size: 'small'});
// expect(url).not.toContain('pin_family.png');
// });
// it('should not process and an undefined marker', function() {
// var markers = [{"latitude":undefined,"longitude":undefined, icon: 'undefined'}];
// var url = myService.getMapUrl(markers, {size: 'small'});
// expect(url).not.toContain('undefined');
// expect(url).toContain('png');
// expect(urlRegEx.test(url)).toBe(true);
// });
});
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 250;
/**
Create the `HTMLReporter`, which Jasmine calls to provide results of each spec and each suite. The Reporter is responsible for presenting results to the user.
*/
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
/**
Delegate filtering of specs to the reporter. Allows for clicking on single suites or specs in the results to only run a subset of the suite.
*/
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
/**
Run all of the tests when the page finishes loading - and make sure to run any previous `onload` handler
### Test Results
Scroll down to see the results of all of these specs.
*/
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
//document.querySelector('.version').innerHTML = jasmineEnv.versionString();
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();