{"id":747,"date":"2025-01-14T18:13:35","date_gmt":"2025-01-14T18:13:35","guid":{"rendered":"https:\/\/bendauphinee.com\/writing\/?p=747"},"modified":"2025-01-22T21:00:41","modified_gmt":"2025-01-22T21:00:41","slug":"an-app-from-scratch-part-8-creating-new-templates-tool-us1-c3","status":"publish","type":"post","link":"https:\/\/bendauphinee.com\/writing\/2025\/01\/14\/an-app-from-scratch-part-8-creating-new-templates-tool-us1-c3\/","title":{"rendered":"An App From Scratch: Part 8 \u2013\u00a0Creating New Templates Tool (US1-C3)"},"content":{"rendered":"\n<p class=\"has-small-font-size\">15 minute reading time; ~2860 words<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n\n<p>Welcome and hello!<\/p>\n\n\n\n<p>Today, we&#8217;re going to create a template creation tool. This post talks about creating the new interface elements needed, how we connect our frontend to backend with an API call, and some more conversation about pull request sizing.<\/p>\n\n\n\n<p>Without further ado, let&#8217;s dive into it and build that tool!<\/p>\n\n\n\n<p class=\"has-accent-5-background-color has-background\">If you haven&#8217;t read the previous posts, I&#8217;d suggest you start at <a href=\"https:\/\/bendauphinee.com\/writing\/2024\/12\/20\/designing-an-app-from-scratch-part-1-what-to-build\/\" data-type=\"link\" data-id=\"https:\/\/bendauphinee.com\/writing\/2024\/12\/20\/designing-an-app-from-scratch-part-1-what-to-build\/\">An App From Scratch: Part 1 \u2013 What To Build<\/a>. You can also find all the related documents and code here: <a href=\"https:\/\/bendauphinee.com\/writing\/building-tailgunner\/\">Building Tailgunner<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Do I See?<\/h2>\n\n\n\n<p>As you can see by the card below, there are a few things we need to solve to complete the tool needed. Based on the fact that there is a system diagram linked in the details, I&#8217;d guess there&#8217;s going to be a lot of details to work through.<\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-contrast-background-color has-text-color has-background has-link-color wp-elements-781664196e2006396d26241bf57c8255 has-global-padding is-layout-constrained wp-container-core-group-is-layout-9597dc02 wp-block-group-is-layout-constrained\" style=\"padding-top:var(--wp--preset--spacing--10);padding-right:var(--wp--preset--spacing--10);padding-bottom:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)\">\n<p class=\"has-contrast-color has-accent-3-background-color has-text-color has-background has-link-color wp-elements-f26b1101c9421ad49f3b31ecf5418c10\" style=\"padding-top:0;padding-right:0.3rem;padding-bottom:0;padding-left:0.3rem\"><strong>Card<\/strong>: US1-C3<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<h4 class=\"wp-block-heading has-base-color has-text-color has-background has-link-color wp-elements-4bf8fa03559180f6a65d7015bc498d5b\" style=\"background-color:#dddddd;padding-top:var(--wp--preset--spacing--10);padding-right:var(--wp--preset--spacing--10);padding-bottom:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)\">Title<\/h4>\n\n\n\n<p>Create tool to add new template<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<h4 class=\"wp-block-heading has-base-color has-text-color has-background has-link-color wp-elements-208c9d0f6b2264867b69c2622d7d9968\" style=\"background-color:#dddddd;padding-top:var(--wp--preset--spacing--10);padding-right:var(--wp--preset--spacing--10);padding-bottom:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)\">Type<\/h4>\n\n\n\n<p>Story<\/p>\n<\/div>\n<\/div>\n\n\n\n<h4 class=\"wp-block-heading has-base-color has-text-color has-background has-link-color wp-elements-c2d2f57ca0c39c3684d432537b97ceee\" style=\"background-color:#dddddd;padding-top:var(--wp--preset--spacing--10);padding-right:var(--wp--preset--spacing--10);padding-bottom:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)\">Description<\/h4>\n\n\n\n<p class=\"has-medium-font-size\">As a business owner, I want a way to add a new template, so that I can create a new data set.<\/p>\n\n\n\n<p><strong>Acceptance Criteria<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>There is a way from the template list page to open the template add tool.<\/li>\n\n\n\n<li>The business owner is able to create new templates that they own.<\/li>\n\n\n\n<li>New templates show up in the template list.<\/li>\n<\/ul>\n\n\n\n<p><strong>Details<\/strong><\/p>\n\n\n\n<p>See the system diagram for <a href=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2024\/12\/Tailgunner-System-Diagram-2024-12.png\" target=\"_blank\" rel=\"noreferrer noopener\" data-rel=\"lightbox-gallery-rmQAb2Gi\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\">creating a new template<\/a>.<\/p>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">What I Need To Do<\/h3>\n\n\n\n<p>Reviewing the system diagram and acceptance criteria, we can break down these tasks:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a button to open an add dialog<\/li>\n\n\n\n<li>Create the add dialog in the list page<\/li>\n\n\n\n<li>Create a route to save the new template<\/li>\n\n\n\n<li>Connect the dialog save to the new route<\/li>\n\n\n\n<li>Add the new template to the list display<\/li>\n\n\n\n<li>Add a notification for the created template<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Putting It Into Action<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">Create a button to open an add dialog<\/h4>\n\n\n\n<p>Personally, the best place for an add button is up in the top right corner. The first step is to tidy up the current header. If we look at the current header, we can see there&#8217;s a bunch of Tailwind styles embedded in it.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;template #header&gt;\n    &lt;h2 class=&quot;font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight&quot;&gt;\n        Templates\n    &lt;\/h2&gt;\n&lt;\/template&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #D4D4D4\"> #<\/span><span style=\"color: #9CDCFE\">header<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">h2<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        Templates<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">h2<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>As part of adding the button, I&#8217;m going to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Move the header H2 styles to our css file.<\/li>\n\n\n\n<li>Add the button to the header.<\/li>\n\n\n\n<li>Add a flexbox so I can align the new button to the right side.<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">CSS<\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/* Template Header Elements *\/\n.template_header{\n    @apply flex justify-between items-center;\n}\n\n.template_header h2{\n    @apply font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight;\n}\n\n\/* Generic Button Styles *\/\nbutton.add_button{\n    @apply m-1 p-2 text-base text-black rounded bg-sky-400;\n}\n\nbutton.add_button:hover{\n    @apply bg-sky-200;\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/* Template Header Elements *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D7BA7D\">.template_header<\/span><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    @apply <\/span><span style=\"color: #9CDCFE\">flex<\/span><span style=\"color: #D4D4D4\"> justify-between items-center;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D7BA7D\">.template_header<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #D7BA7D\">h2<\/span><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    @apply font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/* Generic Button Styles *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D7BA7D\">button.add_button<\/span><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    @apply m-1 p-2 text-base text-black rounded bg-sky-400;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D7BA7D\">button.add_button:hover<\/span><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    @apply bg-sky-200;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Moving these styles to the CSS file means they won&#8217;t need to load on every single page load, and will also help to keep things consistent across different pages, since we now have one place to change that will update everywhere.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;template #header&gt;\n    &lt;div class=&quot;template_header&quot;&gt;\n        &lt;h2&gt;\n            Templates\n        &lt;\/h2&gt;\n        &lt;button class=&quot;add_button&quot; @click=&quot;btnClick('Add New Template')&quot;&gt;\n            Add New Template\n        &lt;\/button&gt;\n    &lt;\/div&gt;\n&lt;\/template&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #D4D4D4\"> #<\/span><span style=\"color: #9CDCFE\">header<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;template_header&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">h2<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            Templates<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">h2<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;add_button&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">@click<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;btnClick(&#39;Add New Template&#39;)&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            Add New Template<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"75\" src=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-9-1024x75.png\" alt=\"\" class=\"wp-image-778\" srcset=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-9-1024x75.png 1024w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-9-300x22.png 300w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-9-768x56.png 768w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-9.png 1252w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Now with that done, we have a way to trigger the next piece we&#8217;re doing!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Create the add dialog in the list page<\/h4>\n\n\n\n<p>First, we&#8217;ll create some code to support the dialog.<\/p>\n\n\n\n<p>We need some variables to track the state of the dialog (line 5), and what the state of the form in it is (line 6-8). We&#8217;ll also make a small function that will eventually save the template, but for now will just close the dialog (line 11-14).<\/p>\n\n\n\n<p> To power this, we&#8217;re also going to use the <code>ref<\/code> function from Vue (line 2), so that the UI can automatically update when we make changes to these variables.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;script setup&gt;\nimport { ref } from 'vue';\n\n\/\/ Add dialog state and methods\nconst showDialog = ref(false);\nconst form = ref({\n    title: '',\n    errors: null\n});\n\n\/\/ This function will be used to actually create the form we request\nconst createTemplate = () =&gt; {\n  showDialog.value = false;\n};\n&lt;\/script&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">script<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">setup<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">ref<\/span><span style=\"color: #D4D4D4\"> } <\/span><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;vue&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ Add dialog state and methods<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">showDialog<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">ref<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">false<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">form<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">ref<\/span><span style=\"color: #D4D4D4\">({<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">title:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;&#39;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">errors:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">null<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">});<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ This function will be used to actually create the form we request<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">createTemplate<\/span><span style=\"color: #D4D4D4\"> = () <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #9CDCFE\">showDialog<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">false<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">};<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">script<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Next, we&#8217;ll add the actual dialog, with a small form in it. We&#8217;re going to use <a href=\"https:\/\/inertiajs.com\/forms\">Inertia&#8217;s form handling<\/a>, so we&#8217;ll also make sure to add the right hooks in the code for that.<\/p>\n\n\n\n<p>Breaking down some key lines:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Line 3<\/strong>: The v-if reacts to the state of the variable on line 5 above. If we set that variable to true, the dialog will appear, if we set it back to false, it&#8217;ll disappear again.<\/li>\n\n\n\n<li><strong>Line 6<\/strong>: This blocks the standard form submit action, and instead tells our browser to call the function we created on line 12 above.<\/li>\n\n\n\n<li><strong>Line 8:<\/strong> The value of this field will be linked to the variable we set up in line 7 earlier. When someone types into this field, the above variable is updated, and if the above variable is updated by something in the code, the field below will reflect the same value. This is called <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/vuejs-v-model-two-way-binding\" data-type=\"link\" data-id=\"https:\/\/www.digitalocean.com\/community\/tutorials\/vuejs-v-model-two-way-binding\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">two-way binding<\/a>.<\/li>\n\n\n\n<li><strong>Line 13<\/strong>: If our request to the server returns an error about this field, we&#8217;ll outline it in red. As well, on line 15-17, we actually show the error message. (That <code>?.<\/code> operator is called <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/Optional_chaining\">optional chaining<\/a>, a way of accessing properties that might not be set, without throwing errors.)<\/li>\n\n\n\n<li><strong>Line 19<\/strong>: Clicking the cancel button will set the variable controlling the dialog back to false, causing it to be hidden again.<\/li>\n\n\n\n<li><strong>Line 23<\/strong>: While the form is processing, the Save button will be disabled<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;template&gt; &lt;!-- Ignore this line, it's just so the formatter shows the right colors --&gt;\n\n&lt;div v-if=&quot;showDialog&quot; class=&quot;dialog-overlay&quot;&gt;\n    &lt;div class=&quot;dialog&quot;&gt;\n        &lt;h3 class=&quot;title&quot;&gt;Create New Template&lt;\/h3&gt;\n        &lt;form @submit.prevent=&quot;createTemplate&quot;&gt;\n            &lt;input\n                v-model=&quot;form.title&quot;\n                type=&quot;text&quot;\n                placeholder=&quot;Template Name&quot;\n                id=&quot;name&quot;\n                class=&quot;w-full p-2 border rounded mb-4&quot;\n                :class=&quot;{ 'border-red-500': form.errors?.title }&quot;\n            \/&gt;\n            &lt;p v-if=&quot;form.errors?.title&quot; class=&quot;text-red-500 text-sm mb-2&quot;&gt;\n                {{ form.errors.title }}\n            &lt;\/p&gt;\n            &lt;div class=&quot;flex justify-end gap-2&quot;&gt;\n                &lt;button class=&quot;cancel_button&quot; @click=&quot;showDialog = false&quot;&gt;Cancel&lt;\/button&gt;\n                &lt;button\n                    class=&quot;add_button&quot;\n                    type=&quot;submit&quot;\n                    :disabled=&quot;form.processing&quot;\n                &gt;Save&lt;\/button&gt;\n            &lt;\/div&gt;\n        &lt;\/form&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #6A9955\">&lt;!-- Ignore this line, it&#39;s just so the formatter shows the right colors --&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">v-if<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;showDialog&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;dialog-overlay&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;dialog&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">h3<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;title&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\">Create New Template<\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">h3<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">form<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">@submit.prevent<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;createTemplate&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">input<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">v-model<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;form.title&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">type<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;text&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">placeholder<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;Template Name&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">id<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;name&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;w-full p-2 border rounded mb-4&quot;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">:class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;{ &#39;border-red-500&#39;: form.errors?.title }&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">\/&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">p<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">v-if<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;form.errors?.title&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;text-red-500 text-sm mb-2&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                {{ form.errors.title }}<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">p<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;flex justify-end gap-2&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;cancel_button&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">@click<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;showDialog = false&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\">Cancel<\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">button<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;add_button&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">type<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;submit&quot;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">:disabled<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;form.processing&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\">Save<\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">form<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Along with the dialog code itself (which I placed just before the <code>&lt;AppLayout title=\"Templates\"&gt;<\/code>), we also need a few styles. Below, we&#8217;ve set up an overlay that will cover everything on the screen, then placed the dialog content above that. (Same as last post, you can read more in the <a href=\"https:\/\/tailwindcss.com\/docs\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Tailwindcss docs<\/a> about what these do.)<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">CSS<\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/* Dialog Styles *\/\n.dialog-overlay {\n    @apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50;\n}\n\n.dialog {\n    @apply bg-white p-6 rounded-lg shadow-xl max-w-md w-full m-4;\n}\n\n.dialog .title{\n    @apply text-xl font-bold mb-4;\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/* Dialog Styles *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D7BA7D\">.dialog-overlay<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    @apply fixed inset-0 bg-black bg-opacity-50 <\/span><span style=\"color: #9CDCFE\">flex<\/span><span style=\"color: #D4D4D4\"> items-center justify-center z-50;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D7BA7D\">.dialog<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    @apply bg-white p-6 rounded-lg shadow-xl max-w-md w-full m-4;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D7BA7D\">.dialog<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #D7BA7D\">.title<\/span><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    @apply text-xl font-bold mb-4;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Finally, we&#8217;ll update the button to control template visibility.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;template #header&gt;\n    &lt;div class=&quot;template_header&quot;&gt;\n        &lt;h2&gt;\n            Templates\n        &lt;\/h2&gt;\n        &lt;button class=&quot;add_button&quot; @click=&quot;showDialog = true&quot;&gt;\n            Add New Template\n        &lt;\/button&gt;\n    &lt;\/div&gt;\n&lt;\/template&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #D4D4D4\"> #<\/span><span style=\"color: #9CDCFE\">header<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;template_header&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">h2<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            Templates<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">h2<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;add_button&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">@click<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;showDialog = true&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            Add New Template<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>And now, let&#8217;s get a look at what the dialog looks like!<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"484\" height=\"242\" src=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-6.png\" alt=\"\" class=\"wp-image-769\" srcset=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-6.png 484w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-6-300x150.png 300w\" sizes=\"auto, (max-width: 484px) 100vw, 484px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Create a route to save the new template<\/h4>\n\n\n\n<p>The only thing we have to do is enable the <code>store<\/code> resource on our existing route. Later, we could move this to an actual <code>\/api\/<\/code> endpoint, but that would mean other adjustments to our code as well, so we&#8217;ll leave that for now.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">PHP<\/span><span role=\"button\" tabindex=\"0\" data-code=\"Route::middleware([\n    'auth:sanctum',\n    config('jetstream.auth_session'),\n    'verified',\n])-&gt;group(function () {\n    Route::get('\/dashboard', function () {\n        return Inertia::render('Dashboard');\n    })-&gt;name('dashboard');\n\n    Route::resource('\/templates', TemplateController::class)-&gt;only(['index', 'store']);\n});\n\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #4EC9B0\">Route<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">middleware<\/span><span style=\"color: #D4D4D4\">([<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #CE9178\">&#39;auth:sanctum&#39;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">config<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;jetstream.auth_session&#39;<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #CE9178\">&#39;verified&#39;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">])-&gt;<\/span><span style=\"color: #DCDCAA\">group<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4EC9B0\">Route<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">get<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;\/dashboard&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Inertia<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">render<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;Dashboard&#39;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    })-&gt;<\/span><span style=\"color: #DCDCAA\">name<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;dashboard&#39;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4EC9B0\">Route<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">resource<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;\/templates&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #4EC9B0\">TemplateController<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\">)-&gt;<\/span><span style=\"color: #DCDCAA\">only<\/span><span style=\"color: #D4D4D4\">([<\/span><span style=\"color: #CE9178\">&#39;index&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&#39;store&#39;<\/span><span style=\"color: #D4D4D4\">]);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">});<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>There&#8217;s a handy command you can run, that will show you all the routes Laravel has. I&#8217;ve cut out most of them, but here&#8217;s a small snippet showing the command and what it outputs.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Bash<\/span><span role=\"button\" tabindex=\"0\" data-code=\"$ php artisan route:list\n\n  GET|HEAD  \/ ....................................................................................\n  GET|HEAD  dashboard ............ dashboard\n  GET|HEAD  login ................ login \u203a Laravel\\Fortify \u203a AuthenticatedSessionController@create\n  GET|HEAD  templates ............ templates.index \u203a TemplateController@index\n  POST      templates ............ templates.store \u203a TemplateController@store\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line cbp-line-highlight\"><span style=\"color: #DCDCAA\">$<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">php<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">artisan<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">route:list<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">GET<\/span><span style=\"color: #D4D4D4\">|<\/span><span style=\"color: #DCDCAA\">HEAD<\/span><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #CE9178\">\/<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">....................................................................................<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">GET<\/span><span style=\"color: #D4D4D4\">|<\/span><span style=\"color: #DCDCAA\">HEAD<\/span><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #CE9178\">dashboard<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">............<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">dashboard<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">GET<\/span><span style=\"color: #D4D4D4\">|<\/span><span style=\"color: #DCDCAA\">HEAD<\/span><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #CE9178\">login<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">................<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">login<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">\u203a<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">Laravel<\/span><span style=\"color: #D7BA7D\">\\F<\/span><span style=\"color: #CE9178\">ortify<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">\u203a<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">AuthenticatedSessionController@create<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">GET<\/span><span style=\"color: #D4D4D4\">|<\/span><span style=\"color: #DCDCAA\">HEAD<\/span><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #CE9178\">templates<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">............<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">templates.index<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">\u203a<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">TemplateController@index<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">POST<\/span><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #CE9178\">templates<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">............<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">templates.store<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">\u203a<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">TemplateController@store<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Next, you can see the function that we added to our controller. The validation (line 4-6) will check that we have passed in the correct data to create a new template, and if there are problems, will pass back specific error messages (which we set up our form for earlier). After that, we&#8217;re going to create the new template (line 9-12), and then pass back a JSON response that contains the new template information, as well as some data for a &#8220;flash&#8221; message.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">PHP<\/span><span role=\"button\" tabindex=\"0\" data-code=\"public function store(Request $request)\n{\n    \/\/ Validate that we have the required data for a new template\n    $validated = $request-&gt;validate([\n        'title' =&gt; 'required|string|max:120',\n    ]);\n\n    \/\/ Make us a new template\n    $template = Template::create([\n        'title' =&gt; $validated['title'],\n        'user_id' =&gt; auth()-&gt;id(),\n    ]);\n\n    \/\/ Pass back the data for the new template, and a flash message\n    return response()-&gt;json([\n        'template' =&gt; [\n            'id' =&gt; $template-&gt;id,\n            'title' =&gt; $template-&gt;title,\n            'description' =&gt; '',\n            'created_at' =&gt; $template-&gt;created_at,\n            'last_used' =&gt; $template-&gt;created_at,\n            'records' =&gt; 0,\n        ],\n        'flash' =&gt; [\n            'success' =&gt; [\n                'data' =&gt; [\n                    'id' =&gt; $template-&gt;id,\n                    'title' =&gt; $template-&gt;title,\n                ]\n            ]\n        ]\n    ]);\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">store<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">Request<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$request<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Validate that we have the required data for a new template<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$validated<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">$request<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #DCDCAA\">validate<\/span><span style=\"color: #D4D4D4\">([<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&#39;title&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #CE9178\">&#39;required|string|max:120&#39;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    ]);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Make us a new template<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$template<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #4EC9B0\">Template<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">create<\/span><span style=\"color: #D4D4D4\">([<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&#39;title&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #9CDCFE\">$validated<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #CE9178\">&#39;title&#39;<\/span><span style=\"color: #D4D4D4\">],<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&#39;user_id&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #DCDCAA\">auth<\/span><span style=\"color: #D4D4D4\">()-&gt;<\/span><span style=\"color: #DCDCAA\">id<\/span><span style=\"color: #D4D4D4\">(),<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    ]);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Pass back the data for the new template, and a flash message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">response<\/span><span style=\"color: #D4D4D4\">()-&gt;<\/span><span style=\"color: #DCDCAA\">json<\/span><span style=\"color: #D4D4D4\">([<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&#39;template&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&#39;id&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #9CDCFE\">$template<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #9CDCFE\">id<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&#39;title&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #9CDCFE\">$template<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&#39;description&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #CE9178\">&#39;&#39;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&#39;created_at&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #9CDCFE\">$template<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #9CDCFE\">created_at<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&#39;last_used&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #9CDCFE\">$template<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #9CDCFE\">created_at<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&#39;records&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        ],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&#39;flash&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&#39;success&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #CE9178\">&#39;data&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #CE9178\">&#39;id&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #9CDCFE\">$template<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #9CDCFE\">id<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #CE9178\">&#39;title&#39;<\/span><span style=\"color: #D4D4D4\"> =&gt; <\/span><span style=\"color: #9CDCFE\">$template<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                ]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            ]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        ]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    ]);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>One small change is also required for the Template model. We need to set a few fields as fillable, <a href=\"https:\/\/laravel.com\/docs\/11.x\/eloquent#mass-assignment\">so we can mass-assign them<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">PHP<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Template extends Model\n{\n    protected $fillable = ['title', 'description', 'user_id'];\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">&lt;?php<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">namespace<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">App\\Models<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">use<\/span><span style=\"color: #D4D4D4\"> Illuminate\\Database\\Eloquent\\Factories\\<\/span><span style=\"color: #4EC9B0\">HasFactory<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">use<\/span><span style=\"color: #D4D4D4\"> Illuminate\\Database\\Eloquent\\<\/span><span style=\"color: #4EC9B0\">Model<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Template<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">extends<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">protected<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$fillable<\/span><span style=\"color: #D4D4D4\"> = [<\/span><span style=\"color: #CE9178\">&#39;title&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&#39;description&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&#39;user_id&#39;<\/span><span style=\"color: #D4D4D4\">];<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Here&#8217;s an example of the data that this endpoint is returning when we create a new template.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">JSON<\/span><span role=\"button\" tabindex=\"0\" data-code=\"{\n    &quot;template&quot;: {\n        &quot;id&quot;: 99,\n        &quot;title&quot;: &quot;A Test Template&quot;,\n        &quot;description&quot;: &quot;&quot;,\n        &quot;created_at&quot;: &quot;2025-01-13T12:00:00.000000Z&quot;,\n        &quot;last_used&quot;: &quot;2025-01-13T12:00:00.000000Z&quot;,\n        &quot;records&quot;: 0\n    },\n    &quot;flash&quot;: {\n        &quot;success&quot;: {\n            &quot;data&quot;: {\n                &quot;id&quot;: 99,\n                &quot;title&quot;: &quot;A Test Template&quot;\n            }\n        }\n    }\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">&quot;template&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">&quot;id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #B5CEA8\">99<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">&quot;title&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;A Test Template&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">&quot;description&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">&quot;created_at&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;2025-01-13T12:00:00.000000Z&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">&quot;last_used&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;2025-01-13T12:00:00.000000Z&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">&quot;records&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #B5CEA8\">0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">&quot;flash&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">&quot;success&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">&quot;data&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">&quot;id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #B5CEA8\">99<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">&quot;title&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;A Test Template&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Connect the dialog save to the new route<\/h4>\n\n\n\n<p>We&#8217;re going to use the <a href=\"https:\/\/axios-http.com\/docs\/intro\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Axios library<\/a> to make our POST call, saving the data for our new template. If everything goes well, we&#8217;ll hide the dialog and clear out the form. If there is an error, we&#8217;ll pass it to the form so it can be displayed and (hopefully) fixed by the user.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">JavaScript<\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/\/ Save the template\nconst createTemplate = () =&gt; {\n    axios.post('\/templates', { title: form.value.title })\n        .then(response =&gt; {\n            \/\/ Clean up the form\n            showDialog.value = false;\n            form.value.title = '';\n        })\n        .catch(error =&gt; {\n            form.value.errors = error.response.data.errors;\n        });\n};\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/\/ Save the template<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">createTemplate<\/span><span style=\"color: #D4D4D4\"> = () <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">axios<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">post<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;\/templates&#39;<\/span><span style=\"color: #D4D4D4\">, { <\/span><span style=\"color: #9CDCFE\">title:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\"> })<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #DCDCAA\">then<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Clean up the form<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">showDialog<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">false<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        })<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #DCDCAA\">catch<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">errors<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">data<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">errors<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">};<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Add the new template to the list display<\/h4>\n\n\n\n<p>This is an easy change! When we get a successful save response, we just add the returned template data to the top of the list of templates, which triggers an automatic update of the displayed table.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">JavaScript<\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/\/ Save the template\nconst createTemplate = () =&gt; {\n    axios.post('\/templates', { title: form.value.title })\n        .then(response =&gt; {\n            \/\/ Clean up the form\n            showDialog.value = false;\n            form.value.title = '';\n\n            \/\/ Add the new template to the top of the list\n            templates.value.unshift(response.data.template);\n        })\n        .catch(error =&gt; {\n            form.value.errors = error.response.data.errors;\n        });\n};\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/\/ Save the template<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">createTemplate<\/span><span style=\"color: #D4D4D4\"> = () <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">axios<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">post<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;\/templates&#39;<\/span><span style=\"color: #D4D4D4\">, { <\/span><span style=\"color: #9CDCFE\">title:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\"> })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #DCDCAA\">then<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Clean up the form<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">showDialog<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">false<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Add the new template to the top of the list<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">templates<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">unshift<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">data<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">template<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #DCDCAA\">catch<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">errors<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">data<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">errors<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">};<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"flashmsg\">Add a flash message for the created template<\/h4>\n\n\n\n<p>A flash message is a brief message, intended to communicate status or display a dismissible message. In our case, we&#8217;re going to add a flash message just above the table to show that the template was created, and give a link to edit it.<\/p>\n\n\n\n<p>To do this, we&#8217;re going to set up a variable to hold the flash information (line 2), and a small function to get rid of it when the user dismisses it (line 3).<\/p>\n\n\n\n<p>We&#8217;ll also need <a href=\"https:\/\/vuejs.org\/guide\/essentials\/watchers\">Vue&#8217;s <code>watch()<\/code> function<\/a> (line 2), to keep an eye on the flash value and update the UI when it changes (line 10-18).<\/p>\n\n\n\n<p>Finally, we need to update the flash value with the information we get back from the API call (line 32-35). Since we set up the watch on line 10, changing this value will immediately update the interface.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;script setup&gt;\nimport { ref, watch } from 'vue';\n\n...\n\n\/\/ Check for and handle the flash message\nconst flash = ref(null);\nconst dismissFlash = () =&gt; {flash.value = null;};\n\nwatch(\n    () =&gt; page.props.flash?.success,\n    (newFlash) =&gt; {\n        if (newFlash) {\n            flash.value = newFlash;\n        }\n    },\n    { immediate: true }\n);\n\n\/\/ Save the template\nconst createTemplate = () =&gt; {\n    axios.post('\/templates', { title: form.value.title })\n        .then(response =&gt; {\n            \/\/ Clean up the form\n            showDialog.value = false;\n            form.value.title = '';\n\n            \/\/ Add the new template to the list\n            templates.value.unshift(response.data.template);\n\n            \/\/ Trigger our flash message\n            flash.value = {\n                message: response.data.message,\n                data: response.data.template\n            };\n        })\n        .catch(error =&gt; {\n            form.value.errors = error.response.data.errors;\n        });\n};\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">script<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">setup<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">ref<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">watch<\/span><span style=\"color: #D4D4D4\"> } <\/span><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;vue&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ Check for and handle the flash message<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">flash<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">ref<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">null<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">dismissFlash<\/span><span style=\"color: #D4D4D4\"> = () <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><span style=\"color: #9CDCFE\">flash<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">null<\/span><span style=\"color: #D4D4D4\">;};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #DCDCAA\">watch<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    () <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">page<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">props<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">flash<\/span><span style=\"color: #D4D4D4\">?.<\/span><span style=\"color: #9CDCFE\">success<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    (<\/span><span style=\"color: #9CDCFE\">newFlash<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">newFlash<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">flash<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">newFlash<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    },<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    { <\/span><span style=\"color: #9CDCFE\">immediate:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">true<\/span><span style=\"color: #D4D4D4\"> }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ Save the template<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">createTemplate<\/span><span style=\"color: #D4D4D4\"> = () <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">axios<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">post<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;\/templates&#39;<\/span><span style=\"color: #D4D4D4\">, { <\/span><span style=\"color: #9CDCFE\">title:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\"> })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #DCDCAA\">then<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Clean up the form<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">showDialog<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">false<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">title<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Add the new template to the list<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">templates<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">unshift<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">data<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">template<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Trigger our flash message<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">flash<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">message:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">data<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">data:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">data<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">template<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #DCDCAA\">catch<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">form<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">errors<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">data<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">errors<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">};<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In reviewing this task, the notification was specified to include two buttons: &#8220;Add Data&#8221; and &#8220;Edit Template&#8221;. In getting to the requirement, we&#8217;ve spotted <em>one<\/em> problem however&#8230; because the template doesn&#8217;t have any defined data fields, we can&#8217;t actually add any data to it.<\/p>\n\n\n\n<p>If there were stakeholders, we&#8217;d have a quick chat with them before removing this button from the final implementation. Where I&#8217;m solo, I had a conversation with myself, and I approved this change.<\/p>\n\n\n\n<p>Finally, below, you can see the UI code to handle the flash message, attached to a <code>v-if<\/code> directive that watches the value we set above. Using the data in the <code>flash.data<\/code>, we can set up the message and button to edit (for now, just showing an alert message).<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;template&gt; &lt;!-- Ignore this line, it's just so the formatter shows the right colors --&gt;\n\n&lt;div class=&quot;bg-white dark:bg-gray-800 overflow-x-auto shadow-xl sm:rounded-lg&quot;&gt;\n    &lt;div v-if=&quot;flash&quot; class=&quot;ilf_success&quot;&gt;\n        &lt;span class=&quot;block sm:inline&quot;&gt;\n            Successfully created new template &quot;{{ flash.data.title }}&quot;\n            &lt;button \n                class=&quot;edit&quot; \n                @click=&quot;btnClick(`Edit Template ${flash.data.id}`)&quot;\n            &gt;Edit Template&lt;\/button&gt;\n        &lt;\/span&gt;\n        &lt;button @click=&quot;dismissFlash&quot; class=&quot;close&quot;&gt;\n            &lt;span class=&quot;text-2xl&quot;&gt;\u00d7&lt;\/span&gt;\n        &lt;\/button&gt;\n    &lt;\/div&gt;\n\n    &lt;table v-if=&quot;templates.length&quot; class=&quot;style01&quot;&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #6A9955\">&lt;!-- Ignore this line, it&#39;s just so the formatter shows the right colors --&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;bg-white dark:bg-gray-800 overflow-x-auto shadow-xl sm:rounded-lg&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">v-if<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;flash&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;ilf_success&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">span<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;block sm:inline&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            Successfully created new template &quot;{{ flash.data.title }}&quot;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #D4D4D4\"> <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;edit&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">@click<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;btnClick(`Edit Template ${flash.data.id}`)&quot;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\">Edit Template<\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">span<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">@click<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;dismissFlash&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;close&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">span<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;text-2xl&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\">\u00d7<\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">span<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">button<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">table<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">v-if<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;templates.length&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;style01&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>With all that wired up, let&#8217;s have a look at the completed page!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"247\" src=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-11-1024x247.png\" alt=\"\" class=\"wp-image-785\" srcset=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-11-1024x247.png 1024w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-11-300x72.png 300w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-11-768x185.png 768w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-11.png 1237w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Comparing it to the wireframe, it seems we got reasonably close.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"287\" src=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-12-1024x287.png\" alt=\"\" class=\"wp-image-786\" srcset=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-12-1024x287.png 1024w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-12-300x84.png 300w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-12-768x215.png 768w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-12-1536x431.png 1536w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-12.png 1562w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">The Last Little Tweak<\/h4>\n\n\n\n<p>We&#8217;re going to make one final ease-of-use fix. We don&#8217;t yet have this template tool linked, and I&#8217;ve had to keep navigating to it via URL. Let&#8217;s make a little change to add a link to this page in the main template <code>AppLayout.vue<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Vue<\/span><span role=\"button\" tabindex=\"0\" data-code=\"&lt;template&gt; &lt;!-- Ignore this line, it's just so the formatter shows the right colors --&gt;\n\n&lt;!-- Navigation Links --&gt;\n&lt;div class=&quot;hidden space-x-8 sm:-my-px sm:ms-10 sm:flex&quot;&gt;\n    &lt;NavLink :href=&quot;route('dashboard')&quot; :active=&quot;route().current('dashboard')&quot;&gt;\n        Dashboard\n    &lt;\/NavLink&gt;\n    &lt;NavLink :href=&quot;route('templates.index')&quot; :active=&quot;route().current('templates.index')&quot;&gt;\n        Templates\n    &lt;\/NavLink&gt;\n&lt;\/div&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">template<\/span><span style=\"color: #808080\">&gt;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #6A9955\">&lt;!-- Ignore this line, it&#39;s just so the formatter shows the right colors --&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">&lt;!-- Navigation Links --&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">class<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;hidden space-x-8 sm:-my-px sm:ms-10 sm:flex&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #F44747\">NavLink<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">:href<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;route(&#39;dashboard&#39;)&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">:active<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;route().current(&#39;dashboard&#39;)&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        Dashboard<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #F44747\">NavLink<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #F44747\">NavLink<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">:href<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;route(&#39;templates.index&#39;)&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">:active<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;route().current(&#39;templates.index&#39;)&quot;<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        Templates<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #F44747\">NavLink<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">div<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>All we had to do was copy the existing link, and update the referenced route and templates. As you may recall from earlier, we&#8217;re using <a href=\"https:\/\/laravel.com\/docs\/11.x\/controllers#actions-handled-by-resource-controllers\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Laravel&#8217;s resource controller function<\/a>, which give us both default handlers in our controller and a default route structure.<\/p>\n\n\n\n<p>This little change gives us a handy link to our tool!<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"398\" height=\"244\" src=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-13.png\" alt=\"\" class=\"wp-image-788\" srcset=\"https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-13.png 398w, https:\/\/bendauphinee.com\/writing\/wp-content\/uploads\/2025\/01\/image-13-300x184.png 300w\" sizes=\"auto, (max-width: 398px) 100vw, 398px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Commit And Merge<\/h2>\n\n\n\n<p>Today&#8217;s branch name is <code>US1-C3_build_add_template_dialog<\/code>, and it&#8217;s going into <a href=\"https:\/\/github.com\/bendauphinee\/tailgunner\/pull\/4\">this pull request<\/a>, and merged <a href=\"https:\/\/github.com\/bendauphinee\/tailgunner\/commit\/202d583ce6bae28444bdf1e2cdcdc6c9dda0fec8\">in this commit<\/a>. I&#8217;ve also created some unit tests for the above work, and a new testing configuration. One note I want to make about PR size (which I&#8217;ve <a href=\"https:\/\/bendauphinee.com\/writing\/2025\/01\/07\/an-app-from-scratch-part-6-creating-db-tables-us1-c1\/#prsize\" data-type=\"post\" data-id=\"614\" target=\"_blank\" rel=\"noreferrer noopener\">talked about previously<\/a>) is that this one is on the larger side of what I would consider acceptable to send to a reviewer.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The Pull Request<\/h4>\n\n\n\n<p>I&#8217;ve changed 9 files, and about 350 lines of code. To me, the best way to break this up would have been to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Submit the non-critical change separately (adding a test environment, adding a link to the page, even the model adjustment if done before the main code).<\/li>\n\n\n\n<li>Break up the functional changes into pieces. Some possible break points are:\n<ul class=\"wp-block-list\">\n<li>once we had the Add New Template button.<\/li>\n\n\n\n<li>again after we&#8217;d added the route.<\/li>\n\n\n\n<li>before we added the flash message.<\/li>\n\n\n\n<li>a final one to capture any other changes to the code.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>This separation would allow code to stream into the main branch faster and earlier, and would make reviewing each PR review shorter and easier. That said, this size of PR isn&#8217;t unreasonable either, because it gives a complete overview of the feature, but it would take a reviewer longer to process.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A New Test Environment<\/h4>\n\n\n\n<p>One of the things that was annoying me was every time I ran the test suite, it would wipe all my development data, since it was using the same database. To fix that, I added a new testing database, which I added to my PHPUnit config, and created a new .env file for.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">phpunit.xml<\/span><span role=\"button\" tabindex=\"0\" data-code=\"        &lt;env name=&quot;TELESCOPE_ENABLED&quot; value=&quot;false&quot;\/&gt;\n\n        &lt;env name=&quot;DB_DATABASE&quot; value=&quot;tailgunner_testing&quot;\/&gt;\n        &lt;env name=&quot;DB_CONNECTION&quot; value=&quot;mysql&quot;\/&gt;\n    &lt;\/php&gt;\n&lt;\/phpunit&gt;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">env<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;TELESCOPE_ENABLED&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;false&quot;<\/span><span style=\"color: #808080\">\/&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">env<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;DB_DATABASE&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;tailgunner_testing&quot;<\/span><span style=\"color: #808080\">\/&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #808080\">&lt;<\/span><span style=\"color: #569CD6\">env<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;DB_CONNECTION&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&quot;mysql&quot;<\/span><span style=\"color: #808080\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">php<\/span><span style=\"color: #808080\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #808080\">&lt;\/<\/span><span style=\"color: #569CD6\">phpunit<\/span><span style=\"color: #808080\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">.env.testing<\/span><span role=\"button\" tabindex=\"0\" data-code=\"# Database setup for test environment\nDB_CONNECTION=mysql\nDB_HOST=127.0.0.1\nDB_PORT=3306\nDB_DATABASE=tailgunner_testing\nDB_USERNAME=root\nDB_PASSWORD=\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\"># Database setup for test environment<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">DB_CONNECTION<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">mysql<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">DB_HOST<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #B5CEA8\">127.0<\/span><span style=\"color: #CE9178\">.0.1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">DB_PORT<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #B5CEA8\">3306<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">DB_DATABASE<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">tailgunner_testing<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">DB_USERNAME<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">root<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">DB_PASSWORD<\/span><span style=\"color: #D4D4D4\">=<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>With these small changes, I can now run the tests against a specific testing database. (<code>--env<\/code> is to specify the environment, while <code>--filter<\/code> is to just run the one suite of tests.)<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Bash<\/span><span role=\"button\" tabindex=\"0\" data-code=\"$ php artisan test --env=testing --filter TemplateControllerTest\n\n   PASS  Tests\\Unit\\Controllers\\TemplateControllerTest\n  \u2713 index returns user templates                    13.38s\n  \u2713 store creates new template                       0.24s\n  \u2713 store validates title length                     0.07s\n  \u2713 store validates empty title                      0.13s\n  \u2713 index requires authentication                    0.11s\n  \u2713 store requires authentication                    0.12s\n  \u2713 store returns correctly formatted response       0.15s\n\n  Tests:    7 passed (48 assertions)\n  Duration: 14.35s\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">$<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">php<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">artisan<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">test<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">--env=testing<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">--filter<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">TemplateControllerTest<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #DCDCAA\">PASS<\/span><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #CE9178\">Tests<\/span><span style=\"color: #D7BA7D\">\\U<\/span><span style=\"color: #CE9178\">nit<\/span><span style=\"color: #D7BA7D\">\\C<\/span><span style=\"color: #CE9178\">ontrollers<\/span><span style=\"color: #D7BA7D\">\\T<\/span><span style=\"color: #CE9178\">emplateControllerTest<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2713<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">index<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">returns<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">user<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">templates<\/span><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #B5CEA8\">13.38<\/span><span style=\"color: #CE9178\">s<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2713<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">store<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">creates<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">template<\/span><span style=\"color: #D4D4D4\">                       <\/span><span style=\"color: #B5CEA8\">0.24<\/span><span style=\"color: #CE9178\">s<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2713<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">store<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">validates<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">title<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">length<\/span><span style=\"color: #D4D4D4\">                     <\/span><span style=\"color: #B5CEA8\">0.07<\/span><span style=\"color: #CE9178\">s<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2713<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">store<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">validates<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">empty<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">title<\/span><span style=\"color: #D4D4D4\">                      <\/span><span style=\"color: #B5CEA8\">0.13<\/span><span style=\"color: #CE9178\">s<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2713<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">index<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">requires<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">authentication<\/span><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #B5CEA8\">0.11<\/span><span style=\"color: #CE9178\">s<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2713<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">store<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">requires<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">authentication<\/span><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #B5CEA8\">0.12<\/span><span style=\"color: #CE9178\">s<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2713<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">store<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">returns<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">correctly<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">formatted<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">response<\/span><span style=\"color: #D4D4D4\">       <\/span><span style=\"color: #B5CEA8\">0.15<\/span><span style=\"color: #CE9178\">s<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">Tests:<\/span><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #B5CEA8\">7<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">passed<\/span><span style=\"color: #D4D4D4\"> (48 <\/span><span style=\"color: #CE9178\">assertions<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">Duration:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">14.35<\/span><span style=\"color: #CE9178\">s<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>At the end of this post, we&#8217;ve shown the process of creating a new interactive element, and touched on some code organization lessons along the way. We&#8217;re starting to get a feel for the structure of our app, and how all the pieces connect together.<\/p>\n\n\n\n<p>The work for today&#8217;s post took longer than expected. Initially, I had figured this would take an hour or two, but the biggest challenge that derailed me was working out how best to connect the create dialog to the backend API (the initial model I had in my head turned out to be wrong, so I lost a few hours learning and working out how to connect things properly).<\/p>\n\n\n\n<p>This is one of the fun things about engineering and why estimates are not as precise as we&#8217;d like them to be. Overall, I spent about a half-day writing the code, and another few hours organizing and writing this post.<\/p>\n\n\n\n<p>With that, I hope you learned something new! Look for the next part soon: <a href=\"https:\/\/bendauphinee.com\/writing\/2025\/01\/17\/an-app-from-scratch-part-9-setting-up-our-production-server-and-deployment-us1-c4\/\">Setting up our production server and deployment (US1-C4)<\/a><\/p>\n\n\n\n<p>Let me know what you think of how the tool looks, or anything else from this post!<\/p>\n\n\n\n<p>Cheers!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>15 minute reading time; ~2860 words Welcome and hello! Today, we&#8217;re going to create a template creation tool. This post talks about creating the new interface elements needed, how we connect our frontend to backend with an API call, and some more conversation about pull request sizing. Without further ado, let&#8217;s dive into it and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[],"class_list":["post-747","post","type-post","status-publish","format-standard","hentry","category-software-engineering"],"_links":{"self":[{"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/posts\/747","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/comments?post=747"}],"version-history":[{"count":56,"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/posts\/747\/revisions"}],"predecessor-version":[{"id":923,"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/posts\/747\/revisions\/923"}],"wp:attachment":[{"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/media?parent=747"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/categories?post=747"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bendauphinee.com\/writing\/wp-json\/wp\/v2\/tags?post=747"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}