Browse Source

add javascript ajax example

pull/2699/head
David Lord 7 years ago
parent
commit
fce1885f76
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
  1. 5
      docs/patterns/jquery.rst
  2. 6
      docs/testing.rst
  3. 14
      examples/javascript/.gitignore
  4. 31
      examples/javascript/LICENSE
  5. 4
      examples/javascript/MANIFEST.in
  6. 49
      examples/javascript/README.rst
  7. 5
      examples/javascript/js_example/__init__.py
  8. 33
      examples/javascript/js_example/templates/base.html
  9. 35
      examples/javascript/js_example/templates/fetch.html
  10. 27
      examples/javascript/js_example/templates/jquery.html
  11. 27
      examples/javascript/js_example/templates/plain.html
  12. 16
      examples/javascript/js_example/views.py
  13. 13
      examples/javascript/setup.cfg
  14. 30
      examples/javascript/setup.py
  15. 15
      examples/javascript/tests/conftest.py
  16. 28
      examples/javascript/tests/test_js_example.py
  17. 3
      examples/tutorial/README.rst
  18. 2
      examples/tutorial/flaskr/auth.py
  19. 2
      examples/tutorial/setup.cfg
  20. 6
      examples/tutorial/setup.py
  21. 3
      tox.ini

5
docs/patterns/jquery.rst

@ -162,5 +162,6 @@ explanation of the little bit of code above:
argument. Note that we can use the `$SCRIPT_ROOT` variable here that
we set earlier.
If you don't get the whole picture, download the :gh:`sourcecode
for this example <examples/jqueryexample>`.
Check out the :gh:`example source <examples/javascript>` for a full
application demonstrating the jQuery on this page, as well as the same
thing using ``XMLHttpRequest`` and ``fetch``.

6
docs/testing.rst

@ -209,12 +209,6 @@ Running that should now give us three passing tests::
============= 3 passed in 0.23 seconds ==============
For more complex tests with headers and status codes, check out the
`MiniTwit Example`_ from the sources which contains a larger test
suite.
.. _MiniTwit Example:
https://github.com/pallets/flask/tree/master/examples/minitwit/
Other Testing Tricks
--------------------

14
examples/javascript/.gitignore vendored

@ -0,0 +1,14 @@
venv/
*.pyc
__pycache__/
instance/
.cache/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
.idea/
*.swp
*~

31
examples/javascript/LICENSE

@ -0,0 +1,31 @@
Copyright © 2010 by the Pallets team.
Some rights reserved.
Redistribution and use in source and binary forms of the software as
well as documentation, with or without modification, are permitted
provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

4
examples/javascript/MANIFEST.in

@ -0,0 +1,4 @@
include LICENSE
graft js_example/templates
graft tests
global-exclude *.pyc

49
examples/javascript/README.rst

@ -0,0 +1,49 @@
JavaScript Ajax Example
=======================
Demonstrates how to post form data and process a JSON response using
JavaScript. This allows making requests without navigating away from the
page. Demonstrates using |XMLHttpRequest|_, |fetch|_, and
|jQuery.ajax|_. See the `Flask docs`_ about jQuery and Ajax.
.. |XMLHttpRequest| replace:: ``XMLHttpRequest``
.. _XMLHttpRequest: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
.. |fetch| replace:: ``fetch``
.. _fetch: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
.. |jQuery.ajax| replace:: ``jQuery.ajax``
.. _jQuery.ajax: https://api.jquery.com/jQuery.ajax/
.. _Flask docs: http://flask.pocoo.org/docs/patterns/jquery/
Install
-------
::
python3 -m venv venv
. venv/bin/activate
pip install -e .
Run
---
::
export FLASK_APP=js_example
flask run
Open http://127.0.0.1:5000 in a browser.
Test
----
::
pip install -e '.[test]'
coverage run -m pytest
coverage report

5
examples/javascript/js_example/__init__.py

@ -0,0 +1,5 @@
from flask import Flask
app = Flask(__name__)
from js_example import views

33
examples/javascript/js_example/templates/base.html

@ -0,0 +1,33 @@
<!doctype html>
<title>JavaScript Example</title>
<link rel="stylesheet" href="https://unpkg.com/sakura.css@1.0.0/css/normalize.css">
<link rel="stylesheet" href="https://unpkg.com/sakura.css@1.0.0/css/sakura-earthly.css">
<style>
ul { margin: 0; padding: 0; display: flex; list-style-type: none; }
li > * { padding: 1em; }
li.active > a { color: #5e5e5e; border-bottom: 2px solid #4a4a4a; }
form { display: flex; }
label > input { width: 3em; }
form > * { padding-right: 1em; }
#result { font-weight: bold; }
</style>
<ul>
<li><span>Type:</span>
<li class="{% if js == 'plain' %}active{% endif %}">
<a href="{{ url_for('index', js='plain') }}">Plain</a>
<li class="{% if js == 'fetch' %}active{% endif %}">
<a href="{{ url_for('index', js='fetch') }}">Fetch</a>
<li class="{% if js == 'jquery' %}active{% endif %}">
<a href="{{ url_for('index', js='jquery') }}">jQuery</a>
</ul>
<hr>
<p>{% block intro %}{% endblock %}</p>
<hr>
<form>
<label>a <input name="a"></label>
<span>+</span>
<label>b <input name="b"></label>
<input type="submit" value="Calculate">
</form>
<span>= <span id="result"></span></span>
{% block script %}{% endblock %}

35
examples/javascript/js_example/templates/fetch.html

@ -0,0 +1,35 @@
{% extends 'base.html' %}
{% block intro %}
<a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch"><code>fetch</code></a>
is the <em>new</em> plain JavaScript way to make requests. It's
supported in all modern browsers except IE, which requires a
<a href="https://github.com/github/fetch">polyfill</a>.
{% endblock %}
{% block script %}
<script src="https://unpkg.com/promise-polyfill@7.1.2/dist/polyfill.min.js"></script>
<script src="https://unpkg.com/whatwg-fetch@2.0.4/fetch.js"></script>
<script>
function addSubmit(ev) {
ev.preventDefault();
fetch('{{ url_for('add') }}', {
method: 'POST',
body: new FormData(this)
})
.then(parseJSON)
.then(addShow);
}
function parseJSON(response) {
return response.json();
}
function addShow(data) {
var span = document.getElementById('result');
span.innerText = data.result;
}
document.forms[0].addEventListener('submit', addSubmit);
</script>
{% endblock %}

27
examples/javascript/js_example/templates/jquery.html

@ -0,0 +1,27 @@
{% extends 'base.html' %}
{% block intro %}
<a href="https://jquery.com/">jQuery</a> is a popular library that
adds cross browser APIs for common tasks. However, it requires loading
an extra library.
{% endblock %}
{% block script %}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
function addSubmit(ev) {
ev.preventDefault();
$.ajax({
method: 'POST',
url: '{{ url_for('add') }}',
data: $(this).serialize()
}).done(addShow);
}
function addShow(data) {
$('#result').text(data.result);
}
$('form:first').on('submit', addSubmit);
</script>
{% endblock %}

27
examples/javascript/js_example/templates/plain.html

@ -0,0 +1,27 @@
{% extends 'base.html' %}
{% block intro %}
<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a>
is the plain JavaScript way to make requests. It's natively supported
by all browsers.
{% endblock %}
{% block script %}
<script>
function addSubmit(ev) {
ev.preventDefault();
var request = new XMLHttpRequest();
request.addEventListener('load', addShow);
request.open('POST', '{{ url_for('add') }}');
request.send(new FormData(this));
}
function addShow() {
var data = JSON.parse(this.responseText);
var span = document.getElementById('result');
span.innerText = data.result;
}
document.forms[0].addEventListener('submit', addSubmit);
</script>
{% endblock %}

16
examples/javascript/js_example/views.py

@ -0,0 +1,16 @@
from flask import jsonify, render_template, request
from js_example import app
@app.route('/', defaults={'js': 'plain'})
@app.route('/<any(plain, jquery, fetch):js>')
def index(js):
return render_template('{0}.html'.format(js), js=js)
@app.route('/add', methods=['POST'])
def add():
a = request.form.get('a', 0, type=float)
b = request.form.get('b', 0, type=float)
return jsonify(result=a + b)

13
examples/javascript/setup.cfg

@ -0,0 +1,13 @@
[metadata]
license_file = LICENSE
[bdist_wheel]
universal = True
[tool:pytest]
testpaths = tests
[coverage:run]
branch = True
source =
js_example

30
examples/javascript/setup.py

@ -0,0 +1,30 @@
import io
from setuptools import find_packages, setup
with io.open('README.rst', 'rt', encoding='utf8') as f:
readme = f.read()
setup(
name='js_example',
version='1.0.0',
url='http://flask.pocoo.org/docs/patterns/jquery/',
license='BSD',
maintainer='Pallets team',
maintainer_email='contact@palletsprojects.com',
description='Demonstrates making Ajax requests to Flask.',
long_description=readme,
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=[
'flask',
],
extras_require={
'test': [
'pytest',
'coverage',
'blinker',
],
},
)

15
examples/javascript/tests/conftest.py

@ -0,0 +1,15 @@
import pytest
from js_example import app
@pytest.fixture(name='app')
def fixture_app():
app.testing = True
yield app
app.testing = False
@pytest.fixture
def client(app):
return app.test_client()

28
examples/javascript/tests/test_js_example.py

@ -0,0 +1,28 @@
import pytest
from flask import template_rendered
@pytest.mark.parametrize(('path', 'template_name'), (
('/', 'plain.html'),
('/plain', 'plain.html'),
('/fetch', 'fetch.html'),
('/jquery', 'jquery.html'),
))
def test_index(app, client, path, template_name):
def check(sender, template, context):
assert template.name == template_name
with template_rendered.connected_to(check, app):
client.get(path)
@pytest.mark.parametrize(('a', 'b', 'result'), (
(2, 3, 5),
(2.5, 3, 5.5),
(2, None, 2),
(2, 'b', 2),
))
def test_add(client, a, b, result):
response = client.post('/add', data={'a': a, 'b': b})
assert response.get_json()['result'] == result

3
examples/tutorial/README.rst

@ -65,12 +65,11 @@ Test
::
pip install pytest
pip install '.[test]'
pytest
Run with coverage report::
pip install pytest coverage
coverage run -m pytest
coverage report
coverage html # open htmlcov/index.html in a browser

2
examples/tutorial/flaskr/auth.py

@ -56,7 +56,7 @@ def register():
elif db.execute(
'SELECT id FROM user WHERE username = ?', (username,)
).fetchone() is not None:
error = 'User {} is already registered.'.format(username)
error = 'User {0} is already registered.'.format(username)
if error is None:
# the name is available, store it in the database and go to

2
examples/tutorial/setup.cfg

@ -2,7 +2,7 @@
license_file = LICENSE
[bdist_wheel]
universal = False
universal = True
[tool:pytest]
testpaths = tests

6
examples/tutorial/setup.py

@ -20,4 +20,10 @@ setup(
install_requires=[
'flask',
],
extras_require={
'test': [
'pytest',
'coverage',
],
},
)

3
tox.ini

@ -31,7 +31,8 @@ deps =
commands =
# the examples need to be installed to test successfully
pip install -e examples/tutorial -q
pip install -q -e examples/tutorial[test]
pip install -q -e examples/javascript[test]
# pytest-cov doesn't seem to play nice with -p
coverage run -p -m pytest tests examples

Loading…
Cancel
Save