Angular (web framework): Difference between revisions
(9 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Angular is a web framework by Google which allows you to create progressive web apps (PWAs). | Angular is a web framework by Google which allows you to create progressive web apps (PWAs) which are single page applications (SPA). | ||
It can also be used to create native mobile or desktop apps. | It can also be used to create native mobile or desktop apps. | ||
Note that this is a front-end framework only. You will need to pair it with a back-end framework to get stateful functionality. | |||
''This page is about Angular, also known as Angular 2. For AngularJS, the predecessor to Angular, see [https://angularjs.org/ https://angularjs.org/].'' | ''This page is about Angular, also known as Angular 2. For AngularJS, the predecessor to Angular, see [https://angularjs.org/ https://angularjs.org/].'' | ||
Line 9: | Line 10: | ||
* Install [[NodeJS]] and npm | * Install [[NodeJS]] and npm | ||
* Install the Angular CLI: <code>npm install -g @angular/cli</code> | * Install the Angular CLI: <code>npm install -g @angular/cli</code> | ||
===Creating a project=== | |||
<pre> | |||
ng new <project-name> | |||
</pre> | |||
<pre> | |||
ng serve --open | |||
</pre> | |||
==Usage== | ==Usage== | ||
Line 20: | Line 30: | ||
===Services=== | ===Services=== | ||
Services are singleton classes which can be accessed from any component. | |||
<pre> | |||
ng generate service <name> | |||
</pre> | |||
To access a service from a component, add a reference to the service as a parameter to the constructor of your component. | |||
==Routing== | |||
<pre> | |||
ng generate module app-routing --flat --module=app | |||
</pre> | |||
{{hidden | Route Module Example | | |||
<syntaxhighlight lang="typescript"> | |||
import { NgModule } from '@angular/core'; | |||
import { RouterModule, Routes } from '@angular/router'; | |||
import { HeroesComponent } from './heroes/heroes.component'; | |||
const routes: Routes = [ | |||
{ path: 'heroes', component: HeroesComponent } | |||
]; | |||
@NgModule({ | |||
imports: [RouterModule.forRoot(routes)], | |||
exports: [RouterModule] | |||
}) | |||
export class AppRoutingModule { } | |||
</syntaxhighlight> | |||
}} | |||
==Deployment== | ==Deployment== | ||
Line 44: | Line 82: | ||
</pre> | </pre> | ||
}} | }} | ||
===Express=== | |||
How to setup an Express server to host your Angular web application: | |||
{{ hidden | Route | | |||
First setup CSRF Protection: | |||
<syntaxhighlight lang="typescript"> | |||
this.csrfProtection = csurf({cookie: true}); | |||
this.app.use(this.csrfProtection); | |||
this.app.all( | |||
'*', | |||
(req: Request, res: Response, next: NextFunction): void => { | |||
res.cookie('XSRF-TOKEN', req.csrfToken()); | |||
next(); | |||
} | |||
); | |||
</syntaxhighlight> | |||
Then setup your routes to serve your frontend: | |||
<syntaxhighlight lang="typescript"> | |||
if (CONFIG.app.useProxy) { | |||
const myProxy = httpProxy.createProxyServer({ws: true}); | |||
console.log(`Proxying to ${CONFIG.app.appProxy}`); | |||
router.all('/*', (req: Request, res: Response, next: NextFunction) => { | |||
myProxy.web( | |||
req, | |||
res, | |||
{target: req.protocol + '://' + CONFIG.app.appProxy} | |||
); | |||
}); | |||
} else { | |||
router.all('/*', express.static(CONFIG.app.appFolder)); | |||
router.all('/*', (req: Request, res: Response, next: NextFunction) => { | |||
res.status(200).sendFile('index.html', {root: CONFIG.app.appFolder}); | |||
}); | |||
} | |||
</syntaxhighlight> | |||
If you are proxying for development, you will also need to proxy websockets: | |||
<syntaxhighlight lang="typescript> | |||
server.on( | |||
'upgrade', | |||
(request: http.IncomingMessage, socket: net.Socket, head: Buffer) => { | |||
const pathname = url.parse(request.url).pathname; | |||
if (pathname === '/backend') { | |||
this.wss.handleUpgrade(request, socket, head, ws => { | |||
this.wss.emit('connection', ws); | |||
}); | |||
} else if (CONFIG.app.useProxy) { | |||
console.log('proxying websocket'); | |||
myProxy.ws(request, socket, head, { | |||
target: 'ws://' + CONFIG.app.appProxy, | |||
}); | |||
} else { | |||
socket.destroy(); | |||
} | |||
} | |||
); | |||
</syntaxhighlight> | |||
}} | |||
==Libraries== | |||
Some interesting libraries for Angular | |||
* [https://github.com/angular/components Angular Components] | |||
** [[Angular Material]] ([https://material.angular.io/ website]) | |||
==Advanced Usage== | |||
===CSRF/XSRF=== | |||
See [https://angular.io/guide/http#security-xsrf-protection http#security-xsrf-protection] | |||
By default, the <code>HttpClientModule</code> will automatically reflect the <code>XSRF-TOKEN</code> cookie as <code>X-XSRF-TOKEN</code> if the following conditions are met: | |||
* <code>XSRF-TOKEN</code> is a cookie under <code>/</code> with <code>HttpOnly</code> set to false. | |||
* The outgoing request is not a <code>GET</code> or <code>HEAD</code> request. | |||
* The outgoing request path is a relative path of form <code>api/endpoint</code> or <code>//example.com/api/endpoint</code>. | |||
You can also set the name of the cookie and name of the header to something else if you prefer. | |||
===Open in new tab=== | |||
If you're making an SPA, and therefore using client-side routing with <code>routerLink</code>, your buttons and links may not have open in a new link on right click. | |||
See [https://stackoverflow.com/questions/56627500/right-click-open-in-new-tab-is-not-available-on-routerlink-withhin-a-div-tag SO] for a way to add this. | |||
===Advanced Routing=== | |||
* [https://medium.com/ngconf/routing-to-angular-material-dialogs-c3fb7231c177 Routing to Angular Material Dialogs] | |||
==Resources== | ==Resources== |