|
500 | 500 | "cell_type": "markdown",
|
501 | 501 | "metadata": {},
|
502 | 502 | "source": [
|
503 |
| - "We want to be able to avoid user to write an invalid email address, so we need a validator using traitlets." |
504 |
| - ] |
505 |
| - }, |
506 |
| - { |
507 |
| - "cell_type": "code", |
508 |
| - "execution_count": null, |
509 |
| - "metadata": {}, |
510 |
| - "outputs": [], |
511 |
| - "source": [ |
| 503 | + "We want to be able to avoid user to write an invalid email address, so we need a validator using traitlets.\n", |
| 504 | + "\n", |
| 505 | + "```python\n", |
512 | 506 | "from traitlets import Unicode, Bool, validate, TraitError\n",
|
513 | 507 | "from ipywidgets import DOMWidget, ValueWidget, register\n",
|
514 | 508 | "\n",
|
| 509 | + "from ._frontend import module_name, module_version\n", |
| 510 | + "\n", |
515 | 511 | "\n",
|
516 | 512 | "@register\n",
|
517 | 513 | "class Email(DOMWidget, ValueWidget):\n",
|
| 514 | + " _model_name = Unicode('EmailModel').tag(sync=True)\n", |
| 515 | + " _model_module = Unicode(module_name).tag(sync=True)\n", |
| 516 | + " _model_module_version = Unicode(module_version).tag(sync=True)\n", |
| 517 | + "\n", |
518 | 518 | " _view_name = Unicode('EmailView').tag(sync=True)\n",
|
519 |
| - " _view_module = Unicode('email_widget').tag(sync=True)\n", |
520 |
| - " _view_module_version = Unicode('0.1.0').tag(sync=True)\n", |
| 519 | + " _view_module = Unicode(module_name).tag(sync=True)\n", |
| 520 | + " _view_module_version = Unicode(module_version).tag(sync=True)\n", |
521 | 521 | "\n",
|
522 |
| - " # Attributes\n", |
523 |
| - " value = Unicode('[email protected]', help=\"The email value.\").tag(sync=True)\n", |
| 522 | + " value = Unicode('[email protected]').tag(sync=True)\n", |
524 | 523 | " disabled = Bool(False, help=\"Enable or disable user changes.\").tag(sync=True)\n",
|
525 | 524 | "\n",
|
526 | 525 | " # Basic validator for the email value\n",
|
|
530 | 529 | " raise TraitError('Invalid email value: it must contain an \"@\" character')\n",
|
531 | 530 | " if proposal['value'].count(\".\") == 0:\n",
|
532 | 531 | " raise TraitError('Invalid email value: it must contain at least one \".\" character')\n",
|
533 |
| - " return proposal['value']" |
| 532 | + " return proposal['value']\n", |
| 533 | + "```" |
534 | 534 | ]
|
535 | 535 | },
|
536 | 536 | {
|
|
566 | 566 | "cell_type": "markdown",
|
567 | 567 | "metadata": {},
|
568 | 568 | "source": [
|
569 |
| - "By replacing the string literal with a call to `model.get`, the view will now display the value of the back end upon display. However, it will not update itself to a new value when the value changes." |
570 |
| - ] |
571 |
| - }, |
572 |
| - { |
573 |
| - "cell_type": "code", |
574 |
| - "execution_count": null, |
575 |
| - "metadata": {}, |
576 |
| - "outputs": [], |
577 |
| - "source": [ |
578 |
| - "%%javascript\n", |
579 |
| - "require.undef('email_widget');\n", |
580 |
| - "\n", |
581 |
| - "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n", |
582 |
| - " \n", |
583 |
| - " var EmailView = widgets.DOMWidgetView.extend({\n", |
584 |
| - "\n", |
585 |
| - " // Render the view.\n", |
586 |
| - " render: function() { \n", |
587 |
| - " this.email_input = document.createElement('input');\n", |
588 |
| - " this.email_input.type = 'email';\n", |
589 |
| - " this.email_input.value = this.model.get('value');\n", |
590 |
| - " this.email_input.disabled = this.model.get('disabled');\n", |
| 569 | + "By replacing the string literal with a call to `model.get`, the view will now display the value of the back end upon display. However, it will not update itself to a new value when the value changes.\n", |
591 | 570 | "\n",
|
592 |
| - " this.el.appendChild(this.email_input);\n", |
593 |
| - " },\n", |
594 |
| - " });\n", |
| 571 | + "```typescript\n", |
| 572 | + "export\n", |
| 573 | + "class EmailView extends DOMWidgetView {\n", |
| 574 | + " render() {\n", |
| 575 | + " this._emailInput = document.createElement('input');\n", |
| 576 | + " this._emailInput.type = 'email';\n", |
| 577 | + " this._emailInput.value = this.model.get('value');\n", |
| 578 | + " this._emailInput.disabled = this.model.get('disabled');\n", |
| 579 | + " \n", |
| 580 | + " this.el.appendChild(this._emailInput);\n", |
| 581 | + " }\n", |
595 | 582 | "\n",
|
596 |
| - " return {\n", |
597 |
| - " EmailView: EmailView\n", |
598 |
| - " };\n", |
599 |
| - "});" |
600 |
| - ] |
601 |
| - }, |
602 |
| - { |
603 |
| - "cell_type": "code", |
604 |
| - "execution_count": null, |
605 |
| - "metadata": {}, |
606 |
| - "outputs": [], |
607 |
| - "source": [ |
608 |
| - "Email(value='[email protected]', disabled=True)" |
| 583 | + " private _emailInput: HTMLInputElement;\n", |
| 584 | + "}\n", |
| 585 | + "```" |
609 | 586 | ]
|
610 | 587 | },
|
611 | 588 | {
|
|
623 | 600 | "cell_type": "markdown",
|
624 | 601 | "metadata": {},
|
625 | 602 | "source": [
|
626 |
| - "To get the view to update itself dynamically, register a function to update the view's value when the model's `value` property changes. This can be done using the `model.on` method. The `on` method takes three parameters, an event name, callback handle, and callback context. The Backbone event named `change` will fire whenever the model changes. By appending `:value` to it, you tell Backbone to only listen to the change event of the `value` property (as seen below)." |
627 |
| - ] |
628 |
| - }, |
629 |
| - { |
630 |
| - "cell_type": "code", |
631 |
| - "execution_count": null, |
632 |
| - "metadata": {}, |
633 |
| - "outputs": [], |
634 |
| - "source": [ |
635 |
| - "%%javascript\n", |
636 |
| - "require.undef('email_widget');\n", |
637 |
| - "\n", |
638 |
| - "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n", |
639 |
| - " \n", |
640 |
| - " var EmailView = widgets.DOMWidgetView.extend({\n", |
641 |
| - "\n", |
642 |
| - " // Render the view.\n", |
643 |
| - " render: function() { \n", |
644 |
| - " this.email_input = document.createElement('input');\n", |
645 |
| - " this.email_input.type = 'email';\n", |
646 |
| - " this.email_input.value = this.model.get('value');\n", |
647 |
| - " this.email_input.disabled = this.model.get('disabled');\n", |
648 |
| - "\n", |
649 |
| - " this.el.appendChild(this.email_input);\n", |
650 |
| - " \n", |
651 |
| - " // Python -> JavaScript update\n", |
652 |
| - " this.model.on('change:value', this.value_changed, this);\n", |
653 |
| - " this.model.on('change:disabled', this.disabled_changed, this);\n", |
654 |
| - " },\n", |
655 |
| - " \n", |
656 |
| - " value_changed: function() {\n", |
657 |
| - " this.email_input.value = this.model.get('value'); \n", |
658 |
| - " },\n", |
659 |
| - " \n", |
660 |
| - " disabled_changed: function() {\n", |
661 |
| - " this.email_input.disabled = this.model.get('disabled'); \n", |
662 |
| - " },\n", |
663 |
| - " });\n", |
664 |
| - "\n", |
665 |
| - " return {\n", |
666 |
| - " EmailView: EmailView\n", |
667 |
| - " };\n", |
668 |
| - "});" |
| 603 | + "To get the view to update itself dynamically, register a function to update the view's value when the model's `value` property changes. This can be done using the `model.on` method. The `on` method takes three parameters, an event name, callback handle, and callback context. The Backbone event named `change` will fire whenever the model changes. By appending `:value` to it, you tell Backbone to only listen to the change event of the `value` property (as seen below).\n", |
| 604 | + "\n", |
| 605 | + "```typescript\n", |
| 606 | + "export\n", |
| 607 | + "class EmailView extends DOMWidgetView {\n", |
| 608 | + " render() {\n", |
| 609 | + " this._emailInput = document.createElement('input');\n", |
| 610 | + " this._emailInput.type = 'email';\n", |
| 611 | + " this._emailInput.value = this.model.get('value');\n", |
| 612 | + " this._emailInput.disabled = this.model.get('disabled');\n", |
| 613 | + "\n", |
| 614 | + " this.el.appendChild(this._emailInput);\n", |
| 615 | + "\n", |
| 616 | + " // Python -> JavaScript update\n", |
| 617 | + " this.model.on('change:value', this._onValueChanged, this);\n", |
| 618 | + " this.model.on('change:disabled', this._onDisabledChanged, this);\n", |
| 619 | + " }\n", |
| 620 | + "\n", |
| 621 | + " private _onValueChanged() {\n", |
| 622 | + " this._emailInput.value = this.model.get('value');\n", |
| 623 | + " }\n", |
| 624 | + "\n", |
| 625 | + " private _onDisabledChanged() {\n", |
| 626 | + " this._emailInput.disabled = this.model.get('disabled');\n", |
| 627 | + " }\n", |
| 628 | + "\n", |
| 629 | + " private _emailInput: HTMLInputElement;\n", |
| 630 | + "}\n", |
| 631 | + "```" |
669 | 632 | ]
|
670 | 633 | },
|
671 | 634 | {
|
672 | 635 | "cell_type": "markdown",
|
673 | 636 | "metadata": {},
|
674 | 637 | "source": [
|
675 |
| - "This allows us to update the value from the Python kernel to the views. Now to get the value updated from the front-end to the Python kernel (when the input is not disabled) we can do it using the `model.set` method." |
676 |
| - ] |
677 |
| - }, |
678 |
| - { |
679 |
| - "cell_type": "code", |
680 |
| - "execution_count": null, |
681 |
| - "metadata": {}, |
682 |
| - "outputs": [], |
683 |
| - "source": [ |
684 |
| - "%%javascript\n", |
685 |
| - "require.undef('email_widget');\n", |
686 |
| - "\n", |
687 |
| - "define('email_widget', [\"@jupyter-widgets/base\"], function(widgets) {\n", |
688 |
| - " \n", |
689 |
| - " var EmailView = widgets.DOMWidgetView.extend({\n", |
690 |
| - "\n", |
691 |
| - " // Render the view.\n", |
692 |
| - " render: function() { \n", |
693 |
| - " this.email_input = document.createElement('input');\n", |
694 |
| - " this.email_input.type = 'email';\n", |
695 |
| - " this.email_input.value = this.model.get('value');\n", |
696 |
| - " this.email_input.disabled = this.model.get('disabled');\n", |
697 |
| - "\n", |
698 |
| - " this.el.appendChild(this.email_input);\n", |
699 |
| - " \n", |
700 |
| - " // Python -> JavaScript update\n", |
701 |
| - " this.model.on('change:value', this.value_changed, this);\n", |
702 |
| - " this.model.on('change:disabled', this.disabled_changed, this);\n", |
703 |
| - " \n", |
704 |
| - " // JavaScript -> Python update\n", |
705 |
| - " this.email_input.onchange = this.input_changed.bind(this);\n", |
706 |
| - " },\n", |
707 |
| - " \n", |
708 |
| - " value_changed: function() {\n", |
709 |
| - " this.email_input.value = this.model.get('value'); \n", |
710 |
| - " },\n", |
711 |
| - " \n", |
712 |
| - " disabled_changed: function() {\n", |
713 |
| - " this.email_input.disabled = this.model.get('disabled'); \n", |
714 |
| - " },\n", |
715 |
| - " \n", |
716 |
| - " input_changed: function() {\n", |
717 |
| - " this.model.set('value', this.email_input.value);\n", |
718 |
| - " this.model.save_changes();\n", |
719 |
| - " },\n", |
720 |
| - " });\n", |
721 |
| - "\n", |
722 |
| - " return {\n", |
723 |
| - " EmailView: EmailView\n", |
724 |
| - " };\n", |
725 |
| - "});" |
| 638 | + "This allows us to update the value from the Python kernel to the views. Now to get the value updated from the front-end to the Python kernel (when the input is not disabled) we can do it using the `model.set` method.\n", |
| 639 | + "\n", |
| 640 | + "```typescript\n", |
| 641 | + "export\n", |
| 642 | + "class EmailView extends DOMWidgetView {\n", |
| 643 | + " render() {\n", |
| 644 | + " this._emailInput = document.createElement('input');\n", |
| 645 | + " this._emailInput.type = 'email';\n", |
| 646 | + " this._emailInput.value = this.model.get('value');\n", |
| 647 | + " this._emailInput.disabled = this.model.get('disabled');\n", |
| 648 | + "\n", |
| 649 | + " this.el.appendChild(this._emailInput);\n", |
| 650 | + "\n", |
| 651 | + " // Python -> JavaScript update\n", |
| 652 | + " this.model.on('change:value', this._onValueChanged, this);\n", |
| 653 | + " this.model.on('change:disabled', this._onDisabledChanged, this);\n", |
| 654 | + "\n", |
| 655 | + " // JavaScript -> Python update\n", |
| 656 | + " this._emailInput.onchange = this._onInputChanged.bind(this);\n", |
| 657 | + " }\n", |
| 658 | + "\n", |
| 659 | + " private _onValueChanged() {\n", |
| 660 | + " this._emailInput.value = this.model.get('value');\n", |
| 661 | + " }\n", |
| 662 | + "\n", |
| 663 | + " private _onDisabledChanged() {\n", |
| 664 | + " this._emailInput.disabled = this.model.get('disabled');\n", |
| 665 | + " }\n", |
| 666 | + "\n", |
| 667 | + " private _onInputChanged() {\n", |
| 668 | + " this.model.set('value', this._emailInput.value);\n", |
| 669 | + " this.model.save_changes();\n", |
| 670 | + " }\n", |
| 671 | + "\n", |
| 672 | + " private _emailInput: HTMLInputElement;\n", |
| 673 | + "}\n", |
| 674 | + "```" |
726 | 675 | ]
|
727 | 676 | },
|
728 | 677 | {
|
|
733 | 682 | }
|
734 | 683 | },
|
735 | 684 | "source": [
|
736 |
| - "## Test" |
737 |
| - ] |
738 |
| - }, |
739 |
| - { |
740 |
| - "cell_type": "code", |
741 |
| - "execution_count": null, |
742 |
| - "metadata": {}, |
743 |
| - "outputs": [], |
744 |
| - "source": [ |
| 685 | + "## Test\n", |
| 686 | + "\n", |
| 687 | + "To instantiate a new widget:\n", |
| 688 | + "\n", |
| 689 | + "```python\n", |
745 | 690 | "email = Email(value='[email protected]', disabled=False)\n",
|
746 |
| - "email" |
747 |
| - ] |
748 |
| - }, |
749 |
| - { |
750 |
| - "cell_type": "code", |
751 |
| - "execution_count": null, |
752 |
| - "metadata": {}, |
753 |
| - "outputs": [], |
754 |
| - "source": [ |
755 |
| - "email.value" |
756 |
| - ] |
757 |
| - }, |
758 |
| - { |
759 |
| - "cell_type": "code", |
760 |
| - "execution_count": null, |
761 |
| - "metadata": {}, |
762 |
| - "outputs": [], |
763 |
| - "source": [ |
764 |
| - "email.value = '[email protected]'" |
| 691 | + "email\n", |
| 692 | + "```\n", |
| 693 | + "\n", |
| 694 | + "To get the value of the widget:\n", |
| 695 | + "\n", |
| 696 | + "```python\n", |
| 697 | + "email.value\n", |
| 698 | + "```\n", |
| 699 | + "\n", |
| 700 | + "To set the value of the widget:\n", |
| 701 | + "\n", |
| 702 | + "```python\n", |
| 703 | + "email.value = '[email protected]'\n", |
| 704 | + "```" |
765 | 705 | ]
|
766 | 706 | },
|
767 | 707 | {
|
|
0 commit comments