{"id":2234,"date":"2022-10-26T22:41:42","date_gmt":"2022-10-26T14:41:42","guid":{"rendered":"https:\/\/www.techcoil.com\/blog\/?p=2234"},"modified":"2022-10-26T22:41:42","modified_gmt":"2022-10-26T14:41:42","slug":"rendering-multiple-checkboxes-with-wtforms-and-bootstrap","status":"publish","type":"post","link":"https:\/\/www.techcoil.com\/blog\/rendering-multiple-checkboxes-with-wtforms-and-bootstrap\/","title":{"rendered":"Rendering multiple checkboxes with WTForms and Bootstrap"},"content":{"rendered":"<p>When you use <a href=\"https:\/\/pypi.org\/project\/WTForms\/\" rel=\"noopener\" target=\"_blank\">WTForms<\/a> and <a href=\"https:\/\/getbootstrap.com\/\" rel=\"noopener\" target=\"_blank\">Bootstrap<\/a>, you can quickly build up the dashboard for your own content management system with <a href=\"\/blog\/tag\/python\" rel=\"noopener\" target=\"_blank\">Python<\/a>.<\/p>\n<p>This is because WTForms provide several out-of-the-box implementations for rendering some <a href=\"https:\/\/wtforms.readthedocs.io\/en\/2.3.x\/fields\/?highlight=field#basic-fields\" rel=\"noopener\" target=\"_blank\">basic fields<\/a> that for capturing form data.<\/p>\n<p>However, rendering multiple checkboxes can be open to different UI implementations based on users' preferences. Therefore, different <a href=\"https:\/\/wtforms.readthedocs.io\/en\/2.3.x\/fields\/?highlight=field\" rel=\"noopener\" target=\"_blank\">fields<\/a> and <a href=\"https:\/\/wtforms.readthedocs.io\/en\/2.3.x\/widgets\/?highlight=widget#widgets\" rel=\"noopener\" target=\"_blank\">widgets<\/a> are available in WTForms to cater for different ways of displaying a form input to the user.<\/p>\n<p>Given these points, let's see how we can render multiple checkboxes with WTForms and Bootstrap.<\/p>\n<h2>Rendering multiple checkboxes with WTForms only<\/h2>\n<p>First, let us look at a <a href=\"https:\/\/wtforms.readthedocs.io\/en\/stable\/specific_problems\/#specialty-field-tricks\" rel=\"noopener\" target=\"_blank\">sample implementation of rendering a list of checkboxes with WTForms<\/a>.<\/p>\n<p>If we render MultiCheckboxField without any CSS styling, we get a dotted list of checkboxes.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/sample-list-of-checkboxes-rendered-with-only-WTForms.gif\" alt=\"sample list of checkboxes rendered with only WTForms\" class=\"aligncenter\" \/><\/p>\n<p>Given that, we know that the sample implementation had rendered an unordered list of checkboxes.<\/p>\n<h2>Implementing a WTForms field to display a list of checkboxes with Bootstrap's list group component<\/h2>\n<p>Since the sample implementation renders our checkboxes as an unordered list of checkboxes, the HTML structure bodes well with <a href=\"https:\/\/getbootstrap.com\/docs\/5.0\/components\/list-group\/#checkboxes-and-radios\" rel=\"noopener\" target=\"_blank\">Bootstrap's list group component<\/a>.<\/p>\n<h3>Including own CSS classes to the different HTML tags rendered by ListWidget<\/h3>\n<p>Once we had decided on the Bootstrap component to use, we can look at how we can insert the relevant Bootstrap classes into our HTML elements.<\/p>\n<p>In order to achieve the list group component styling, we need to render:<\/p>\n<ul>\n<li>the <strong>ul<\/strong> element with <strong>list-group<\/strong> class<\/li>\n<li>the <strong>li<\/strong> element with <strong>list-group-item<\/strong> class<\/li>\n<li>the <strong>input<\/strong> element for the checkboxes with <strong>form-check<\/strong><\/li>\n<\/ul>\n<p>First, let's include the CSS classes to the <strong>li<\/strong> and <strong>input<\/strong> elements first.<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom wtforms import SelectMultipleField, widgets\r\nfrom markupsafe import Markup\r\n\r\n\r\nclass BootstrapListWidget(widgets.ListWidget):\r\n\r\n    def __call__(self, field, **kwargs):\r\n        kwargs.setdefault(&quot;id&quot;, field.id)\r\n        html = &#x5B;f&quot;&lt;{self.html_tag} {widgets.html_params(**kwargs)}&gt;&quot;]\r\n        for subfield in field:\r\n            if self.prefix_label:\r\n                html.append(f&quot;&lt;li class='list-group-item'&gt;{subfield.label} {subfield(class_='form-check-input ms-1')}&lt;\/li&gt;&quot;)\r\n            else:\r\n                html.append(f&quot;&lt;li class='list-group-item'&gt;{subfield(class_='form-check-input me-1')} {subfield.label}&lt;\/li&gt;&quot;)\r\n        html.append(&quot;&lt;\/%s&gt;&quot; % self.html_tag)\r\n        return Markup(&quot;&quot;.join(html))\r\n\r\n\r\nclass MultiCheckboxField(SelectMultipleField):\r\n    &quot;&quot;&quot;\r\n    A multiple-select, except displays a list of checkboxes.\r\n\r\n    Iterating the field will produce subfields, allowing custom rendering of\r\n    the enclosed checkbox fields.\r\n    &quot;&quot;&quot;\r\n    widget = BootstrapListWidget(prefix_label=False)\r\n    option_widget = widgets.CheckboxInput()\r\n\r\n\r\n<\/pre>\n<p>If you look into the default rendering logic of ListWidget, you will see that it does not allow a way to include CSS classes to the child elements of the ul element.<\/p>\n<p>Therefore, we first create a subclass of <a href=\"https:\/\/wtforms.readthedocs.io\/en\/2.3.x\/widgets\/?highlight=widget#wtforms.widgets.ListWidget\" rel=\"noopener\" target=\"_blank\">ListWidget<\/a> and modify the <code>__call__<\/code> method to include our own CSS classes into the relevant HTML element.<\/p>\n<p>Once we had done so, we then define MultiCheckboxField to use <code>BootstrapListWidget<\/code> as the widget.<\/p>\n<p>After we had completed our <code>MultiCheckboxField<\/code>, we can then include it in our FlaskForm:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom wtforms import TextAreaField\r\n\r\nclass PageForm(FlaskForm):\r\n    categories = MultiCheckboxField('Categories',\r\n                                    choices=&#x5B;('news', 'News'), \r\n                                             ('tutorial', 'Tutorial'), \r\n                                             ('reviews', 'Reviews'), \r\n                                             ('recommendations', 'Recommendations')])\r\n    content = TextAreaField('Content')\r\n    \r\n<\/pre>\n<h2>Rendering our MultiCheckboxField field in Jinja template<\/h2>\n<p>Finally, we can render our MultiCheckboxField in our <a href=\"https:\/\/jinja.palletsprojects.com\/en\/3.1.x\/\" rel=\"noopener\" target=\"_blank\">Jinja template<\/a>.<\/p>\n<p>Given that the form variable is an instance of PageForm, we can do so with the following template code segment:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n    {{ form.categories.label(class_=&quot;form-label&quot;) }}\r\n    {{ form.categories(class_=&quot;list-group&quot;) }}\r\n<\/pre>\n<p>As shown above, we had included the <strong>list-group<\/strong> CSS class to the <strong>ul<\/strong> element at the point when we render the MultiCheckboxField field.<\/p>\n<p>When we browse to the web page rendered by our Jinja template, we can now see that we have a list group of checkboxes.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/sample-list-of-checkboxes-rendered-with-bootstrap-and-WTForms-small-version.gif\" alt=\"sample list of checkboxes rendered with bootstrap and WTForms small version\" class=\"aligncenter\" \/><\/p>\n\n      <ul id=\"social-sharing-buttons-list\">\n        <li class=\"facebook\">\n          <a href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https%3A%2F%2Fwp.me%2Fp245TQ-A2\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n            <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Facebook.png\" alt=\"Facebook icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"twitter\">\n          <a href=\"https:\/\/twitter.com\/intent\/tweet?text=&url=https%3A%2F%2Fwp.me%2Fp245TQ-A2&via=Techcoil_com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Twitter.png\" alt=\"Twitter icon\"> Tweet\n          <\/a>\n        <\/li>\n        <li class=\"linkedin\">\n          <a href=\"https:\/\/www.linkedin.com\/shareArticle?mini=1&title=&url=https%3A%2F%2Fwp.me%2Fp245TQ-A2&source=https:\/\/www.techcoil.com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/linkedin.png\" alt=\"Linkedin icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"pinterest\">\n          <a href=\"https:\/\/pinterest.com\/pin\/create\/button\/?url=https%3A%2F%2Fwww.techcoil.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F2234&description=\" class=\"pin-it-button\" target=\"_blank\" role=\"button\" rel=\"nofollow\" count-layout=\"horizontal\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Pinterest.png\" alt=\"Pinterest icon\"> Save\n          <\/a>\n        <\/li>\n      <\/ul>\n    ","protected":false},"excerpt":{"rendered":"<p>When you use <a href=\"https:\/\/pypi.org\/project\/WTForms\/\" rel=\"noopener\" target=\"_blank\">WTForms<\/a> and <a href=\"https:\/\/getbootstrap.com\/\" rel=\"noopener\" target=\"_blank\">Bootstrap<\/a>, you can quickly build up the dashboard for your own content management system with <a href=\"\/blog\/tag\/python\" rel=\"noopener\" target=\"_blank\">Python<\/a>.<\/p>\n<p>This is because WTForms provide several out-of-the-box implementations for rendering some <a href=\"https:\/\/wtforms.readthedocs.io\/en\/2.3.x\/fields\/?highlight=field#basic-fields\" rel=\"noopener\" target=\"_blank\">basic fields<\/a> that for capturing form data.<\/p>\n<p>However, rendering multiple checkboxes can be open to different UI implementations based on users&#8217; preferences. Therefore, different <a href=\"https:\/\/wtforms.readthedocs.io\/en\/2.3.x\/fields\/?highlight=field\" rel=\"noopener\" target=\"_blank\">fields<\/a> and <a href=\"https:\/\/wtforms.readthedocs.io\/en\/2.3.x\/widgets\/?highlight=widget#widgets\" rel=\"noopener\" target=\"_blank\">widgets<\/a> are available in WTForms to cater for different ways of displaying a form input to the user.<\/p>\n<p>Given these points, let&#8217;s see how we can render multiple checkboxes with WTForms and Bootstrap.<\/p>\n","protected":false},"author":1,"featured_media":2235,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"footnotes":""},"categories":[375,4],"tags":[763,226,233,764],"jetpack_featured_media_url":"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/sample-list-of-checkboxes-rendered-with-bootstrap-and-WTForms.gif","jetpack_shortlink":"https:\/\/wp.me\/p245TQ-A2","jetpack-related-posts":[],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/2234"}],"collection":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/comments?post=2234"}],"version-history":[{"count":0,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/2234\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media\/2235"}],"wp:attachment":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media?parent=2234"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/categories?post=2234"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/tags?post=2234"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}