Paul BecotteAdmin

Updating the Blog

Single Page Apps for Everyone

It has been a while now since I started my DevBlog project. As usual, work gets in the way and I can only really get motivated to get stuff done in side projects in spurts (with my off-duty coding time often being taken up by interesting work-related stuff that gets stuck in my head lol). Over the last month I managed to put in some hours though, and got a lot of coding done! The whole app now has a dedicated Angular2 frontend written in Typescript, and I added a comment system. (please sign up and leave a comment to let me know that this is working lol). The fun part about the Angular2 frontend is that I do not know Javascript or Typescript. Though I had picked up bits and pieces contributing features to the Bam frontend (which was an Angular 1 project in JS), this is the first time I have written anything useful in a frontend language, and the first time even seeing Typescript. Let me tell you a bit about some things I learned in the Angular2 world.

Services aren't just for http

When I first set up the system, I assumed services were mainly for making api calls to the backend. However, I found that they can also provide global state for the application. For example, a MessageService object that gets injected just like the other ones can handle displaying your messages on the top level route.

@Injectable()
export class MessageService { 
    public messages:string[]; 
    constructor () { this.messages = [] } 
    addMessage(message:string) { this.messages.push(message) } 
    ackMessage(message:string) { var index = this.messages.indexOf(message); this.messages.splice(index, 1); }}
//root.component.html
<div *ngFor="let message of messageService.messages" class="alert alert-dismissable alert-success"> 
    <button (click)="messageService.ackMessage(message)" type="button" class="close" data-dismiss="alert" aria hidden="true">
        ×
    </button> 
    <p>
        {{ message }}
    </p> 
</div>

So any component that wants to flash a message can just inherit the MessageService and call addMessage()!

Auth is harder than it should be

While it seems like this should be a solved problem, it took me a couple days to get authentication working at all in my app. Most of these problems were with the Python libraries I was using for backend security- very few libraries consider that you may not be serving Jinja2 templates and hardcode things like WTForms CSRF. Since I am not, disabling the CSRF check was the easiest fix on the backend. On the frontend, I wound up having to build an auth service that wraps the built in http service. It adds the auth token header to every request before passing it along.

// auth.service.ts
head() {
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    let authToken = localStorage.getItem('auth_token');
    headers.append('Authorization', `JWT ${authToken}`);
    return {headers}
}

get(url) {
    return this.http.get(url, this.head())
}

post(url, body) {
    return this.http.post(url, body, this.head())
}

Again, this service carries some global state (is the user logged in? What permissions do they have?). There is probably a more elegant way to inject this in the place of the built in HTTP, but this worked for me!

Conclusion

These two tips are far from the state of the art, but I learned a ton while doing this, and am now pretty impressed by how quickly I can add interactive front ends to my apps. I am a pretty big fan of Angular2- if only they would actually release it now lol...