Skip to content

Instantly share code, notes, and snippets.

@lbustelo
Last active January 19, 2016 17:28
Show Gist options
  • Save lbustelo/30fd748973be52edcb71 to your computer and use it in GitHub Desktop.
Save lbustelo/30fd748973be52edcb71 to your computer and use it in GitHub Desktop.
Tutorial Notebook for jupyter-declarativewidgets
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simple Todo App\n",
"This tutorial takes you through a step by step look at how to put together a very basic Todo application using [`jupyter-declarativewidgets`](https://github.com/jupyter-incubator/declarativewidgets)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Step 1. The Python Code\n",
"\n",
"We are going to keep it simple to start with. The Todo `list` will be a Python variable. We will define some simple functions to `add` and `remove` Todo items."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"todo = []\n",
"\n",
"def addTodo(title, date=None):\n",
" global todo\n",
" todo = todo + [(title, date)]\n",
"\n",
"def removeTodo(idx:int):\n",
" global todo\n",
" del todo[idx]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets test the code"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"addTodo('a')\n",
"addTodo('b')\n",
"addTodo('c')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"todo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"removeTodo(1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"todo"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Step 2. Lets visualize the list\n",
"This is where we can use a simple `HTML` template using [Polymer](https://www.polymer-project.org/1.0/) to render the list. The `template` is an `urth-core-bind`, one of the `declarativewidgets` elements, which enhances data binding capabilities in several ways that you will see through the course of this tutorial. In the template we are using the binding variable `{{todo}}` to build the UI and a [dom-repeat](https://www.polymer-project.org/1.0/docs/devguide/templates.html#dom-repeat) `template` to build a simple `HTML` list."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%HTML\n",
"<template is=\"urth-core-bind\">\n",
" <ul>\n",
" <template is=\"dom-repeat\" items=\"{{todo}}\">\n",
" <li>{{item.0}}</li>\n",
" </template>\n",
" </ul>\n",
"</template>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But where are the Todo items?| Well... we need to send the data to the browser so it can be rendered. This is done with the following `Python` code."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from urth.widgets.widget_channels import channel\n",
"channel().set(\"todo\", todo)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Noticed what happened? Now the items of the list are rendered in our HTML template above."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Step 3. Lets add to the list\n",
"Now we need some UI to add new items to the list. A simple `HTML` form will do, but we need to connect the form submition to a call to the `addTodo` `Python` function. This is done by using the `urth-core-function` element. This element bridges the `HTML` markup and the `Python` code. \n",
"\n",
"The basics are:\n",
"* 'ref' is the name of the function in `Python` (i.e. `addTodo`)\n",
"* Parameters for the function are expose in the form `arg-param_name`.\n",
"* use `{{}}` template variables to bind values from the form to the function.\n",
"* calling the `invoke` method of the `urth-core-function` invokes the `Python` function.\n",
"\n",
"More details on all elements [here](http://jupyter-incubator.github.io/declarativewidgets/docs.html)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%HTML\n",
"<template is=\"urth-core-bind\">\n",
" <urth-core-function id=\"addTodo\" ref=\"addTodo\" arg-title=\"{{title}}\" arg-date=\"{{dueDate}}\"></urth-core-function> \n",
" <br/>Add New Item\n",
" <form onSubmit=\"return false;\">\n",
" title: <input id=\"titleIn\" type=\"text\" value=\"{{title::change}}\"></input> \n",
" date: <input id=\"dateIn\" type=\"text\" value=\"{{dueDate::change}}\"></input> \n",
" <button onClick=\"addTodo.invoke(); titleIn.value=''; dateIn.value=''\">Add</button>\n",
" </form>\n",
"</template>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Try adding something to the Todo list. The cell below show that the items are added."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"todo"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that the UI we created above it is not getting updated. The browser has no clue that the `Python` `todo` variable has changes. We need to modify the `addTodo` function to notify that the `todo` list has changed. That is done using `channel().set(\"todo\", todo)`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def addTodo(title, date=None):\n",
" global todo\n",
" todo = todo + [(title, date)]\n",
" channel().set(\"todo\", todo)\n",
" \n",
"# Only here to refresh the UI \n",
"channel().set(\"todo\", todo)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now try adding another item and notice that the list ui is not getting updated."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Step 3. Lets remove from the list\n",
"We will modify our original UI to add a remove button. Now each item will show its content and a button used to remove the item from the Todo list."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%HTML\n",
"<template is=\"urth-core-bind\">\n",
" <ul>\n",
" <template is=\"dom-repeat\" items=\"{{todo}}\">\n",
" <li>\n",
" <urth-core-function ref=\"removeTodo\" arg-idx=\"[[index]]\" onClick=\"this.invoke()\">\n",
" <button>x</button> \n",
" </urth-core-function> \n",
" {{item.0}}\n",
" </li>\n",
" </template>\n",
" </ul>\n",
"</template>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that clicking on the button is not removing the items from the UI. As with `addTod`, we need to modify `removeTodo` to notify that the `todo` list has chanted."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def removeTodo(idx:int):\n",
" global todo\n",
" del todo[idx]\n",
" channel().set(\"todo\", todo)\n",
" \n",
"# Only here to refresh the UI \n",
"channel().set(\"todo\", todo)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Try removing an item now. You should see the list getting updated."
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"#### Step 4. Lets make it look a bit nicer\n",
"With `declarativewidgets` we can import new elements to make our UI look nicer. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%HTML\n",
"<link rel='import' href='urth_components/paper-card/paper-card.html' \n",
" is='urth-core-import' package='PolymerElements/paper-card'>\n",
"<link rel='import' href='urth_components/paper-item/paper-item.html' \n",
" is='urth-core-import' package='PolymerElements/paper-item'>\n",
"<link rel='import' href='urth_components/paper-input/paper-input.html' \n",
" is='urth-core-import' package='PolymerElements/paper-input'>\n",
"<link rel='import' href='urth_components/paper-icon-button/paper-icon-button.html' \n",
" is='urth-core-import' package='PolymerElements/paper-icon-button'>\n",
"<link rel='import' href='urth_components/paper-button/paper-button.html' \n",
" is='urth-core-import' package='PolymerElements/paper-button'>\n",
"<link rel='import' href='urth_components/iron-icons/iron-icons.html' \n",
" is='urth-core-import' package='PolymerElements/iron-icons'>\n",
"<link rel='import' href='urth_components/iron-collapse/iron-collapse.html' \n",
" is='urth-core-import' package='PolymerElements/iron-collapse'>\n",
"<link rel='import' href='urth_components/paper-date-picker/paper-date-picker.html' \n",
" is='urth-core-import' package='bendavis78/paper-date-picker'>\n",
"\n",
"<style is=\"custom-style\">\n",
" paper-card {\n",
" width: 100%;\n",
" }\n",
" \n",
" .list {\n",
" @apply(--layout-vertical);\n",
" }\n",
"</style> \n",
"\n",
"<template is=\"urth-core-bind\"> \n",
" <paper-card heading=\"Todo List\" style=\"width: 100%\">\n",
" <div class=\"card-content\">\n",
" <div class=\"list\" role=\"listbox\">\n",
" <template is=\"dom-repeat\" items=\"{{todo}}\">\n",
" <paper-item>\n",
" <urth-core-function ref=\"removeTodo\" arg-idx=\"[[index]]\" onClick=\"this.invoke()\" delay=\"250\">\n",
" <paper-icon-button icon=\"clear\">X</paper-icon-button>\n",
" </urth-core-function> \n",
" <span>{{item.0}}</span>\n",
" <template is=\"dom-if\" if=\"{{item.1}}\">\n",
" <span style=\"color: gray\">&nbsp;({{item.1}})</span>\n",
" </template>\n",
" </paper-item>\n",
" </template>\n",
" <div>\n",
" </div>\n",
" <div class=\"card-actions\">\n",
" <paper-button onClick=\"newItemForm.toggle(); titleIn2.value=''\">New Item</paper-button>\n",
" <iron-collapse id=\"newItemForm\">\n",
" <div class=\"content\">\n",
" <paper-input id=\"titleIn2\" label=\"Title\" value=\"{{title}}\"></paper-input>\n",
" <label style=\"display: block; color: gray; border-bottom: 1px solid #737373; margin-top: 2px;\">Due Date</label>\n",
" <div>\n",
" <paper-date-picker date=\"{{dueDate}}\"></paper-date-picker>\n",
" </div>\n",
" <div style=\"text-align: right; margin: 10px 20px\">\n",
" <urth-core-function ref=\"addTodo\" arg-title=\"{{title}}\" arg-date=\"{{dueDate}}\" onClick=\"this.invoke();\" delay=\"250\">\n",
" <paper-button raised onClick=\"newItemForm.toggle()\"><iron-icon icon=\"add\"></iron-icon>Add Item</paper-button>\n",
" </urth-core-function>\n",
" </div>\n",
" </div>\n",
" </iron-collapse>\n",
" </div>\n",
" </paper-card> \n",
"</template>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment