1
0
mirror of https://github.com/mgerb/mywebsite synced 2026-01-10 09:52:51 +00:00

got angular routing working - starting on html components

This commit is contained in:
2016-05-15 01:58:38 -05:00
parent d680c85c4a
commit 73fcbe6a5f
22 changed files with 778 additions and 42 deletions

View File

@@ -1,16 +0,0 @@
package controller
import (
//"encoding/json"
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
)
// IndexGET displays the home page
func NotFound404(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
http.Redirect(w, r, "/404.html", 404)
fmt.Fprint(w, "test")
}

29
controller/api/testApi.go Normal file
View File

@@ -0,0 +1,29 @@
package api
import (
"encoding/json"
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
)
type ApiCall struct {
Fname string
Lname string
}
// Redirect to discord
func TestApiCall(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := new(ApiCall)
s.Fname = ps.ByName("fname")
s.Lname = ps.ByName("lname")
response, _ := json.MarshalIndent(s, "", " ")
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(response))
}

View File

@@ -1,18 +0,0 @@
package controller
import (
//"encoding/json"
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
)
// IndexGET displays the home page
func IndexGet(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Header().Set("Content-Type", "application/json")
response := "{\"test\" : 123}"
fmt.Fprint(w, response)
}

13
controller/redirect.go Normal file
View File

@@ -0,0 +1,13 @@
package controller
import (
"github.com/julienschmidt/httprouter"
"net/http"
)
// Redirect to discord
func Discord(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
http.Redirect(w, r, "https://discordapp.com/invite/0Z2tzxKECEj2BHwj", 301)
}

View File

@@ -1 +0,0 @@
404: Page not found

330
public/css/style.css Normal file
View File

@@ -0,0 +1,330 @@
html {
overflow-y: scroll;
}
body {
font-family: Century Gothic,CenturyGothic,AppleGothic,sans-serif;
}
a {
color: #00B7FF;
}
.textCenter {
text-align: center;
}
.resume{
font-size: 12pt;
font-weight: 400;
}
.header {
height: 400px;
background: url("/public/images/headerBackground.jpg") center no-repeat;
background-size: cover;
}
.headerText{
font-size: 80px;
color: white;
margin-top: 0px;
}
.large-text{
font-size: 100px;
}
.centerDiv{
position: relative;
top: 50%;
transform: translateY(-50%);
}
.form-signin {
max-width: 500px;
padding: 15px;
margin: 0 auto;
}
.form-signin .form-control {
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
}
.form-file {
max-width: 500px;
padding: 15px;
margin: 0 auto;
}
.form-file .form-control {
position: relative;
height: 34px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
}
.colorRed {
color: red;
}
.colorGreen {
color: green;
}
.timeForm {
width: 30%;
display: inline;
}
.aboutMeImage {
width: 100%;
height: 100%;
}
.center {
margin-left: auto;
margin-right: auto;
display: block;
}
/*
* Override Bootstrap's default container.
*/
@media (min-width: 1200px) {
.container {
width: 970px;
}
}
/*
* Masthead for nav
*/
.blog-masthead {
background-color: #428bca;
-webkit-box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
}
/* Nav links */
.blog-nav-item {
position: relative;
display: inline-block;
padding: 10px;
font-weight: 500;
color: #cdddeb;
}
.blog-nav-item:hover,
.blog-nav-item:focus {
color: #fff;
text-decoration: none;
}
/* Active state gets a caret at the bottom */
.blog-nav .active {
color: #fff;
}
.blog-nav .active:after {
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 0;
margin-left: -5px;
vertical-align: middle;
content: " ";
border-right: 5px solid transparent;
border-bottom: 5px solid;
border-left: 5px solid transparent;
}
/*
* Blog name and description
*/
.blog-header {
padding-top: 20px;
padding-bottom: 20px;
}
.blog-title {
margin-top: 30px;
margin-bottom: 0;
font-size: 60px;
font-weight: normal;
}
.blog-description {
font-size: 20px;
color: #999;
}
/*
* Main column and sidebar layout
*/
.blog-main {
font-size: 18px;
line-height: 1.5;
}
/* Sidebar modules for boxing content */
.sidebar-module {
padding: 15px;
margin: 0 -15px 15px;
}
.sidebar-module-inset {
padding: 15px;
background-color: #f5f5f5;
border-radius: 4px;
}
.sidebar-module-inset p:last-child,
.sidebar-module-inset ul:last-child,
.sidebar-module-inset ol:last-child {
margin-bottom: 0;
}
/* Pagination */
.pager {
margin-bottom: 60px;
text-align: left;
}
.pager > li > a {
width: 140px;
padding: 10px 20px;
text-align: center;
border-radius: 30px;
}
/*
* Blog posts
*/
.blog-post {
margin-bottom: 60px;
}
.blog-post-title {
margin-bottom: 5px;
font-size: 40px;
}
.blog-post-meta {
margin-bottom: 20px;
color: #999;
}
/*
* Footer
*/
.blog-footer {
padding: 40px 0;
color: #999;
text-align: center;
background-color: #f9f9f9;
border-top: 1px solid #e5e5e5;
}
.blog-footer p:last-child {
margin-bottom: 0;
}
.lowerLeft{
color: white;
display: table-cell;
vertical-align: bottom;
height: 400px;
width: 800px;
}
.colorWhite{
color: white;
}
.mitchell-navbar{
border-radius: 0 !important;
background-color: #262626;
border: 0;
}
.gist {
width:600px !important;
}
.gist-file{
}
.gist-data{
max-height: 500px;
max-width: 600px;
}
.chart-legend li span{
display: inline-block;
width: 12px;
height: 12px;
margin-right: 5px;
}
.modal {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 255, 255, 255, .8 )
url('http://i.stack.imgur.com/FhHRx.gif')
50% 50%
no-repeat;
}
/* When the body has the loading class, we turn
the scrollbar off with overflow:hidden */
body.loading {
overflow: hidden;
}
/* Anytime the body has the loading class, our
modal element will be visible */
body.loading .modal {
display: block;
}
.btn-file {
position: relative;
overflow: hidden;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: white;
cursor: inherit;
display: block;
}
input[readonly] {
background-color: white !important;
cursor: text !important;
}

BIN
public/images/aboutme.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 KiB

BIN
public/images/sensors.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

49
public/js/app.js Normal file
View File

@@ -0,0 +1,49 @@
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
$routeProvider.
when('/', {
templateUrl: '/public/view/index.html',
controller: 'IndexController'
}).
when('/sensors', {
templateUrl: '/public/view/404.html',
controller: 'SensorsController'
}).
when('/post/:postName', {
templateUrl: '/public/view/post.html',
controller: 'PostController'
}).
when('/discord', {
redirect: 'https://discordapp.com/invite/0Z2tzxKECEj2BHwj'
}).
otherwise({
templateUrl: '/public/view/404.html'
});
}]);
app.controller('IndexController', function($scope) {
$scope.message = 'This is Add new order screen';
});
app.controller('SensorsController', function($scope) {
$scope.message = 'This is Show orders screen';
});
//handle each post page after individual posts are selected
app.controller('PostController', function($scope, $route, $routeParams) {
$scope.post = "/public/posts/" + $routeParams.postName + ".html";
});

View File

@@ -0,0 +1,55 @@
<div class="blog-post">
<h2 id="title" class="blog-post-title">Temperature Sensor - Server Side</h2>
<p id="date" class="blog-post-meta">January 1, 2016 by Mitchell</p>
<p id="intro">The server side coding is a bit more complicated than programming the ESP8266 itself. I use a NoSQL database to store the information and some of the queries are complex and can be confusing to understand. I also make use of REST API's to send the data to the client side.
</p>
<hr>
<h3>Storing Information</h3>
<p>For this project I am using MongoDB to store all of my information because it goes well with my server, which is coded in Node.js, but any database could be used. I also wanted to learn about NoSQL databases because I already have experience with SQL databases. Information on coding the ESP8266 can be found <a href="/?post=12-18-2015.html">here</a> in a previous post.
</p>
<code>mitchellg.me/temperature?temperature=0&humidity=0&location=0&key=0</code>
<p>Above is the GET request that is sent to the server from the ESP8266. Data is tranferred through GET parameters. The key is an authentication code that I set to prevent unwanted HTTP requests. This is similar to an API key. Below is the code implemented to handle the HTTP request from the ESP8266.
</p>
<script src="https://gist.github.com/mgerb42/4bedafa2bde264ee3135.js"></script>
<h3>Creating the REST API</h3>
<p>There are many ways that I could display the temperature information on a graph, but I was trying to come up with a quick and easy way that was also efficient. I also wanted reusability in case I wanted to add or change things down the road. I decided I was going to use <a href="http://www.chartjs.org/">Chart.js</a> because it is open source and free. These graphs are implemented on the front end using javascript. Because of this I needed to figure out a way to send the sensor data to the client side. I felt that the best way for me to do it would be creating a REST API. I plan on making another post in the future explaining all of my client side code along with how to use Chart.js.
</p>
<p>Now that I know how I want to display my information I just need to think of what information I want to display. I thought it would be cool to display a few different graphs. As of right now I have one graph that displays data by the year and one that displays by each month. The maximum and minimum temperature of each day are displayed as well as the average humidity for that day. The user can also select which year or which month to display and the graph will adjust accordingly.
</p>
<p>Now that I know what information I need I can start developing my REST API. I have a MongoDB collection called "temperature", which stores temperature, humidity, location, and time updated. Updated is a type of Date, which I will use in all of the queries to group by each day. To do the grouping in MongoDB I needed to use the <a href="https://docs.mongodb.org/v3.0/aggregation/">aggregation functionality</a> of MongoDB. Aggregation allows me to essentially perform queries on top of queries using the MongoDB "pipeline". This is similar to an SQL query when a selection is performed within a selection.
</p>
<script src="https://gist.github.com/mgerb42/4879f4897f7e863e9003.js"></script>
<h3>Explanation of MongoDB Queries</h3>
<p>The first function takes in a location and year and returns maximum and minimum temperature readings as well as average humidity for each day in the selected year. The results are also returned sorted from newest to oldest.
</p>
<p>In the first part of the aggregation pipeline, which is $project, I am just selecting the temperature, humidity, year, month, and day. This part is important because it allows me to pull the year, month, and day from the date that is stored in the database. This way I do not have to store each of these entries separately in the database.
</p>
<p>This data is then passed to the next part of the aggregation pipeline. The $match pipeline stage selects out information from the collection which match with the selected year and location.
</p>
<p>The $group aggregation operator is the stage in which I actually group the data by the location, year, month, and day. For each group I also take the max and min temperatures along with the average humidity by using the correct accumulator operators. Now that I have the appropriate information I need, I just use the $sort pipeline operator to sort the data based on time updated.
</p>
<p>The function to display by month is the exact same, except I take in the month attribute and add it to the $match operator within the aggregation pipeline. Just like that the query is complete and all I need to do is send the response back to the client. Chart.js uses JSON format, which makes things extremely easy because MongoDB querie results are in JSON. I set the content type to JSON, and use JSON.stringify() to convert the JSON to a readable format for debugging purposes. An example API request can be tested out here.
</p>
<p><a href="/api/sensorbylocation/year?location=Winona%20Apartment&year=2016">/api/sensorbylocation/year?location=Winona%20Apartment&year=2016</a>
</p>
</div>

View File

@@ -1 +0,0 @@
test

23
public/view/404.html Normal file
View File

@@ -0,0 +1,23 @@
<br>
<br>
<br>
<br>
<br>
<h1 class="text-center large-text">404</h1>
<h4 class="text-center">This page may be in production, or it may not exist.</h4>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>

25
public/view/index.html Normal file
View File

@@ -0,0 +1,25 @@
<div class="container">
<div class="row">
<div class="col-sm-8 blog-main">
</div> <!-- new blog posts-->
<div class="col-sm-4 blog-sidebar">
<h1 class="text-center">About Me</h1>
<img class="aboutMeImage center img-rounded" src="/public/images/aboutme.jpg">
<br>
<div class="sidebar-module sidebar-module-inset">
<p> I'm 22 years old and currently attending Winona State University as a Computer Science major.
I am graduating in Spring of 2016 and plan to pursue a career in the field of software development.
</p>
</div>
</div>
</div>
</div>

27
public/view/post.html Normal file
View File

@@ -0,0 +1,27 @@
<div class="container">
<div class="row">
<div class="col-sm-8 blog-main">
<ng-include src="post"></ng-include>
</div> <!-- new blog posts-->
<div class="col-sm-4 blog-sidebar">
<h1 class="text-center">About Me</h1>
<img class="aboutMeImage center img-rounded" src="/public/images/aboutme.jpg">
<br>
<div class="sidebar-module sidebar-module-inset">
<p> I'm 22 years old and currently attending Winona State University as a Computer Science major.
I am graduating in Spring of 2016 and plan to pursue a career in the field of software development.
</p>
</div>
</div>
</div>
</div>

100
public/view/template.html Normal file
View File

@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>mitchel.io</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.css">
<link href='https://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
<style>
[ng\:cloak], [ng-cloak], .ng-cloak {
display: none;
}
</style>
</head>
<body ng-app="app" ng-cloak>
<div class="header">
<div class="container">
<div class="lowerLeft">
<h1 class="">mitchel.io</h1>
<p class="">A site in which I share information about my personal projects.</p>
</div>
</div>
</div>
<nav class="navbar mitchell-navbar" role="navigation">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/sensors">Sensors</a>
</li>
<li>
<a href="/resume">Resume</a>
</li>
<li>
<a href="mailto:mgerber11@winona.edu">Contact</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li>
<a href="/newpost">New Post</a>
</li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container -->
</nav>
<!-- dynamically load content into the page with angular (ng-view) -->
<ng-view></ng-view>
<!-- ------------------------------------------------------------- -->
<footer class="blog-footer">
<p>Site created and managed by Mitchell Gerber</p>
<span>©2015-2016</span>
<br>
<span>Glyphicons provided by</span><br>
<a href="http://glyphicons.com/" target="_blank"><span>glyphicons.com</span></a>
</footer>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-beta1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/i18n/jquery-ui-i18n.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-route.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-resource.js"></script>
<script src="/public/js/app.js"></script>
</html>

1
readme.md Normal file
View File

@@ -0,0 +1 @@
## Converting to Go back end and Angular front end

View File

@@ -1,24 +1,42 @@
package route
import (
//"encoding/json"
//"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
"github.com/mgerb42/mywebsite/controller"
"github.com/mgerb42/mywebsite/controller/api"
)
func Routes() *httprouter.Router {
r := httprouter.New()
r.GET("/", controller.IndexGet)
r.GET("/api/:fname/:lname", api.TestApiCall)
//set up public folder path
r.ServeFiles("/public/*filepath", http.Dir("./public"))
//404 not found
r.NotFound = http.NotFoundHandler()
//route every invalid request to template file
//routing is all handled on the client side with angular
r.NotFound = http.HandlerFunc(fileHandler("./public/view/template.html"))
return r
}
//route requests to static files
func routerFileHandler(path string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
http.ServeFile(w, r, path)
}
}
//function to serve files with standard net/http library
func fileHandler(path string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, path)
}
}

12
testing_files/404.go Normal file
View File

@@ -0,0 +1,12 @@
package controller
import (
"net/http"
)
// IndexGET displays the home page
func PageNotFound(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./public/404.html")
}

77
testing_files/index.go Normal file
View File

@@ -0,0 +1,77 @@
package controller
import (
"encoding/json"
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
)
type Person struct {
Location City
Name string
Age int
Car []Car
}
type City struct {
Coords Coordinate
Population int
}
type Coordinate struct {
Latitude int
Longitude int
}
type Car struct {
Make string
Year int
}
// IndexGET displays the home page
func IndexGet(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
params := p.ByName("test")
fmt.Println(params)
w.Header().Set("Content-Type", "application/json")
js := Person{
Location: City{
Coords: Coordinate{
Latitude: 23,
Longitude: 32,
},
Population: 5000,
},
Name: "Mitchell",
Age: 22,
Car: []Car{
Car{
Make: "Mitz",
Year: 2003,
},
Car{
Make: "Honda",
Year: 2016,
},
},
}
b, err := json.MarshalIndent(js, "", " ")
if err != nil {
fmt.Println(err.Error)
}
s := string(b)
fmt.Fprint(w, s)
}
func Api(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
param := p.ByName("name")
fmt.Fprint(w, param)
}

13
testing_files/redirect.go Normal file
View File

@@ -0,0 +1,13 @@
package controller
import (
"github.com/julienschmidt/httprouter"
"net/http"
)
// Redirect to discord
func Discord(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
http.Redirect(w, r, "https://discordapp.com/invite/0Z2tzxKECEj2BHwj", 301)
}