Skip to content

Instantly share code, notes, and snippets.

@Kritner
Last active September 8, 2018 22:52
Show Gist options
  • Save Kritner/fadc18ea0eff5e0e70f2ee75098e01f9 to your computer and use it in GitHub Desktop.
Save Kritner/fadc18ea0eff5e0e70f2ee75098e01f9 to your computer and use it in GitHub Desktop.
Medium blog post - solar projection, adding form - Form typescript model
export class SolarProjectionFormModel {
constructor(
public yearsToProject: number,
public utilitySolarArrayKwhYear: number,
public solarCostPerMonth: number,
public solarFinanceYears: number,
public utilityCostFullYear: number,
public utilityPercentIncreasePerYear: number
) { }
}
<h1>Solar Projection</h1>
<div class="container">
<!-- form inputs solar projection-->
<div>
<form *ngIf="!isExpandedForm" (ngSubmit)="onSubmit()" #projectionForm="ngForm">
<div class="form-group">
<label for="yearsToProject">Years to project</label>
<input type="number" class="form-control" id="yearsToProject" name="yearsToProject" required [(ngModel)]="model.yearsToProject"
/>
</div>
<div class="form-group">
<label for="utilitySolarArrayKwhYear">Utility/Solar Array kw/year</label>
<input type="number" class="form-control" id="utilitySolarArrayKwhYear" name="utilitySolarArrayKwhYear" required [(ngModel)]="model.utilitySolarArrayKwhYear"
/>
</div>
<div class="form-group">
<label for="solarCostPerMonth">Solar Array cost/month</label>
<input type="number" class="form-control" id="solarCostPerMonth" name="solarCostPerMonth" required [(ngModel)]="model.solarCostPerMonth"
/>
</div>
<div class="form-group">
<label for="solarFinanceYears">Solar Finance Years</label>
<input type="number" class="form-control" id="solarFinanceYears" name="solarFinanceYears" required [(ngModel)]="model.solarFinanceYears"
/>
</div>
<div class="form-group">
<label for="utilityCostFullYear">Utility Cost Full Year</label>
<input type="number" class="form-control" id="utilityCostFullYear" name="utilityCostFullYear" required [(ngModel)]="model.utilityCostFullYear"
/>
</div>
<div class="form-group">
<label for="utilityPercentIncreasePerYear">Utility Cost % Increase/year</label>
<input type="number" class="form-control" id="utilityPercentIncreasePerYear" name="utilityPercentIncreasePerYear" required
[(ngModel)]="model.utilityPercentIncreasePerYear" />
</div>
<button type="submit" class="btn btn-success" [disabled]="!projectionForm.form.valid">
Submit
</button>
</form>
<button type="button" class="btn" (click)="toggleFormInput()">
Projection Criteria
<span class="glyphicon" [ngClass]="{
'glyphicon-chevron-down': isExpandedForm,
'glyphicon-chevron-up': !isExpandedForm
}"></span>
</button>
</div>
<!-- Solar projection-->
<div>
<p *ngIf="!solarProjection"><em>Loading...</em></p>
<div *ngIf="solarProjection">
<h4>Solar Estimate (Guaranteed for 90% of total Kw/year Production)</h4>
<ul>
<li>Solar Cost/year: {{ solarProjection.solarEstimate.totalCost | currency }}</li>
<li>Solar Cost/month: {{ solarProjection.solarEstimate.averageCostPerMonth | currency }}</li>
<li>Total Kw/h/year: {{ solarProjection.solarEstimate.totalKiloWattHours | number }}</li>
<li>Solar Cost kw/h {{ solarProjection.solarEstimate.averageCostKiloWattHour | currency }}</li>
<li>Total Years Financed: {{ solarProjection.financeYears }} </li>
</ul>
<table class='table'>
<thead>
<tr>
<th>Year</th>
<th>Total Cost Utility</th>
<th>Avg. Cost/month (Utility)</th>
<th>Cost/year 100% gen.</th>
<th>Savings/year 100% gen.</th>
<th>Cost/year 90% gen.</th>
<th>Savings/year 90% gen.</th>
<th>Cost/year 80% gen.</th>
<th>Savings/year 80% gen.</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let projection of solarProjection.futureProjection">
<td>{{ projection.purchaseYear | indexOffset }}</td>
<td>{{ projection.totalCost | currency }}</td>
<td>{{ projection.averageCostPerMonth | currency }}</td>
<td>{{ projection.costSolar100Percent | currency }}</td>
<td [ngClass]="{
positive: inTheGreen(projection.totalSavings100Percent),
negative: !inTheGreen(projection.totalSavings100Percent)
}">{{ projection.totalSavings100Percent | currency }}</td>
<td>{{ projection.costSolar90Percent | currency }}</td>
<td [ngClass]="{
positive: inTheGreen(projection.totalSavings90Percent),
negative: !inTheGreen(projection.totalSavings90Percent)
}">{{ projection.totalSavings90Percent | currency }}</td>
<td>{{ projection.costSolar80Percent | currency }}</td>
<td [ngClass]="{
positive: inTheGreen(projection.totalSavings80Percent),
negative: !inTheGreen(projection.totalSavings80Percent)
}">{{ projection.totalSavings80Percent | currency }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
import { Component, OnInit, Inject } from '@angular/core';
import { HttpHeaders, HttpParams } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';
import { SolarProjectionFormModel } from './solar-projection-form-model';
@Component({
selector: 'app-solar-projection',
templateUrl: './solar-projection.component.html',
styleUrls: ['./solar-projection.component.css']
})
export class SolarProjectionComponent implements OnInit {
private http: HttpClient;
private baseUrl: string;
isExpandedForm: boolean = true;
solarProjection: SolarProjection;
model: SolarProjectionFormModel =
new SolarProjectionFormModel(
25,
17000,
180,
20,
2240,
.03
);
constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
this.http = http;
this.baseUrl = baseUrl;
}
ngOnInit() {
this.getProjection();
}
getProjection() {
let headers = new HttpHeaders({
'Accept': 'application/json',
'Content-Type': 'application/json'
});
let params = new HttpParams()
.set("param", JSON.stringify(this.model));
this.http.get<SolarProjection>(
this.baseUrl + 'api/SolarProjection',
{
headers: headers,
params: params
}
)
.subscribe(
result => {
this.solarProjection = result;
},
error => {
console.error(error)
}
);
}
inTheGreen(value: number): boolean {
if (value >= 0) {
return true;
}
return false;
}
toggleFormInput() {
this.isExpandedForm = !this.isExpandedForm;
}
onSubmit() {
this.toggleFormInput();
this.getProjection();
}
}
interface SolarProjection {
solarEstimate: YearlyElectricityUsage;
futureProjection: FutureProjection[];
financeYears: number;
}
interface YearlyElectricityUsage {
averageCostKiloWattHour: number;
averageCostPerMonth: number;
totalCost: number;
totalKiloWattHours: number;
}
interface FutureProjection {
solarEstimate: YearlyElectricityUsage;
purchaseYear: number;
averageCostKiloWattHour: number;
averageCostPerMonth: number;
totalCost: number;
totalKiloWattHours: number;
costSolar100Percent: number;
totalSavings100Percent: number;
costSolar90Percent: number;
totalSavings90Percent: number;
costSolar80Percent: number;
totalSavings80Percent: number;
}
[Route("api/[controller]")]
[ApiController]
public class SolarProjectionController : ControllerBase
{
private readonly IProjectFutureEnergyCostService _service;
public SolarProjectionController(IProjectFutureEnergyCostService service)
{
_service = service;
}
[HttpGet("[action]")]
public SolarVsUtilityProjection GetProjection()
{
return _service.CalculateFutureProjection(
ElectricityDataHelper.GetUsageWithPanelsMortgageAnnual(),
new ProjectionParameters(
ElectricityDataHelper.GetUsageUtility2017FromAnnual(),
25,
20,
.03
)
);
}
/// <summary>
/// Get solar projection with a json
/// string representing <see cref="SolarProjectionParameters"/>.
///
/// TODO there's gotta be a better way to do this signature,
/// both from a param and return perspective. I feel like
/// parameter should convey the proper type, and the result
/// should be able to convey a status perhaps?
/// </summary>
/// <param name="param">Json representation of <see cref="SolarProjectionParameters"/></param>
/// <returns><see cref="SolarVsUtilityProjection"/></returns>
[HttpGet]
public SolarVsUtilityProjection Get(string param)
{
// Convert json string to type
var solarProjectionParameters = JsonConvert
.DeserializeObject<SolarProjectionParameters>(param);
// Calculate future projection
return _service.CalculateFutureProjection(
solarEstimate: new YearlyKwhUsageFromAnnual(
totalCost: solarProjectionParameters.SolarCostPerMonth * 12,
totalKiloWattHours: solarProjectionParameters.UtilitySolarArrayKwhYear
),
projectionParameters: new ProjectionParameters(
utilityYear: new YearlyKwhUsageFromAnnual(
totalCost: solarProjectionParameters.UtilityCostFullYear,
totalKiloWattHours: solarProjectionParameters.UtilitySolarArrayKwhYear
),
yearsToProject: solarProjectionParameters.YearsToProject,
financeYears: solarProjectionParameters.SolarFinanceYears,
percentIncreasePerYear: solarProjectionParameters.UtilityPercentIncreasePerYear
)
);
}
}
/// <summary>
/// Parameters for creating a solar projection
/// </summary>
public class SolarProjectionParameters
{
/// <summary>
/// The number of years to project
/// </summary>
public int YearsToProject { get; set; }
/// <summary>
/// The total kw/h year used (will make solar projection with the
/// assumption the array can theoretically cover 100% of energy needs)
/// </summary>
public int UtilitySolarArrayKwhYear { get; set; }
/// <summary>
/// The cost per month of the solar financing
/// </summary>
public double SolarCostPerMonth { get; set; }
/// <summary>
/// The number of years the solar panels are financed
/// </summary>
public int SolarFinanceYears { get; set; }
/// <summary>
/// The total cost of a utility year
/// </summary>
public double UtilityCostFullYear { get; set; }
/// <summary>
/// The percentage increase of utility costs per year
/// </summary>
public double UtilityPercentIncreasePerYear { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment