The Bootstrap framework for creating web pages
has been very popular in recent years, both because of the design and
the automatic support for responsive pages on all sorts of devices.
Bootstrap can easily be used in combination with Flask. The template file
view_bootstrap.html
is identical to the former view_table.html
,
except that we load the Bootstrap CSS file and include in comments
how to add the typical navigation bar found in many Bootstrap-based
web pages. Moreover, we use the grid layout functionality of Bootstrap
to control the placement of elements (name, input field, label,
and error message) in the input form.
The template looks like
<!DOCTYPE html>
<html lang="en">
<link href=
"http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"
rel="stylesheet">
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: {
equationNumbers: { autoNumber: "AMS" },
extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
}
});
</script>
<script type="text/javascript" src=
"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<!--
<nav class="navbar navbar-default" role="navigation">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
{% for text, url in some_sequence %}
<li><a href="/{{url}}">{{ text }}</a></li>
{% endfor %}
</ul>
</div>
</nav>
-->
<h2>Damped sine wave</h2>
This web page visualizes the function \(
u(t) = Ae^{-bt}\sin (w t), \hbox{ for } t\in [0,T]
\).
<p>
<form class="navbar-form navbar-top" method="post" action="">
<div class="form-group">
{% for field in form %}
<div class="row">
<div class="input-group">
<label class="col-xs-1 control-label">
<span class="input-group-addon"> \( {{ field.name }} \) </span>
</label>
<div class="col-xs-2">
{{ field(class_="form-control") }}
</div>
<div class="col-xs-3">
{{ field.label }}
</div>
{% if field.errors %}
{% for error in field.errors %}
<div class="col-xs-3">
<div style="color: red;">{{ error }}</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
{% endfor %}
<br/>
<input type="submit" value="Compute" class="btn btn-default">
</form>
<p>
{% if result != None %}
<img src="{{ result }}" width="400">
{% endif %}
</html>
The input fields and fonts now get the typical Bootstrap look and feel:
The only special feature in this template is the need to pass a CSS
class form-control
to the field object in the part that defines
the input field. We also use the standard input-group-addon
style
in the name part of the Bootstrap form. A heading Damped sine wave was
added to demonstrate the Bootstrap fonts.
It is easy to switch to other Bootstrap styles, e.g., those in the "Bootswatch family": "http:bootswatch.com":
<link href=
"http://netdna.bootstrapcdn.com/bootswatch/3.1.1/X/bootstrap.min.css"
rel="stylesheet">
where X
can be journal
, cosmo
, flatly
, and other legal
Bootswatch styles. The journal style looks like this:
While view_bootstrap.html
makes use of plain Bootstrap HTML code, there is
also a higher-level framework, called Flask-Bootstrap that combines Flask and Bootstrap. Installation of
this extension is done by sudo pip install flask-bootstrap
.
After app = Flask(__name__)
we need to do
from flask_bootstrap import Bootstrap
Bootstrap(app)
We introduce a command-line argument to control whether we want the
plain view or the Bootstrap view. The complete controller.py
file
then looks like
from model import InputForm
from flask import Flask, render_template, request
from compute import compute
import sys
app = Flask(__name__)
try:
template_name = sys.argv[1]
except IndexError:
template_name = 'view_plain'
if template_name == 'view_flask_bootstrap':
from flask_bootstrap import Bootstrap
Bootstrap(app)
@app.route('/vib1', methods=['GET', 'POST'])
def index():
form = InputForm(request.form)
if request.method == 'POST' and form.validate():
result = compute(form.A.data, form.b.data,
form.w.data, form.T.data)
else:
result = None
return render_template(template_name + '.html',
form=form, result=result)
if __name__ == '__main__':
app.run(debug=True)
The template employs new keywords extends
and block
:
{% extends "bootstrap/base.html" %}
{% block styles %}
{{super()}}
<style>
.appsize { width: 800px }
</style>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: {
equationNumbers: { autoNumber: "AMS" },
extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
}
});
</script>
<script type="text/javascript" src=
"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
{% endblock %}
<!--
{% block navbar %}
<nav class="navbar navbar-default" role="navigation">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
{% for f in some_sequence %}
<li><a href="/{{f}}">{{f}}</a></li>
{% endfor %}
</ul>
</div>
</nav>
{% endblock %}
-->
{% block content %}
<h2>Damped sine wave</h2>
This web page visualizes the function \(
u(t) = Ae^{-bt}\sin (w t), \hbox{ for } t\in [0,T]
\).
<p>
<form class="navbar-form navbar-top" method="post" action="">
<div class="form-group">
{% for field in form %}
<div class="row">
<div class="input-group appsize">
<label class="col-sm-1 control-label">
<span class="input-group-addon"> \( {{ field.name }} \) </span>
</label>
<div class="col-sm-4">
{{ field(class_="form-control") }}
</div>
<div class="col-sm-4">
{{ field.label }}
</div>
{% if field.errors %}
{% for error in field.errors %}
<div class="col-sm-3">
<div style="color: red;">{{ error }}</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
{% endfor %}
<br/>
<input type="submit" value="Compute" class="btn btn-default">
</form>
<p>
{% if result != None %}
<img src="{{ result }}" width="500">
{% endif %}
</html>
{% endblock %}
It is important to have the MathJax script declaration and all styles within
{% block styles %}
.
It seems easier to apply plain Bootstrap HTML code than the functionality in the Flask-Bootstrap layer.