Skip to content

Instantly share code, notes, and snippets.

@mbcooper
Created August 11, 2015 19:32
Show Gist options
  • Save mbcooper/bb7e827bffd9fafa7f9b to your computer and use it in GitHub Desktop.
Save mbcooper/bb7e827bffd9fafa7f9b to your computer and use it in GitHub Desktop.
A full example of a module.js for a Angular view. This refers to external dependencies, but is an example of the file organization.
/**
* Created by mike on 7/18/2015.
* home.controller -
*/
angular.module('handi.home')
.controller('HomeController', HomeController)
.constant('MaxDeficit', 2)
.constant('DatesChosen', 'datesChosen')
.config(function($stateProvider, States) {
'use strict';
$stateProvider.state(States.home.default, {
url: '/home',
views: {
'content@': {
templateUrl: 'home/home.tpl.html',
controller: 'HomeController as home'
}
}
});
}
);
function HomeController(intervalService, memoryService, DatesChosen,
$state, States, $q, $log, MaxDeficit) {
'use strict';
this.hello = 'Hello';
this.intervals = [];
this.selectedIntervals = [];
this.noPosters = [];
this.loading = false;
var vm = this;
/**
* @method selectInterval
* @param {Interval} item
* @param {object} model
*/
this.selectInterval = function(item, model) {
var getNoPosts = intervalService.variances(item.startDate, item.endDate,
MaxDeficit);
getNoPosts.then(
function(noPosts) {
// append to noPosters
combine(noPosts);
memoryService.set(DatesChosen, vm.selectedIntervals);
},
function(apiError) {
}
);
getNoPosts.finally(function() {
});
};
/**
* @private - combines scores
* @param {Player[]} newNoPosts
*/
function combine(newNoPosts) {
_.each(newNoPosts, function(newPost) {
var existing = _.find(vm.noPosters, {ghin: newPost.ghin});
if (existing) {
// add to existing
existing.add(newPost);
} else {
// append
vm.noPosters.push(newPost);
}
// sort
vm.noPosters = _.sortBy(vm.noPosters, function(post){
return post.deficit;
});
});
}
/**
* @method removeInterval
* @param {Interval} item
* @param model
*/
this.removeInterval = function(item, model) {
// not allowed
$log.debug('times left: ' + vm.selectedIntervals);
memoryService.set(DatesChosen, vm.selectedIntervals);
vm.loading = true;
vm.noPosters.length = 0;
checkPreSelectedIntervals();
};
/**
* @gets a spouse report on time
* @param {number} id
*/
this.popSpouse = function(id) {
$log.debug('ss');
};
activate();
/**
* fetches intervals
*/
function activate() {
vm.selectedIntervals.length = 0;
vm.loading = true;
var getIntervals = intervalService.get();
getIntervals.then(
function(intervals) {
vm.intervals.length = 0;
vm.intervals = intervals;
checkPreSelectedIntervals();
},
function(apiError) {
//if (apiError.status === 401) {
// $state.go(States.login.default);
//}
}
);
}
/**
* Checks to see if we already have some
*/
function checkPreSelectedIntervals() {
var rememberedDates = memoryService.get(DatesChosen);
if (!rememberedDates) {
vm.loading = false;
return;
}
rememberedDates = angular.fromJson(rememberedDates);
// only remember 1
if(rememberedDates.length > 1){
rememberedDates = rememberedDates.slice(0,1);
}
var promises = [];
_.each(rememberedDates, function(rememberedDate) {
var starting = moment(rememberedDate.startDate);
var interval = _.find(vm.intervals, function(inter) {
if (inter.startDate.format() === starting.format()) {
return inter;
}
});
vm.selectedIntervals.push(interval);
promises.push(fetchPromise(interval.startDate, interval.endDate));
});
$q.all(promises)
.finally(function() {
vm.loading = false;
});
}
/**
* NOT DRY :-(
* @param {moment} startDate
* @param {moment} endDate
* @returns {*} - promise of resolved
*/
function fetchPromise(startDate, endDate) {
var defer = $q.defer();
var getNoPosts = intervalService.variances(startDate, endDate,
MaxDeficit);
getNoPosts.then(
function(noPosts) {
// append to noPosters
combine(noPosts);
},
function(apiError) {
}
);
getNoPosts.finally(function() {
defer.resolve();
});
return defer.promise;
}
}
/**
* Created by mike on 7/18/2015.
* home.module -
*/
angular.module('handi.home', [
'angularMoment',
'handi.models.apiError',
'handi.models.player',
'handi.config',
'handi.config.path',
'handi.services.memory',
'handi.filters.telephone'
]);
<div id="home" class="row">
<h4>Handicap Summary</h4>
<div class="leagueSelect"
ng-show="home.intervals.length > 0">
<b>Play Dates: </b>
<ui-select
multiple
id="byInterval"
on-select="home.selectInterval($item, $model)"
on-remove="home.removeInterval($item, $model)"
ng-model="home.selectedIntervals"
theme="bootstrap"
>
<ui-select-match placeholder="Select dates">
{{$item.display}}
</ui-select-match>
<ui-select-choices
repeat="interval in home.intervals">
<div>{{interval.display}}</div>
</ui-select-choices>
</ui-select>
</div>
<div ng-show="home.noPosters.length > 0" class="col-lg-9">
<table class="table table-striped table-hover table-condensed">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Ghin</th>
<th>G</th>
<th>Email</th>
<th>Phone</th>
<th align="right">Tees</th>
<th align="right">Posted</th>
<th align="right">Deficit</th>
<th align="right">Post %</th>
<th>Incidents</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="nope in home.noPosters | orderBy: deficit:desc">
<td>{{$index+1}}</td>
<td>{{::nope.fullName}}</td>
<td title="See Scores"><a ui-sref="handi.scores({playerId: {{nope.id}} })">
{{::nope.ghin}}
</a>
</td>
<td>{{::nope.gender}}</td>
<td>{{::nope.email}}</td>
<td>{{::nope.phone | telephone}}</td>
<td align="right">{{::nope.teeTimes}}</td>
<td align="right">{{::nope.scores}}</td>
<td align="right">{{::nope.deficit}}</td>
<td align="right">{{::nope.percentageEntered | number: 1}}%</td>
<td align="right" title="See Incidents">
<a ui-sref="handi.incidents({playerId: nope.id})">
{{::nope.incidentsCount}}
</a>
</td>
<td style="width: 26px">
<i ng-show="nope.doNotDisturb"
title="Do Not Disturb"
class="fa fa-hand-peace-o"></i>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class=" col-lg-offset-2 col-lg-8 spinnerCover"
ng-show="home.loading">
<i class="fa fa-cog fa-spin fa-4x"></i>
</div>
/**
* Created by mike on 7/19/2015.
* intervals.model -
*/
angular.module('handi.home')
.factory('Interval', function() {
/**
* @class Interval
* @constructor
*
* @property {moment} startDate - beginning of interval
* @property {moment} endDate - end of interval
*/
var Interval = function() {
this.startDate = null;
this.endDate = null;
};
/**
* @method fromDTO - converts from endpoint version to Object
* @param {Date} starter
* @param {Date} ender
*/
Interval.prototype.fromDTO = function(starter, ender) {
var vm = this;
vm.startDate = moment(starter);
vm.endDate = moment(ender);
};
/**
* @property display
* @return {string} for display purposes
*/
Object.defineProperty(Interval.prototype, 'display', {
get: function() {
var vm = this;
var format = 'MMM D, YYYY';
return vm.startDate.format(format) + ' - ' +
vm.endDate.format(format);
},
enumerable: true
});
return Interval;
})
;
/**
* Created by mike on 7/19/2015.
* intervals.service -
*/
angular.module('handi.home')
.service('intervalService', IntervalService);
/**
* @class IntervalService
* @constructor
*/
function IntervalService($q, $http, ENVIRONMENT, EndPoints, ApiError,
Interval, Player) {
var base = ENVIRONMENT.API_PATH;
/**
* @method get - gets the intervals
* @returns {*} - list of start / end dates
*/
var get = function() {
var defer = $q.defer();
var url = base + EndPoints.intervals.list;
var get = $http({
method: 'GET',
url: url,
isArray: true,
cache: false
});
get.then(
function(results) {
var intervals =
_.map(results.data, function(result) {
var interval = new Interval();
interval.fromDTO(result.startDate, result.endDate);
return interval;
});
defer.resolve(intervals);
},
function(data, status, headers, config) {
var apiError = new ApiError(data, status, headers, config);
defer.reject(apiError);
});
return defer.promise;
};
/**
* @method variances - gets the variance report
* @param {Date} startDate
* @param {Date} endDate
* @param {number} maxDeficit
* @returns {*}
*/
var variances = function(startDate, endDate, maxDeficit) {
var dateFormat = 'YYYY-MM-DD';
var defer = $q.defer();
var url = base + EndPoints.intervals.variances +
'?StartDate=' + startDate.format(dateFormat) +
'&EndDate=' + endDate.format(dateFormat) +
'&maxDeficit=' + maxDeficit +
'&playerId=null';
var get = $http({
method: 'GET',
url: url,
isArray: true,
cache: false
});
get.then(
function(results) {
var noPosters =
_.map(results.data, function(result) {
return new Player(result);
});
defer.resolve(noPosters);
},
function(data, status, headers, config) {
var apiError = new ApiError(data, status, headers, config);
defer.reject(apiError);
});
return defer.promise;
};
return {
get: get,
variances: variances
};
}
@mbcooper
Copy link
Author

Here is a test module: interval.models.spec.js -- very extensive property level testing

/**
 * Created by mike on 8/11/2015.
 * interval.mode.spec -
 */
describe('Interval model', function() {
  'use strict';
  var interval;
  var Interval;
  var baseProperties = ['startDate', 'endDate'];

  beforeEach(module('handi.models.interval'));

  beforeEach(function() {
    inject(function(_Interval_) {

      Interval = _Interval_;
      interval = new Interval();

    });
  });

  it('should make an object', function() {
    expect(interval).not.toBeNull();
  });

  it('should make an object of type Interval', function() {
    expect(interval instanceof Interval).toBeTruthy();
  });

  it('should check properties', function() {
    _.each(baseProperties, function(prop) {
      expect(interval.hasOwnProperty(prop)).toBeTruthy();
    });
  });

  it('should test a dto', function() {
   // write a test here
  });

  it('should test a display', function() {
    // write a test here
  });

});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment