├── .gitignore
├── .vscode
└── tasks.json
├── Gruntfile.js
├── LICENSE
├── README.md
├── content
├── style
│ └── main.css
└── templates
│ └── toggleBlock.html
├── index.html
├── package.json
└── src
├── app.js
├── common
├── Conversions.js
├── UnitOfMeasureState.js
├── UserProfile.js
├── formulaBmi.js
├── formulaBmr.js
└── formulaThr.js
├── controllers
├── FormulaController.js
├── UomController.js
└── UserProfileController.js
├── directives
└── ToggleBlock.js
└── filters
├── bmiFilter.js
├── genderFilter.js
├── heightFilter.js
├── uomFilter.js
└── weightFilter.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.1.0",
3 | "command": "grunt",
4 | "isShellCommand": true,
5 | "tasks": [{
6 | "taskName": "watch",
7 | "isBuildCommand": false
8 | }, {
9 | "taskName": "build",
10 | "isBuildCommand": true
11 | }]
12 | }
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | grunt.initConfig({
3 | pkg: grunt.file.readJSON('package.json'),
4 | connect: {
5 | server: {
6 | options: {
7 | livereload: true
8 | }
9 | }
10 | },
11 | browserify: {
12 | dist: {
13 | options: {
14 | transform: [["babelify"]]
15 | },
16 | files: {
17 | "./dist/app.js" : ["./src/app.js"]
18 | }
19 | }
20 | },
21 | watch: {
22 | compile: {
23 | files: 'src/**/*.js',
24 | tasks: ['browserify']
25 | },
26 | run: {
27 | options: {
28 | livereload: true,
29 | base: '.'
30 | },
31 | files: ['./index.html', './dist/**/*.js']
32 | }
33 | }
34 | });
35 | grunt.loadNpmTasks('grunt-contrib-watch');
36 | grunt.loadNpmTasks('grunt-browserify');
37 | grunt.loadNpmTasks('grunt-connect');
38 | grunt.registerTask('livereload', [
39 | 'connect',
40 | 'watch'
41 | ]);
42 | grunt.registerTask('build', [
43 | 'browserify'
44 | ]);
45 | };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Jeremy Likness
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular ES6 Health App
2 |
3 | The [Angular 1.x Health App](https://github.com/JeremyLikness/AngularHealthApp) implemented with ECMAScript 6 (ECMAScript2015) and Babel.js
4 |
5 | 1. Navigate to the parent folder you would like to put the project in.
6 | 2. `git clone https://github.com/JeremyLikness/AngularES6HealthApp.git`
7 | 3. `cd AngularES6HealthApp`
8 | 4. `npm install`
9 | 5. `npm install -g grunt-cli`
10 | 6. `grunt build`
11 | 7. `grunt connect`
12 | 8. Navigate to the port indicated
13 |
--------------------------------------------------------------------------------
/content/style/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: arial, verdana, sans-serif;
3 | line-height: 1.2em;
4 | }
5 |
6 | h1 {
7 | font-size: 2.0em;
8 | font-weight: bold;
9 | color: darkblue;
10 | }
11 |
12 | button {
13 | width: 60px;
14 | border-color: black;
15 | border-radius: 0px;
16 | border-style: solid;
17 | border-width: 2px;
18 | padding: 5px;
19 | }
20 |
21 | div.break {
22 | clear: both;
23 | }
24 |
25 | div.tile {
26 | width: 290px;
27 | height: 150px;
28 | float: left;
29 | margin: 5px;
30 | padding: 5px;
31 | background: lightblue;
32 | border: solid 2px darkblue;
33 | }
34 |
35 | div.unit {
36 | min-width: 200px;
37 | max-width: 310px;
38 | float: left;
39 | margin: 5px;
40 | padding: 5px;
41 | }
42 |
43 | div.Obese {
44 | background: red;
45 | }
46 |
47 | div.Overweight {
48 | background: lightcoral;
49 | }
50 |
51 | div.Underweight {
52 | background: lightcoral;
53 | }
54 |
55 | input.error {
56 | border: 2px solid red;
57 | }
58 |
59 | .label {
60 | max-width: 60%;
61 | float: left;
62 | font-weight: bold;
63 | text-align: right;
64 | padding-right: 5px;
65 | vertical-align: middle;
66 | }
67 |
68 | .labelTarget {
69 | float: left;
70 | text-align: left;
71 | vertical-align: middle;
72 | }
--------------------------------------------------------------------------------
/content/templates/toggleBlock.html:
--------------------------------------------------------------------------------
1 |
2 |
{{label}}
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Health Calculator App
6 |
7 |
8 |
9 |
10 |
11 |
12 |
24 |
25 |
41 |
42 |
57 |
58 | Health Calculator
59 |
60 |
63 |
64 |
74 |
75 |
76 |
77 |
78 |
79 |
BMR:
80 | {{ctrl.bmrValue}} Calories
81 |
82 |
85 |
BMI:
86 | {{ctrl.bmiValue}}
87 | {{ctrl.bmiValue | bmi}}
88 |
89 |
90 |
THR (50%-85%):
91 | {{ctrl.thrValue.min}} — {{ctrl.thrValue.max}} BPM
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angulares6healthapp",
3 | "version": "1.0.0",
4 | "description": "Example of the Angular Health App written in ECMAScript6 using Babel",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Jeremy Likness",
10 | "license": "MIT",
11 | "dependencies": {
12 | "angular" : "^1.4.8",
13 | "common": "^0.2.5"
14 | },
15 | "babel": {
16 | "presets": [
17 | "es2015"
18 | ]
19 | },
20 | "devDependencies": {
21 | "grunt-babel" : "^6.0.0",
22 | "babel" : "^6.3.13",
23 | "grunt" : "^0.4.5",
24 | "browserify" : "^12.0.1",
25 | "grunt-browserify" : "^4.0.1",
26 | "babelify" : "^7.2.0",
27 | "grunt-contrib-watch" : "^0.6.1",
28 | "grunt-connect" : "^0.2.0",
29 | "connect" : "^3.4.0",
30 | "babel-preset-es2015": "^6.3.13"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | import {bmiFilterFactory} from './filters/bmiFilter.js';
2 | import {genderFilterFactory} from './filters/genderFilter.js';
3 | import {uomFilterFactory} from './filters/uomFilter.js';
4 | import {weightFilterFactory} from './filters/weightFilter.js';
5 | import {heightFilterFactory} from './filters/heightFilter.js';
6 |
7 | import {ToggleBlock} from './directives/toggleBlock.js';
8 |
9 | import {UnitOfMeasureState} from './common/UnitOfMeasureState.js';
10 | import {Conversions} from './common/Conversions.js';
11 | import {UserProfile} from './common/UserProfile.js';
12 |
13 | import {UomController} from './controllers/UomController.js';
14 | import {FormulaController} from './controllers/FormulaController.js';
15 | import {UserProfileController} from './controllers/UserProfileController.js';
16 |
17 | let toggleBlockFactory = () => new ToggleBlock();
18 |
19 | class AngularApp {
20 |
21 | constructor() {
22 |
23 | var healthApp = angular.module("healthApp", []);
24 |
25 | healthApp.filter("bmi", bmiFilterFactory);
26 | healthApp.filter("gender", genderFilterFactory);
27 | healthApp.filter("uom", uomFilterFactory);
28 | healthApp.filter("weight", weightFilterFactory);
29 | healthApp.filter("height", heightFilterFactory);
30 |
31 | healthApp.directive("toggleBlock", toggleBlockFactory);
32 |
33 | healthApp.service("uomService", UnitOfMeasureState);
34 | healthApp.service("conversionService", Conversions);
35 |
36 | healthApp.value("userProfile", new UserProfile());
37 |
38 | healthApp.controller("uomCtrl", ["uomService", UomController]);
39 | healthApp.controller("formulaCtrl", ["uomService", "userProfile",
40 | FormulaController]);
41 | healthApp.controller("userProfileCtrl", ["userProfile", "uomService",
42 | "conversionService", UserProfileController]);
43 | }
44 | }
45 |
46 | var app = new AngularApp();
--------------------------------------------------------------------------------
/src/common/Conversions.js:
--------------------------------------------------------------------------------
1 | const centimetersPerInch = 2.54;
2 | const inchesPerFoot = 12;
3 | const poundsPerKilogram = 2.205;
4 |
5 | export class Conversions {
6 |
7 | inchesToCentimeters(inches) {
8 | var input = Number(inches);
9 | return input * centimetersPerInch;
10 | }
11 |
12 | inchesToFeet(inches) {
13 | var input = Number(inches);
14 | return input / inchesPerFoot;
15 | }
16 |
17 | centimetersToInches(centimeters) {
18 | var input = Number(centimeters);
19 | return input / centimetersPerInch;
20 | }
21 |
22 | poundsToKilograms(pounds) {
23 | var input = Number(pounds);
24 | return input / poundsPerKilogram;
25 | }
26 |
27 | kilogramsToPounds(kg) {
28 | var input = Number(kg);
29 | return input * poundsPerKilogram;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/common/UnitOfMeasureState.js:
--------------------------------------------------------------------------------
1 | export class UnitOfMeasureState {
2 |
3 | constructor() {
4 | this._usMeasure = true;
5 | this._metricMeasure = false;
6 | }
7 |
8 | toggle() {
9 | this._usMeasure = !this._usMeasure;
10 | }
11 |
12 | get usMeasure() {
13 | return this._usMeasure;
14 | }
15 |
16 | set usMeasure(value) {
17 | this._usMeasure = !!value;
18 | this._metricMeasure = !this._usMeasure;
19 | }
20 |
21 | get metricMeasure() {
22 | return this._metricMeasure;
23 | }
24 |
25 | set metricMeasure(value) {
26 | this._metricMeasure = !!value;
27 | this._usMeasure = !this._metricMeasure;
28 | }
29 | }
--------------------------------------------------------------------------------
/src/common/UserProfile.js:
--------------------------------------------------------------------------------
1 | export class UserProfile {
2 | constructor() {
3 | this._isMale = true;
4 | this._isFemale = false;
5 | this.heightInches = 60;
6 | this.weightPounds = 130;
7 | this.ageYears = 40;
8 | }
9 |
10 | toggleGender() {
11 | this._isMale = !this._isMale;
12 | }
13 |
14 | get isMale() {
15 | return this._isMale;
16 | }
17 |
18 | set isMale(value) {
19 | this._isMale = !!value;
20 | this._isFemale = !this._isMale;
21 | }
22 |
23 | get isFemale() {
24 | return this._isFemale;
25 | }
26 |
27 | set isFemale(value) {
28 | this._isFemale = !!value;
29 | this._isMale = !this._isFemale;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/common/formulaBmi.js:
--------------------------------------------------------------------------------
1 | function formulaBmi (profile) {
2 |
3 | // BMI = (weight in pound * 703) / (height in inches)^2
4 | var bmi = (profile.weight * 703) / (profile.height * profile.height);
5 |
6 | // round it
7 | return Math.round(bmi * 10.0)/10.0;
8 | }
9 |
10 | export {formulaBmi}
--------------------------------------------------------------------------------
/src/common/formulaBmr.js:
--------------------------------------------------------------------------------
1 | function formulaBmr (profile) {
2 |
3 | // Women - 655 + (4.35 x weight in pounds) + (4.7 x height in inches) - (4.7 x age in years)
4 | function woman(weight, height, age) {
5 | return Math.floor(655 + (4.35 * weight) + (4.7 * height) - (4.7 * age));
6 | }
7 |
8 | // Men - 66 + (6.23 x weight in pounds) + (12.7 x height in inches) - (6.8 x age in years )
9 | function man(weight, height, age) {
10 | return Math.floor(66 + (6.23 * weight) + (12.7 * height) - (6.8 * age));
11 | }
12 |
13 | return profile.isMale ? man(profile.weight, profile.height, profile.age) :
14 | woman(profile.weight, profile.height, profile.age);
15 | }
16 |
17 | export {formulaBmr}
--------------------------------------------------------------------------------
/src/common/formulaThr.js:
--------------------------------------------------------------------------------
1 | function formulaThr (age) {
2 |
3 | // max heart rate = 220 - age;
4 | var max = 220.0 - Number(age);
5 |
6 | // min range = 50%
7 | var min = Math.round(5.0 * max) / 10.0;
8 |
9 | // max range = 85%
10 | var maxRate = Math.round(8.5 * max) / 10.0;
11 |
12 | return {
13 | min: min,
14 | max: maxRate
15 | };
16 | }
17 |
18 | export {formulaThr}
--------------------------------------------------------------------------------
/src/controllers/FormulaController.js:
--------------------------------------------------------------------------------
1 | import {formulaBmr} from '../common/formulaBmr.js';
2 | import {formulaBmi} from '../common/formulaBmi.js';
3 | import {formulaThr} from '../common/formulaThr.js';
4 |
5 | export class FormulaController {
6 | constructor(uomService, userProfile) {
7 | this.uomService = uomService;
8 | this.userProfile = userProfile;
9 | }
10 |
11 | makeParameters() {
12 | return {
13 | isMale: this.userProfile.isMale,
14 | height: this.userProfile.heightInches,
15 | weight: this.userProfile.weightPounds,
16 | age: this.userProfile.ageYears
17 | };
18 | }
19 |
20 | get bmrValue() {
21 | return formulaBmr(this.makeParameters());
22 | }
23 |
24 | get bmiValue() {
25 | return formulaBmi(this.makeParameters());
26 | }
27 |
28 | get thrValue() {
29 | return formulaThr(this.userProfile.ageYears);
30 | }
31 | }
--------------------------------------------------------------------------------
/src/controllers/UomController.js:
--------------------------------------------------------------------------------
1 | export class UomController {
2 | constructor(uomService) {
3 | this.uomService = uomService;
4 | }
5 | }
--------------------------------------------------------------------------------
/src/controllers/UserProfileController.js:
--------------------------------------------------------------------------------
1 | export class UserProfileController {
2 | constructor(userProfile, uomService, conversionService) {
3 | this.userProfile = userProfile;
4 | this.uomService = uomService;
5 | this.conversionService = conversionService;
6 | this._weightVal = uomService.usMeasure ?
7 | userProfile.weightPounds : conversionService.poundsToKilograms(
8 | userProfile.weightPounds);
9 | this._wasMetric = uomService.metricMeasure;
10 | this._ageValue = userProfile.ageYears;
11 | }
12 |
13 | get minHeightRange() {
14 | return this.uomService.usMeasure ? 24 : 60;
15 | }
16 |
17 | get maxHeightRange() {
18 | return this.uomService.usMeasure ? 84 : 215;
19 | }
20 |
21 | get heightValue() {
22 | return this.uomService.usMeasure ?
23 | this.userProfile.heightInches :
24 | this.conversionService.inchesToCentimeters(this.userProfile.heightInches);
25 | }
26 |
27 | set heightValue(value) {
28 | var incoming = Number(value);
29 | this.userProfile.heightInches = this.uomService.usMeasure ?
30 | incoming :
31 | this.conversionService.centimetersToInches(incoming);
32 | }
33 |
34 | get minWeightRange() {
35 | return this.uomService.metricMeasure ? 9 : 20;
36 | }
37 |
38 | get maxWeightRange() {
39 | return this.uomService.metricMeasure ? 182 : 400;
40 | }
41 |
42 | get weightValue() {
43 | if (this.uomService.metricMeasure !== this._wasMetric) {
44 | this._wasMetric = this.uomService.metricMeasure;
45 | if (this._wasMetric) {
46 | this._weightVal = Math.round(this.conversionService.poundsToKilograms(
47 | Number(this._weightVal)
48 | ));
49 | }
50 | else {
51 | this._weightVal = Math.round(this.conversionService.kilogramsToPounds(
52 | Number(this._weightVal)
53 | ));
54 | }
55 | }
56 | return this._weightVal;
57 | }
58 |
59 | set weightValue(value) {
60 | var incoming = Number(value), adjustedWeight = incoming;
61 | this._weightVal = value;
62 | if (this.uomService.metricMeasure) {
63 | adjustedWeight = this.conversionService.kilogramsToPounds(incoming);
64 | }
65 | if (adjustedWeight >= 20 && adjustedWeight <= 400) {
66 | this.userProfile.weightPounds = adjustedWeight;
67 | }
68 | }
69 |
70 | get ageValue() {
71 | return this._ageValue;
72 | }
73 |
74 | set ageValue(value) {
75 | var incoming = Number(value);
76 | this._ageValue = value;
77 | if (incoming >= 13 && incoming <= 120) {
78 | this.userProfile.ageYears = incoming;
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/src/directives/ToggleBlock.js:
--------------------------------------------------------------------------------
1 | export class ToggleBlock {
2 | constructor() {
3 | this.restrict = "E";
4 | this.replace = true;
5 | this.scope = {
6 | label: "@",
7 | buttonText: "=",
8 | toggleFunction: "&"
9 | };
10 | this.templateUrl = "content/templates/toggleBlock.html";
11 | }
12 | }
--------------------------------------------------------------------------------
/src/filters/bmiFilter.js:
--------------------------------------------------------------------------------
1 | export function bmiFilterFactory() {
2 | return function (input) {
3 | var value = Number(input);
4 |
5 | if (value >= 30.0) {
6 | return 'Obese';
7 | }
8 |
9 | if (value >= 25.0) {
10 | return 'Overweight';
11 | }
12 |
13 | if (value < 18.5) {
14 | return 'Underweight';
15 | }
16 |
17 | return 'Normal';
18 | };
19 | }
20 |
--------------------------------------------------------------------------------
/src/filters/genderFilter.js:
--------------------------------------------------------------------------------
1 | export function genderFilterFactory () {
2 | return function (input) {
3 | var check = !!input;
4 | return check ? 'Male' : 'Female';
5 | };
6 | }
--------------------------------------------------------------------------------
/src/filters/heightFilter.js:
--------------------------------------------------------------------------------
1 | var heightFilterFactory = [
2 | "uomService",
3 | "conversionService",
4 | function (uomSvc, conversionSvc) {
5 | return function (input, convert) {
6 |
7 | var heightInches = Number(input), heightCentimeters, ft, result = '';
8 |
9 | if (uomSvc.usMeasure) {
10 | ft = Math.floor(conversionSvc.inchesToFeet(heightInches));
11 | if (ft > 0) {
12 | result = ft + " ft. ";
13 | }
14 | heightInches -= ft * 12;
15 | if (heightInches >= 1) {
16 | result += (Math.floor(heightInches) + ' in.');
17 | }
18 | }
19 | else {
20 | if (convert !== undefined && !!convert === convert && !convert) {
21 | heightCentimeters = heightInches;
22 | }
23 | else {
24 | heightCentimeters = Math.round(
25 | conversionSvc.inchesToCentimeters(heightInches), 1);
26 | }
27 | result = heightCentimeters + ' cm.';
28 | }
29 | return result;
30 | }
31 | }
32 | ];
33 |
34 | export {heightFilterFactory};
--------------------------------------------------------------------------------
/src/filters/uomFilter.js:
--------------------------------------------------------------------------------
1 | export function uomFilterFactory() {
2 | return function (input) {
3 | var check = !!input;
4 | return check ? 'U.S.' : 'Metric';
5 | };
6 | }
--------------------------------------------------------------------------------
/src/filters/weightFilter.js:
--------------------------------------------------------------------------------
1 | export function weightFilterFactory () {
2 | return function (input) {
3 | var check = !!input;
4 | return check ? 'lbs.' : 'kgs.';
5 | };
6 | }
--------------------------------------------------------------------------------