Creating a Python Web Application using Python Flask Part 3: Adding Angular to our web app

<< Part 2

Welcome back to my building a module web application with python flask series. Last time we saw how to have flask serve our static assets and this time we will bring in the javascript. If you haven’t done so all ready remember to follow the blog and share this post to show your support. Let’s get into this section.

Now that we have a core flask app set up and know how to render an HTML page using the Jinja templating engine we should probably make the static page actually do some awesome client side stuff using Angular 1. Now you may be thinking to yourself isn’t there angular 7 now, or isn’t there some other new hot javascript framework out that I heard about from X and then someone else told me Y was better.

Well let me break down why I’m using Angular 1 here, first it is a very solid framework and makes two-way data binding with the dom very simple. This means we can update the data on the page instantly without having to do page reloads and we can do it with a heavily documented and supported framework. Second, I happen to be very comfortable with angular 1.x to be able to quickly put together an application that can fit a clients needs which is ultimately what matters the most when selecting a technology.

However, there are some disadvantages to Angular 1.X such as not being compatible with ES6 but for the stuff we will be doing we don’t need this. Another disadvantage is that as the javascript application grows in size and complexity it’s easy to turn your application into spaghetti code since javascript is primitively typed, meaning that instead of an object being a type ‘person’ or ‘manager’ it is simply an object, making it easy to loose track what the object is supposed to abstract. Newer versions of Angular tries to help this by bringing in Typescript, but you typically need to set up a type script to javascript cross compiler using node, grunt, gulp, or some other tech. But, if you keep the angular controllers small, leave the business logic in services and factories letting them document themselves, and leave dom manipulation for directives; the spaghetti problem can be avoided and instead your angular code base can look like a nicely layered lasagna.

Apple iPad (Wi-Fi, 32GB) – Space Gray (Latest Model)

Please help this site by purchasing through our Amazon links

With that discussion out of the way, lets not forget the importance of this tutorial is to emphasize the interaction between Flask and the other two technologies. We may bring in React down the road if we find the time and there is interest but let’s get back to the minimal Angular set up.
<pre class="wp-block-syntaxhighlighter-code brush: xml; notranslate"><!-- HTML 5 doctype -->
<!DOCTYPE html>
<html ng-app="helloPython">
<head>
    <meta charset="UTF-8">
    <title>Hello world app</title>
    <link rel="stylesheet" type="text/css" href="static/css/theme.css">
    <!-- Angular CDN Imports -->
    <a href="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js">https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js</a>
    <a href="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-route.js">https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-route.js</a>
</head>
<body>
    <h1>Hello from Python Flask</h1>
    <a href="#test">test link</a>
    <div></div>
 
    <!-- Angular App Declaration -->
    <a href="/static/js/app/app.js">/static/js/app/app.js</a>
 
    <!-- Angular Controllers -->
    <a href="/static/js/app/controllers/testController.js">/static/js/app/controllers/testController.js</a>

</pre>

Key callouts:
  1. Add the ng-app to the html tag. Angular will parse for this tag when it source’s the angular library
  2. The two script tags on the top. These are the CDN links, Content distribution network, to the two main angular libraries we need for our minimal application. CDN links are fine for messing around with but please be aware when linking to a javascript file like this it leaves vulnerabilities for man in the middle attacks if the CDN link becomes compromised.
  3. href=”#test” this is an angular anchor that will look for a /test route set up in the app.js file
  4. angular uses a lot of decorators that start with ng-**** Within angular these are known as build in directives which are small pieces of self contained code that describe behavior for a specific component. The ng-view directive specifically will take template webpages that are defined in the app.js router config and insert them into this component
  5. This is the main javascript file that we will use to define and bootstrap the helloWorld angular module
  6. This will be the naming convention for the controllers we will source and expose to angular. Angular uses these controllers for the two-way databinding between the services and the views. It is important to keep these controllers slim and leave most the business logic for services. This will help keep your app maintainable as it grows in size.
With the html set up the other main piece to the Angular puzzle is the app.js file. Lets take a look at what’s in that.

app/static/js/app/app.js

// Module documentation https://docs.angularjs.org/guide/module
var app = angular.module("helloPython", ["ngRoute"]);
 
app.config(function($routeProvider) {
    $routeProvider
    .when("/", {
        templateUrl : "/static/views/main.htm"
    })
    .when("/test", {
        templateUrl : "/static/views/test.htm",
        controller: "testCtrl"
    })
});
Callouts:
1. “app” is defined on the global scope so we can attach controllers to it in other files
2. “helloPython” is the module name that we assigned to ng-app so angular will look for this
3. [“ngRoute”] this list is an example of angulars dependency injection which will give
the helloPython module the ability to use the ngRoute module. This list can be modified
to bring in mode modules. Typically “ngAnimate” is also found here
4. The app.config code sets up the built in client side routing by injecting the $routeProvider from the ngRoute module, using .when to define routes will enable the page to behave as a single page application, SPA, when we go to ‘ourpage.com/’ angular
will insert the main.htm content into the
component and
when we go to ourpage.com/#/test angular will insert test.htm and bind the
test controller javascript to control it’s behavior.
Here’s the code for our super complex Test Controller.
app/js/app/controllers/testController.js:
app.controller(‘testCtrl’, function($scope) {
$scope.title=”Hello from test partial’s controller”
});
Guess it’s not that complex! But what it does, is shows how we can inject the magic $scope that will enable us to link our data to the webpage. In this case since $scope.title is defined, then any webpage that uses this controller will be able to do
{{title}}
and the “Hello from test partial’s controller” text will be inserted here. This may not seem that cool now but later we can have buttons or api calls that will change this value, or link it to a service value that will enable us to dynamically change this value from other sources that use the service and the webpage will be updated to reflect this change instantaneously.
The last two files we need to go over are the two htm files we saw referenced in app.js. These will be the template files that get inserted into
by the angular router and for now they are both pretty small. I used the extension *.htm to designate these are meant to be partials and not complete html files.


/static/views/main.htm:
Hello from main.htm

/static/views/test.htm:
{{ title }}


Remember that the router is actually linking the testController with test.htm so angular will see {{title}} as the page is being inserted and substitute it with whatever $scope.title is currently assigned.
It is also important to mention that Flask will also look for this same {{}} annotation when it initially serves a page and try to substitute in values that are defined server side. For example if index.html had
{{title}}
and there existed code in the flask controller like this:
return render_template(‘hello.html’, title=”Title from flask”)
Then Jinja will substitute that title into the mustache bars and Angular will never see {{title}}. But since main.htm is being templated by Angular and not Jinja then Angular will actually template this file instead of Jinja. For this reason using two templating engines in the same page can get pretty confusing so it may be worth calling out something like this in index.html.
<html> <head> </head> <body> {% raw %} <!– ANGULAR WILL BE DOING ALL THE TEMPLATING –>
… All of our content …

{% endraw %} </body> </html>

This will tell jinja to ignore any templating in our page and specifically let angular parse it. We can also tell angular to use something else for it’s annotations by doing this:
app.config(function($interpolateProvider) {
        $interpolateProvider.startSymbol('[[').endSymbol(']]');
    });
Then we can do inside of index.html
[[ title ]]
to get around the Jinja problem but that will make the code interesting to read for someone new coming to your project.

Anyways that will do it for this post. In our next post we will be bringing in a dashboard theme to make our UI look sweet then touch on some AWS functionality that can help our web app after that! Thank you and have a great day. How have you been liking this series so far? Is there anything else you want to see or specific feature request you want in the future? Leave a comment below.

2 thoughts on “Creating a Python Web Application using Python Flask Part 3: Adding Angular to our web app

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s