Skip to content

Commit

Permalink
Improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Mar 29, 2021
1 parent 3026ad6 commit 9910485
Showing 1 changed file with 73 additions and 7 deletions.
80 changes: 73 additions & 7 deletions examples/user_guide/Custom_Components.ipynb
Expand Up @@ -16,7 +16,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"When building custom applications and dashboards it is frequently useful to extend Panel with custom components, which are specific to a particular application. Panel provides multiple mechanisms to extend and compose diffferent components or even add entirely new components. In this user guide we will go over these approaches and compare the benefits and drawbacks.\n",
" When building custom applications and dashboards it is frequently useful to extend Panel with custom components, which are specific to a particular application. Panel provides multiple mechanisms to extend and compose diffferent components or even add entirely new components. In this user guide we will go over these approaches and compare the benefits and drawbacks.\n",
"\n",
"## Viewer components\n",
"\n",
Expand Down Expand Up @@ -90,26 +90,55 @@
"\n",
"The `ReactiveHTML` provides bi-directional syncing of arbitrary HTML attributes and DOM properties with parameters on the subclass. This kind of component must declare a few class-attributes which declare \n",
"\n",
"- `_html`: The HTML template to render declaring how to link parameters on the class to HTML attributes.\n",
"- `_template`: The HTML template to render declaring how to link parameters on the class to HTML attributes.\n",
"- `_dom_events` (optional): Optional mapping of named nodes to DOM events to add event listeners to.\n",
"- `_scripts` (optional): Optional mapping of Javascript to execute on specific parameter changes.\n",
"\n",
"### HTML templates\n",
"\n",
"A ReactiveHTML component is declared by providing an HTML template on the `_html` attribute on the class. Parameters are synced by inserting them as template variables of the form `${parameter}`, e.g.:\n",
"A ReactiveHTML component is declared by providing an HTML template on the `_template` attribute on the class. Parameters are synced by inserting them as template variables of the form `${parameter}`, e.g.:\n",
"\n",
"```html\n",
" _html = '<div class=\"${div_class}\">${children}</div>'\n",
" _template = '<div class=\"${div_class}\">${children}</div>'\n",
"```\n",
"\n",
"will interpolate the div_class parameter on the `class` attribute of the HTML element. In addition to providing attributes we can also provide children to an HTML tag. Any child parameter will be treated as other Panel components to render into the containing HTML. This makes it possible to use `ReactiveHTML` to lay out other components.\n",
"\n",
"The HTML templates also support [Jinja2](https://jinja.palletsprojects.com/en/2.11.x/) syntax to template parameter variables and template child objs. The Jinja2 templating engine is automatically given a few context variables:\n",
"\n",
"- `param`: The param namespace object allows templating parameter names, labels, docstrings and other attributes.\n",
"- `__doc__`: The class docstring\n",
"\n",
"\n",
"#### Children\n",
"\n",
"In order to template other parameters as child objects there are a few options. By default all parameters referenced using `${child}` syntax are treated as if they were Panel components, e.g.:\n",
"\n",
"```html\n",
"<div id=\"div\">${parameter}</div>\n",
"```\n",
"\n",
"will render the contents of the `parameter` as a Panel object. If you want to render it as a literal string instead you can use the regular Jinja templating syntax instead, i.e. `{{ parameter }}` or you can use the `_child_config` to declare you want to treat `parameter` as a literal:\n",
"\n",
"```python\n",
"_child_config = {'parameter': 'literal'}\n",
"```\n",
"\n",
"If the parameter is a list each item in the list will be inserted in sequence unless declared otherwise. However if you want to wrap each child in some custom HTML you will have to use Jinja2 loop syntax to number the `id` attribute of the child tags and provide an index into the list parameter value: \n",
"\n",
"```html\n",
"<select>\n",
"{% for obj in parameter %}\n",
"<option id=\"option-{{ loop.index0 }}\">${options[{{ loop.index0 }}]}</option>\n",
"{% endfor %}\n",
"```\n",
"\n",
"### DOM Events\n",
"\n",
"In certain cases it is necessary to explicitly declare event listeners on the DOM node to ensure that changes in their properties are synced when an event is fired. To make this possible the HTML element in question must be given a unique id, e.g.:\n",
"\n",
"```html\n",
" _html = '<input id=\"input\"></input>'\n",
" _template = '<input id=\"input\"></input>'\n",
"```\n",
"\n",
"Now we can use this name to declare set of `_dom_events` to subscribe to. The following will subscribe to change DOM events on the input element:\n",
Expand Down Expand Up @@ -161,6 +190,8 @@
"source": [
"### Example\n",
"\n",
"#### Callbacks\n",
"\n",
"To see all of this in action we declare a `Slideshow` component which subscribes to `click` events on an `<img>` element and advances the image `index` on each click:"
]
},
Expand All @@ -176,7 +207,7 @@
" \n",
" index = param.Integer(default=0)\n",
" \n",
" _html = '<img id=\"img\" src=\"https://picsum.photos/800/300?image=${index}\"></img>'\n",
" _template = '<img id=\"img\" src=\"https://picsum.photos/800/300?image=${index}\"></img>'\n",
"\n",
" _scripts = {\n",
" 'index': ['console.log(data.index, img)']\n",
Expand All @@ -199,6 +230,41 @@
"As we can see this approach lets us quickly build custom HTML components with complex interactivity."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Child templates\n",
"\n",
"If we want to provide a template for the children of an HTML node we have to use Jinja2 to loop over the parameter and use the `{{ loop.index0 }}` variable to enumerate the child `id`s and index into the options:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Select(ReactiveHTML):\n",
"\n",
" options = param.List(doc=\"Options to choose from.\")\n",
" \n",
" value = param.String(doc=\"Current selected option\")\n",
" \n",
" _template = \"\"\"\n",
" <select id=\"select\" value=\"${value}\">\n",
" {% for obj in options %}\n",
" <option id=\"option-{{ loop.index0 }}\">${options[{{ loop.index0 }}]}</option>\n",
" {% endfor %}\n",
" </select>\n",
" \"\"\"\n",
" \n",
" _dom_events = {'select': ['change']}\n",
" \n",
"select = Select(options=['A', 'B', 'C'])\n",
"select"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand All @@ -225,7 +291,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.2"
"version": "3.8.8"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
Expand Down

0 comments on commit 9910485

Please sign in to comment.