Quick Start¶
pip install flask-socketio-lit-html
Example: Todo App¶
Define the todo component in jinja html template
{% extends "webcomponent_base.js" %}
{% block render %}
<input type="checkbox">${ this.todo }
{% endblock %}
{% block form %}
<form onsubmit="return false;">
<input type="text" id="todo" value="task">
<button id="submit-button" @click="${ this.add_event }">Add</button>
</form>
{% endblock %}
Create Flask application, configure your element and run it
class Todo(db.Model):
"""Todo webcomponent model"""
todo = db.Column(db.String(80))
class TodoApp(FlaskWelApp):
def __init__(self):
super(TodoApp, self).__init__(__name__)
# Register <todo-item> webcomponent to use /todo/ endpoint blueprint and custom render from todo.html jinja template
self.register_blueprint(Todo.configure_blueprint())
# TodoApp main page
self.add_url_rule('/', "TodoApp", lambda : render_template('todoapp.html'))
TodoApp().runApp()
Keep control of your dependencies
<script src="{{url_for('todo-item.static', filename='socketio-4.1.2.js')}}"></script>
<script src="{{url_for('todo-item.static', filename='element.js')}}"></script>
<script type="module" src="{{url_for('todo-item.webcomponent')}}"></script>
Full example at https://github.com/playerla/flask-wel-todoapp/ and project demo at https://github.com/playerla/flask-socketio-lit-html/blob/master/app.py
How it works¶
The model of the component - the Python class - is used to auto generated all the stuff when configure it with webcomponent_base.IndexModel.configure_blueprint()
.
The next html tags are then available:
<componentname> : The component html tag to use in .html
<ul-componentname> : A dynamic list of all the components
<form-componentname> : A Form to add new component or modify one
Generate a Rest API¶
Register the component blueprint which contains the next JSON endpoints:
GET /componentname : The component implementation - a static javascript module. You can get it via url_for(‘componentname.webcomponent’)
GET /componentname/all : The list of all components indexes in database
GET /componentname/<int:index> : The component with the primary key index
DELETE /componentname/<int:index> : The component with the primary key index
POST /componentname : The JSON new user or the user to modify if index key is set
GET /componentname/dump : The full dump of the database. Performance warning: use once and only if you planned to go offline.
You can overwrite IndexModel class methods get()
, post()
, delete()
and get_all()
to implement your own API.
An external URL could also be specified to replace /componentname for these four API endpoints. See webcomponent_base.IndexModel.configure_blueprint()
Integrate lit-element in Flask jinja¶
The webcomponent inherit from lit-element, business methods have to be overwritten in the jinja template extending webcomponent_base.js. Following blocks are available :
render : the HTML view of the component
style : CSS for the component - Global CSS is ignored with shadow DOM
form : an html form which can be used to create component or modify one
style_form : CSS for the form - by default ItemForm inerit the first style block
Update html on server side data changes¶
A socketio message is sent by the server to the component JS module after a POST request completes. Something like <class ‘__main__.User’>update: name is cls+’update’ where cls is your python component class. The message is the new or updated index, then the component updates itself with a GET call.
Cache and update strategy¶
Item._get()
read cache before any network request. If the key webcomponent-item.index matches then it is used.
GET /componentname/<int:index> and POST /componentname/<int:index> update the local sessionStorage cache on fetch success.
You could populate sessionStorage with GET /componentname/dump before loading your webcomponent.js, to write an offline application.