So I had to start humble and create a traditional ASP .NET project and add MVC functionality to it. I figured this would be a good way to be able to download and learn from the quickstart at :
https://angular.io/docs/ts/latest/cookbook/visual-studio-2015.html
I got some help from the internet with adding MVC "areas" to my project, so as to add MVC functionality, but not lose the traditional ASP application behaviors.
I don't remember where exactly I picked up the "AREAS" education, but the topic is heavily explained :
https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=how+to+add+MVC+areas&*
Jumping to the end, my new stock tracker application runs at :
https://www.customconfiguration.net/ng/Stocks/StocksAngular
New users would want to be logged into Twitter for easy signup, or create a new account to use the app.
Forgiving my choice of traditional (Non-WebApi) controllers for a second, it only seems useful to look at a couple of sample methods :
[Authorize()] [AcceptVerbs(HttpVerbs.Get)] public JsonResult ReadStockQuote(string Id) { Quote q; if (Id.Length > 0) { q = getQuoteFromYahoo(Id); } else { q = new Quote(); } return Json(q, JsonRequestBehavior.AllowGet); } [Authorize()] [AcceptVerbs(HttpVerbs.Get)] [OutputCache(Duration = 360, VaryByParam = "Id")] public JsonResult ReadPrice(string Id) { string lastTrade = string.Empty; string color = string.Empty; string error = string.Empty; try { Quote q = getQuoteFromYahoo(Id); lastTrade = "$" + q.LastTrade; if (q.PercentChange.Contains("-")) { color = "Red"; } else { color = "Green"; } } catch (System.Exception exception) { lastTrade = "error"; error = exception.Message; } return Json( new Stock() { Price = lastTrade, Color = color, // Message = error, Symbol = Id }, JsonRequestBehavior.AllowGet); }
So the code for the controllers just does basic Add, Delete, Get, And some RSS feed reading from Yahoo's generous web services.
Following the example provided at the Angular website, I created and "app" folder with "components" and "services" folders included> Everything prescribed in the tutorial, I copied into my project unchanged.
I then built the app I wanted following the example where relevant. I jumped around to get ahead to Routing, because I really wanted that feature even though my small app could certainly have existed in one view.
My main view for the single page app, just has one selector tag, along with the referenced scripts in the head tag :
<base href="@Url.Content("~")"> @Styles.Render("~/Content/css") <!-- Polyfill(s) for older browsers --> <script src="~/node_modules/core-js/client/shim.min.js"></script> <script src="~/node_modules/zone.js/dist/zone.js"></script> <script src="~/node_modules/systemjs/dist/system.src.js"></script> <script src="~/systemjs.config.js"></script> <script> System. import('main.js') . catch(function (err) { console. error(err); }); </script>
<stocks>Loading AppComponent content here </stocks>
The app Module script file has been updated from the example with my components :
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { HttpModule, JsonpModule } from '@angular/http'; import { Http } from '@angular/http'; import { Router } from '@angular/router'; import { AppServiceStocks } from './services/app.service.stocks'; import { AppStocks } from './components/app.component.stocks'; import { AddComponent } from './components/app.component.stockadd'; import { RemComponent } from './components/app.component.stockrem'; import { NewsComponent } from './components/app.component.stocknews'; import { AppComponent } from './components/app.component'; import { PageNotFoundComponent } from './components/not-found.component'; import { AppRoutingModule } from './app-routing'; @NgModule({ imports: [BrowserModule, HttpModule, FormsModule, AppRoutingModule], declarations: [ AppComponent, AppStocks, AddComponent, PageNotFoundComponent, RemComponent, NewsComponent], bootstrap: [AppComponent] }) export class AppModule { // Diagnostic only: inspect router configuration constructor(router: Router) { // console.log('Routes: ', JSON.stringify(router.config, undefined, 2)); } }
The app Routing script file also was built from tutorial and just fleshed out with my own paths :
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './components/app.component'; import { AppStocks } from './components/app.component.stocks'; import { AddComponent } from './components/app.component.stockadd'; import { RemComponent } from './components/app.component.stockrem'; import { NewsComponent } from './components/app.component.stocknews'; import { PageNotFoundComponent } from './components/not-found.component'; // import { CanDeactivateGuard } from './can-deactivate-guard.service'; // import { AuthGuard } from './auth-guard.service'; import { SelectivePreloadingStrategy } from './components/selective-preloading-strategy'; const appRoutes: Routes = [ { path: 'Stocks/StocksAngular/Add', component: AddComponent }, { path: 'Stocks/StocksAngular/Delete/:id', component: RemComponent }, { path: 'Stocks/StocksAngular/News/:id', component: NewsComponent }, { path: 'Stocks/StocksAngular', component: AppStocks }, { path: '', redirectTo: 'Stocks/StocksAngular', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ]; @NgModule({ imports: [ RouterModule.forRoot( appRoutes, { preloadingStrategy: SelectivePreloadingStrategy } ) ], exports: [ RouterModule ], providers: [ // CanDeactivateGuard, SelectivePreloadingStrategy ] }) export class AppRoutingModule { }
It is important to remember to not allow MVC to interfere with Angular's routing :
In the RouteConfig file place something like - routes.MapRoute( name: "ngOverride", url: "Stocks/StocksAngular/{*.}", defaults: new { controller = "Stocks", action = "StocksAngular" } );
The app service script file is called app.service.stocks.js :
import { Injectable } from '@angular/core'; import { Http, Response, URLSearchParams, RequestOptions, Headers } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/Rx'; import { stock } from '../components/stock'; import { rssitem } from '../components/rssitem'; import { quote } from '../components/quote'; @Injectable() export class AppServiceStocks { private _getStocksListUrl = 'Stocks/StocksJSON'; private _getStockDetailUrl = "Stocks/ReadStockQuote?Id="; private _getPriceUrl = "Stocks/ReadPrice?Id="; private _getNameUrl = "Stocks/GetNameFromSymbol?Id="; private _getNewsUrl = "http://feeds.finance.yahoo.com/rss/2.0/headline?s="; private _deleteStockUrl = "Stocks/Remove"; private _addStockUrl = "Stocks/AddJSON"; private _stockslist: stock[]; constructor(private http: Http) { } stockslist(): Observable{ return this.http.get(this._getStocksListUrl) .map(this.extractData) .catch(this.handleError); } stockDetail(symbol : string): Observable { return this.http.get(this._getStockDetailUrl + symbol) .map(this.extractData) .catch(this.handleError); } getNameFromSymbol(symbol: string): Observable{ return this.http.get(this._getNameUrl + symbol) .map(this.extractData) .catch(this.handleError); } readPrice(symbol: string): Observable { return this.http.get(this._getPriceUrl + symbol) .map(this.extractData) .catch(this.handleError); } readNews(symbol: string): Observable { var newsLink = this._getNewsUrl + symbol + "®ion=US&lang=en-US"; let params: URLSearchParams = new URLSearchParams(); params.set('Link', newsLink); return this.http.get("Stocks/ReadNewsData?", { search: params }) .map(this.extractData) .catch(this.handleError); } readYahooNews(symbol: string): Observable { let params: URLSearchParams = new URLSearchParams(); params.set('Symbol', symbol); return this.http.get("Stocks/ReadYahooNewsData", { search: params }) .map(this.extractData) .catch(this.handleError); } remove(s : stock) : Observable { let headers = new Headers({ 'Content-Type': 'application/json' }); let options = new RequestOptions({ headers: headers }); return this.http.post(this._deleteStockUrl, { item : s }, options) .map(this.extractData) .catch(this.handleError); } add(s: string): Observable { let headers = new Headers({ 'Content-Type': 'application/json' }); let options = new RequestOptions({ headers: headers }); return this.http.post(this._addStockUrl, { Symbol : s }, options) .map(this.extractData) .catch(this.handleError); } private handleError(error: Response | any) { // In a real world app, we might use a remote logging infrastructure let errMsg: string; if (error instanceof Response) { const body = error.json() || ''; const err = body.error || JSON.stringify(body); errMsg = `${error.status} - ${error.statusText || ''} ${err}`; } else { errMsg = error.message ? error.message : error.toString(); } console.error(errMsg); return Observable.throw(errMsg); } private extractData(res: Response) { let body = res.json(); return body || {}; }
import { Component } from '@angular/core'; import { stock } from './stock'; import { quote } from './quote'; import { Observable } from 'rxjs/Observable'; import { AppServiceStocks } from '../services/app.service.stocks'; @Component({ selector: 'stocks', templateUrl: './app/components/app.component.stocks.html?v=4', providers: [AppServiceStocks] }) export class AppStocks { name = 'Angular Stocks'; stockslist: stock[]; mode = 'Observable'; statusMessage = ""; newStockName = ""; newStockSym = ""; newStock = new stock(); rownum = 0; interval = 2; constructor(private _appService: AppServiceStocks) { } ngOnInit() { this.newStockName = ""; this.getStocks(); } private readPrice() { this._appService.readPrice(this.stockslist[this.rownum].Symbol) .subscribe(result => { this.stockslist[this.rownum].Price = result.Price; this.stockslist[this.rownum].Color = result.Color; this.rownum++; if (this.rownum == this.stockslist.length) { this.rownum = 0; } this.getNextQuote(); }); } private getNextQuote() { setTimeout(() => { this.readPrice() }, this.interval * 1000); } getStocks() { this._appService.stockslist() .subscribe( stocks => { this.stockslist = stocks; this.getNextQuote(); }); } }
1 comment:
Just an update on this.. it was done and running, but somehow the free Yahoo webservice for the stock prices stopped working. No worry, it was just a prototyping exercise.
Post a Comment