##// END OF EJS Templates
Add the unlink method to javascript links to maintain compatibility with traitlet links
Jason Grout -
Show More
@@ -1,54 +1,61 b''
1 1 """Link and DirectionalLink classes.
2 2
3 Represents a button in the frontend using a widget. Allows user to listen for
4 click events on the button and trigger backend code when the clicks are fired.
3 Propagate changes between widgets on the javascript side
5 4 """
6 5 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2014, the IPython Development Team.
8 7 #
9 8 # Distributed under the terms of the Modified BSD License.
10 9 #
11 10 # The full license is in the file COPYING.txt, distributed with this software.
12 11 #-----------------------------------------------------------------------------
13 12
14 13 #-----------------------------------------------------------------------------
15 14 # Imports
16 15 #-----------------------------------------------------------------------------
17 16 from .widget import Widget
18 17 from IPython.utils.traitlets import Unicode, Tuple, Any
19 18
20 19 #-----------------------------------------------------------------------------
21 20 # Classes
22 21 #-----------------------------------------------------------------------------
23 22
24 23
25 24 class Link(Widget):
26 25 """Link Widget"""
27 26 _model_name = Unicode('LinkModel', sync=True)
28 27 widgets = Tuple(sync=True, allow_none=False)
29 28
30 29 def __init__(self, widgets=(), **kwargs):
31 30 kwargs['widgets'] = widgets
32 31 super(Link, self).__init__(**kwargs)
33 32
33 # for compatibility with traitlet links
34 def unlink(self):
35 self.close()
36
34 37
35 38 def link(*args):
36 39 return Link(widgets=args)
37 40
38 41
39 42 class DirectionalLink(Widget):
40 43 """Directional Link Widget"""
41 44 _model_name = Unicode('DirectionalLinkModel', sync=True)
42 45 targets = Any(sync=True)
43 46 source = Tuple(sync=True)
44 47
45 48 # Does not quite behave like other widgets but reproduces
46 49 # the behavior of IPython.utils.traitlets.directional_link
47 50 def __init__(self, source, targets=(), **kwargs):
48 51 kwargs['source'] = source
49 52 kwargs['targets'] = targets
50 53 super(DirectionalLink, self).__init__(**kwargs)
51 54
55 # for compatibility with traitlet links
56 def unlink(self):
57 self.close()
58
52 59
53 60 def dlink(source, *targets):
54 61 return DirectionalLink(source, targets)
@@ -1,376 +1,383 b''
1 1 {
2 2 "cells": [
3 3 {
4 4 "cell_type": "markdown",
5 5 "metadata": {},
6 6 "source": [
7 7 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
8 8 ]
9 9 },
10 10 {
11 11 "cell_type": "markdown",
12 12 "metadata": {
13 13 "slideshow": {
14 14 "slide_type": "slide"
15 15 }
16 16 },
17 17 "source": [
18 18 "# Widget Events"
19 19 ]
20 20 },
21 21 {
22 22 "cell_type": "markdown",
23 23 "metadata": {},
24 24 "source": [
25 25 "## Special events"
26 26 ]
27 27 },
28 28 {
29 29 "cell_type": "code",
30 30 "execution_count": null,
31 31 "metadata": {
32 32 "collapsed": false
33 33 },
34 34 "outputs": [],
35 35 "source": [
36 36 "from __future__ import print_function"
37 37 ]
38 38 },
39 39 {
40 40 "cell_type": "markdown",
41 41 "metadata": {},
42 42 "source": [
43 43 "The `Button` is not used to represent a data type. Instead the button widget is used to **handle mouse clicks**. The **`on_click` method** of the `Button` can be used to register function to be called when the button is clicked. The doc string of the `on_click` can be seen below."
44 44 ]
45 45 },
46 46 {
47 47 "cell_type": "code",
48 48 "execution_count": null,
49 49 "metadata": {
50 50 "collapsed": false
51 51 },
52 52 "outputs": [],
53 53 "source": [
54 54 "from IPython.html import widgets\n",
55 55 "print(widgets.Button.on_click.__doc__)"
56 56 ]
57 57 },
58 58 {
59 59 "cell_type": "markdown",
60 60 "metadata": {
61 61 "slideshow": {
62 62 "slide_type": "slide"
63 63 }
64 64 },
65 65 "source": [
66 66 "### Example"
67 67 ]
68 68 },
69 69 {
70 70 "cell_type": "markdown",
71 71 "metadata": {},
72 72 "source": [
73 73 "Since button clicks are **stateless**, they are **transmitted from the front-end to the back-end using custom messages**. By using the `on_click` method, a button that prints a message when it has been clicked is shown below."
74 74 ]
75 75 },
76 76 {
77 77 "cell_type": "code",
78 78 "execution_count": null,
79 79 "metadata": {
80 80 "collapsed": false
81 81 },
82 82 "outputs": [],
83 83 "source": [
84 84 "from IPython.display import display\n",
85 85 "button = widgets.Button(description=\"Click Me!\")\n",
86 86 "display(button)\n",
87 87 "\n",
88 88 "def on_button_clicked(b):\n",
89 89 " print(\"Button clicked.\")\n",
90 90 "\n",
91 91 "button.on_click(on_button_clicked)"
92 92 ]
93 93 },
94 94 {
95 95 "cell_type": "markdown",
96 96 "metadata": {
97 97 "slideshow": {
98 98 "slide_type": "slide"
99 99 }
100 100 },
101 101 "source": [
102 102 "### on_sumbit"
103 103 ]
104 104 },
105 105 {
106 106 "cell_type": "markdown",
107 107 "metadata": {},
108 108 "source": [
109 109 "The **`Text`** also has a special **`on_submit` event**. The `on_submit` event **fires when the user hits return**."
110 110 ]
111 111 },
112 112 {
113 113 "cell_type": "code",
114 114 "execution_count": null,
115 115 "metadata": {
116 116 "collapsed": false
117 117 },
118 118 "outputs": [],
119 119 "source": [
120 120 "text = widgets.Text()\n",
121 121 "display(text)\n",
122 122 "\n",
123 123 "def handle_submit(sender):\n",
124 124 " print(text.value)\n",
125 125 "\n",
126 126 "text.on_submit(handle_submit)"
127 127 ]
128 128 },
129 129 {
130 130 "cell_type": "markdown",
131 131 "metadata": {
132 132 "slideshow": {
133 133 "slide_type": "slide"
134 134 }
135 135 },
136 136 "source": [
137 137 "## Traitlet events"
138 138 ]
139 139 },
140 140 {
141 141 "cell_type": "markdown",
142 142 "metadata": {},
143 143 "source": [
144 144 "**Widget properties are IPython traitlets** and **traitlets are eventful**. To handle changes, the **`on_trait_change` method** of the widget can be used to **register a callback**. The doc string for `on_trait_change` can be seen below."
145 145 ]
146 146 },
147 147 {
148 148 "cell_type": "code",
149 149 "execution_count": null,
150 150 "metadata": {
151 151 "collapsed": false
152 152 },
153 153 "outputs": [],
154 154 "source": [
155 155 "print(widgets.Widget.on_trait_change.__doc__)"
156 156 ]
157 157 },
158 158 {
159 159 "cell_type": "markdown",
160 160 "metadata": {
161 161 "slideshow": {
162 162 "slide_type": "slide"
163 163 }
164 164 },
165 165 "source": [
166 166 "### Signatures"
167 167 ]
168 168 },
169 169 {
170 170 "cell_type": "markdown",
171 171 "metadata": {},
172 172 "source": [
173 173 "Mentioned in the doc string, the callback registered can have **4 possible signatures**:\n",
174 174 "\n",
175 175 "- callback()\n",
176 176 "- callback(trait_name)\n",
177 177 "- callback(trait_name, new_value)\n",
178 178 "- callback(trait_name, old_value, new_value)\n",
179 179 "\n",
180 180 "Using this method, an example of how to output an `IntSlider`'s value as it is changed can be seen below."
181 181 ]
182 182 },
183 183 {
184 184 "cell_type": "code",
185 185 "execution_count": null,
186 186 "metadata": {
187 187 "collapsed": false
188 188 },
189 189 "outputs": [],
190 190 "source": [
191 191 "int_range = widgets.IntSlider()\n",
192 192 "display(int_range)\n",
193 193 "\n",
194 194 "def on_value_change(name, value):\n",
195 195 " print(value)\n",
196 196 "\n",
197 197 "int_range.on_trait_change(on_value_change, 'value')"
198 198 ]
199 199 },
200 200 {
201 201 "cell_type": "markdown",
202 202 "metadata": {},
203 203 "source": [
204 204 "# Linking Widgets"
205 205 ]
206 206 },
207 207 {
208 208 "cell_type": "markdown",
209 209 "metadata": {},
210 210 "source": [
211 211 "Often, you may want to simply link widget attributes together. Synchronization of attributes can be done in a simpler way than by using bare traitlets events. \n",
212 212 "\n",
213 213 "The first method is to use the `link` and `directional_link` functions from the `traitlets` module. "
214 214 ]
215 215 },
216 216 {
217 217 "cell_type": "markdown",
218 218 "metadata": {},
219 219 "source": [
220 220 "## Linking traitlets attributes from the server side"
221 221 ]
222 222 },
223 223 {
224 224 "cell_type": "code",
225 225 "execution_count": null,
226 226 "metadata": {
227 227 "collapsed": false
228 228 },
229 229 "outputs": [],
230 230 "source": [
231 231 "from IPython.utils import traitlets"
232 232 ]
233 233 },
234 234 {
235 235 "cell_type": "code",
236 236 "execution_count": null,
237 237 "metadata": {
238 238 "collapsed": false
239 239 },
240 240 "outputs": [],
241 241 "source": [
242 242 "caption = widgets.Latex(value = 'The values of slider1, slider2 and slider3 are synchronized')\n",
243 243 "sliders1, slider2, slider3 = widgets.IntSlider(description='Slider 1'),\\\n",
244 244 " widgets.IntSlider(description='Slider 2'),\\\n",
245 245 " widgets.IntSlider(description='Slider 3')\n",
246 246 "l = traitlets.link((sliders1, 'value'), (slider2, 'value'), (slider3, 'value'))\n",
247 247 "display(caption, sliders1, slider2, slider3)"
248 248 ]
249 249 },
250 250 {
251 251 "cell_type": "code",
252 252 "execution_count": null,
253 253 "metadata": {
254 254 "collapsed": false
255 255 },
256 256 "outputs": [],
257 257 "source": [
258 258 "caption = widgets.Latex(value = 'Changes in source values are reflected in target1 and target2')\n",
259 259 "source, target1, target2 = widgets.IntSlider(description='Source'),\\\n",
260 260 " widgets.IntSlider(description='Target 1'),\\\n",
261 261 " widgets.IntSlider(description='Target 2')\n",
262 262 "traitlets.dlink((source, 'value'), (target1, 'value'), (target2, 'value'))\n",
263 263 "display(caption, source, target1, target2)"
264 264 ]
265 265 },
266 266 {
267 267 "cell_type": "markdown",
268 268 "metadata": {},
269 269 "source": [
270 270 "Function `traitlets.link` returns a `Link` object. The link can be broken by calling the `unlink` method."
271 271 ]
272 272 },
273 273 {
274 274 "cell_type": "code",
275 275 "execution_count": null,
276 276 "metadata": {
277 277 "collapsed": false
278 278 },
279 279 "outputs": [],
280 280 "source": [
281 281 "# l.unlink()"
282 282 ]
283 283 },
284 284 {
285 285 "cell_type": "markdown",
286 286 "metadata": {},
287 287 "source": [
288 288 "## Linking widgets attributes from the client side"
289 289 ]
290 290 },
291 291 {
292 292 "cell_type": "markdown",
293 293 "metadata": {},
294 294 "source": [
295 295 "When synchronizing traitlets attributes, you may experience a lag because of the latency dues to the rountrip to the server side. You can also directly link widgets attributes, either in a unidirectional or a bidirectional fashion using the link widgets. "
296 296 ]
297 297 },
298 298 {
299 299 "cell_type": "code",
300 300 "execution_count": null,
301 301 "metadata": {
302 302 "collapsed": false
303 303 },
304 304 "outputs": [],
305 305 "source": [
306 306 "caption = widgets.Latex(value = 'The values of range1, range2 and range3 are synchronized')\n",
307 307 "range1, range2, range3 = widgets.IntSlider(description='Range 1'),\\\n",
308 308 " widgets.IntSlider(description='Range 2'),\\\n",
309 309 " widgets.IntSlider(description='Range 3')\n",
310 310 "l = widgets.link((range1, 'value'), (range2, 'value'), (range3, 'value'))\n",
311 311 "display(caption, range1, range2, range3)"
312 312 ]
313 313 },
314 314 {
315 315 "cell_type": "code",
316 316 "execution_count": null,
317 317 "metadata": {
318 318 "collapsed": false
319 319 },
320 320 "outputs": [],
321 321 "source": [
322 322 "caption = widgets.Latex(value = 'Changes in source_range values are reflected in target_range1 and target_range2')\n",
323 323 "source_range, target_range1, target_range2 = widgets.IntSlider(description='Source range'),\\\n",
324 324 " widgets.IntSlider(description='Target range 1'),\\\n",
325 325 " widgets.IntSlider(description='Target range 2')\n",
326 326 "widgets.dlink((source_range, 'value'), (target_range1, 'value'), (target_range2, 'value'))\n",
327 327 "display(caption, source_range, target_range1, target_range2)"
328 328 ]
329 329 },
330 330 {
331 331 "cell_type": "markdown",
332 332 "metadata": {},
333 333 "source": [
334 "Function `widgets.link` returns a `Link` widget. The link can be broken by calling the `close` method."
334 "Function `widgets.link` returns a `Link` widget. The link can be broken by calling the `unlink` method."
335 335 ]
336 336 },
337 337 {
338 338 "cell_type": "code",
339 339 "execution_count": null,
340 340 "metadata": {
341 341 "collapsed": false
342 342 },
343 343 "outputs": [],
344 344 "source": [
345 "# l.close()"
345 "# l.unlink()"
346 346 ]
347 347 },
348 348 {
349 349 "cell_type": "markdown",
350 350 "metadata": {},
351 351 "source": [
352 352 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
353 353 ]
354 354 }
355 355 ],
356 356 "metadata": {
357 357 "cell_tags": [
358 358 [
359 359 "<None>",
360 360 null
361 361 ]
362 362 ],
363 363 "kernelspec": {
364 "codemirror_mode": {
365 "name": "python",
366 "version": 2
367 },
368 364 "display_name": "Python 2",
369 "language": "python",
370 365 "name": "python2"
371 366 },
372 "signature": "sha256:05a3e92089b37f68e3134587ffef6ef73830e5f8b3c515ba24640d7c803820c3"
367 "language_info": {
368 "codemirror_mode": {
369 "name": "ipython",
370 "version": 2
371 },
372 "file_extension": ".py",
373 "mimetype": "text/x-python",
374 "name": "python",
375 "nbconvert_exporter": "python",
376 "pygments_lexer": "ipython2",
377 "version": "2.7.8"
378 },
379 "signature": "sha256:b6eadc174d0d9c1907518d9f37760eb3dca3aec0ef1f3746e6f0537a36e99919"
373 380 },
374 381 "nbformat": 4,
375 382 "nbformat_minor": 0
376 383 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now