Rendering Elements After The HEAD Tag In JavaScript
Ben Nadel demonstrates that elements can be rendered after the Head tag (and before the Body tag) when injected using JavaScript....
From: Ben Nadel
Ben Nadel demonstrates that elements can be rendered after the Head tag (and before the Body tag) when injected using JavaScript....
From: Ben Nadel
Ben Nadel demonstrates one way to update persistent Turbo Drive elements using Stimulus in Hotire and Lucee CFML....
From: Ben Nadel
Ben Nadel looks at parsing strings as delimited lists in MySQL. Specifically, treating a file path as a dash-delimited list of segments....
From: Ben Nadel
Normally I write these "Links For You" posts on the weekend, but my family and I will be on vacation for the next few days and the laptop is not invited. With that in mind, here's what I'd like to share with yall, enjoy!Eleventy 2.0I'm super excited that Eleventy has hit 2.0! You can read about all the changes on the blog post, and there's quite a bit, but for me the biggest updates are:Dramatic reduction (nearly a third) in dependencies.Faster builds (especially important on my large site)Async friendly shortcodes and filtersThere's a lot more, so again, check the post for details. I'm running 2.0 here, and in the new version of my site that I'm working on now.Hiding DOM ElementsI love working with the web and even more so, I love being surprised by what's possible. Here's a great example of that: Šime Vidas @simevidas@mastodon.social Basically, swap <div hidden> for <div hidden=until-found> to allow the user to search within the hidden text via find-in-page. https://webplatform.news/#1675864782000 2:17 PM • February 8, 2023 (UTC) In this toot, Šime Vidas is sharing a new value available to the hidden attribute... which I didn't even know existed! It's basically the HTML version of hiding an element via CSS. And of course, MDN has docs for it: HTMLElement.hiddenConfiguring an Alias for MastodonIn this post by the awesome David Neal, he describes how to create an alias for your Mastodon account with Eleventy and Netlify. I used this myself to create the alias @raymondcamden@raymondcamden.com for my "real" account @raymondcamden@mastodon.social. It took all of five minutes and honestly it's a really cool trick!As an aside, David does commissioned artwork. Here's one he did for me:
From: Raymond Camden
I'm thrilled to announce that I've been asked to present again at the Adobe ColdFusion Summit East 2023, a free one-day conference being held in Washington DC on Apr 6, at the Marriott Marquis. For more on the event, my talk, and how this means I have to skip attending/speaking at DevNexus the same week, read on. [More]
I could also have called this article "How to Speed Up Rust Compilation on Google Cloud Build" but that wasn't as fun. The setup for this article is quite straight forward. As apposed to previous projects of mine, I've been diving much deeper into Google Cloud Build recently. I've been building a collection of Rust Micro-Services that will be running on Cloud Run and as such I've been dealing with incredibly slow build times with some regularity. Rust notoriously concedes to extremely slow compilation time so as to achieve efficiency and safety at run time. As such, I've taken steps to decrease the build time as much as possible - because sitting there waiting for a build is not how I like to spend my evenings.
Chalk this up for yet another thing most folks probably won't need, but it was fun to build so I figured I'd share. I've had a lot of fun building bots for Mastodon. If you're curious about the process, you can read about my experience here: "Building a Mastodon Bot on Pipedream". It occurred to me that it might be cool to build a page on my blog that shows off the bots I've built. It also occurred to me that it's 100% possible I'd build a bot and forget about it.So with that in mind, I built a page that does just that. For each of my bots, it displays their last post. You can see this in action here: https://www.raymondcamden.com/bots. Here's how I built it.I began by looking at the Mastodon embed code written by Bryce Wray, "Static embeds in Eleventy". In his post, he defines a simple shortcode named stoot. Once you make this available in your Eleventy site, you can then do this to embed a toot:{% stoot "mastodon.social", "108241788606585248" %}Simple enough, right? And in theory that could have been enough. All I'd need to do is go to my bots, find one toot, and get the ID. But I thought it would be cool to embed the last toot they did, or at least the last toot at time of building. To enable that, I created another shortcode, lasttoot. It works like so in the template:{% capture "lasttoot_rcb" %}{% lasttoot "botsin.space", "randomcomicbook" %}{% endcapture %}Technically the capture isn't required per se, but as the shortcode returns the ID of the last toot, it would be useless without it. As you can see, I pass in both the server and the username of the bot. Now let's look at the code./*Given a mastodon user, I get their RSS and return the ID of the last toot.*/let Parser = require('rss-parser');let parser = new Parser();module.exports = async (instance, user) => { let rssFeedURL = `https://${instance}/users/${user}.rss`; let feed = await parser.parseURL(rssFeedURL); return feed.items[0].guid.split('/').pop();}Pretty simple, right? All Mastodon user's have an RSS feed of their activity. I used an RSS Parser to bring it in, get the most recent toot, and get the GUID value. That value looks like this (line breaks added for readability):<guid isPermaLink="true"> https://mastodon.social/@raymondcamden/109863869556714822</guid>As all I need is the ID, I do the split/pop calls to grab it. By the way, I wrote this code, and was satisfied with it, but then thought, do I really need an RSS parser? The RSS feed type won't change, maybe I could just use vanilla JavaScript. I did some searching, found solutions using DOMParser, and gave it a shot. It's then when I discovered that it was a client-side JavaScript solution, not server-side. Sigh. I also then remembered I was using rss-parser elsewhere on my site so I wasn't really hurting anything by using it again.To render my bots, I just repeated a bunch of calls to both shortcodes:{% capture "lasttoot_rcb" %}{% lasttoot "botsin.space", "randomcomicbook" %}{% endcapture %}{% stoot "botsin.space", lasttoot_rcb %}{% capture "lasttoot_sjc" %}{% lasttoot "botsin.space", "superjoycat" %}{% endcapture %}{% stoot "botsin.space", lasttoot_sjc %}{% capture "lasttoot_fra" %}{% lasttoot "botsin.space", "rulesofacquisition" %}{% endcapture %}{% stoot "botsin.space", lasttoot_fra %}{% capture "lasttoot_tbs" %}{% lasttoot "botsin.space", "tbshoroscope" %}{% endcapture %}{% stoot "botsin.space", lasttoot_tbs %}{% capture "lasttoot_tdh" %}{% lasttoot "botsin.space", "thisdayinhistory" %}{% endcapture %}{% stoot "botsin.space", lasttoot_tdh %}And that's it. I did run into one interesting issue. For RandomComicBook, the links to the particular comic book were being auto "previewed" in the embed, and since I also show the attached media, the cover, it ended up being displayed twice. I commented out that of the stoot embed for now as it solves it for me. Also, as one more quick aside, the CSS you'll see on my bot page is a bit of a mess. I took Bryce's CSS, messed with it a bit, and got it to "good enough" for my site. It's even embedded directly on the page which is bad practice, but as I'm planning on moving to a new theme soon and doing a big rewrite, I figured it was ok to leave it a bit messy for now.Anyway, let me know if you've got any questions on this, and pour one out for all the fun Twitter bots that have been destroyed by the Muskman!
From: Raymond Camden
Ben Nadel and the crew talk to our very own Carol Weiler about being part of her former company's reduction in force (ie, Carol gets laid off)....
From: Ben Nadel
Are you in the market or considering purchasing Adobe ColdFusion’s full or upgrade license? While you always have the option of going straight to Adobe, I recommend purchasing through a reseller. You will typically see a 5% discount and up to 25% depending on the sale. Do you need help with installation, upgrades, or troubleshooting? […]
From: Chris Tierney
Ben Nadel explores the use of Stimulus to delay preloading of links until a user hovers over a link in Hotwire and Lucee CFML....
From: Ben Nadel
Ben Nadel explores the use of permanent Turbo Frames to defer loading without a degraded visual experience in Hotwire and Lucee CFML....
From: Ben Nadel
Way back in 2003, I wrote my first blog post, it was short and sweet and I can share the entirety of it here:Welcome to my blog. I've been working in software development for many years now. Mostly in ColdFusion, although recently I've been working in Java as well. I plan to use this space to share ColdFusion tips - as well as share what I'm learning with Java (and hopefully save others from the stupid mistakes I make). As always, comments are welcome, and I hope this blog becomes an informative resource for all.Funny that I thought I had "many years" of development experience back then. While I've been coding since I was 9 or 10 or so, I didn't start writing code professionally till 1994 or so.My blog was completely custom-built, in ColdFusion, and while I can't seem to find an original picture of the first design, I did find this from 2005:It may be hard to read, but apparently, on February 3, 2005, I posted not once, not twice, but three times. To be fair, this was pre-Twitter, and as I've said before, I used to post a lot of notes, links, and so forth, as a way of sharing cool stuff with others.That custom blogware turned into an open-source project called BlogCFC. I'm proud to say that it became one of the most popular open-source blogging projects for ColdFusion users with hundreds, if not thousands, of instances out in the wild. I had a lot of people contribute to it, provide feedback, and just generally help make it a great platform. I was torn when I finally walked away from it, but still very proud of what I achieved with it.I eventually decided to move off of the ColdFusion platform and try something new, well new to me, WordPress. I was immediately impressed by how polished the administration was. I was also immediately turned off by how quickly WordPress (or PHP, or my database) would crash and burn, usually while I was asleep. My blog has always had "decent" traffic, but nothing so high as to really require a lot of special tuning, or at least I thought as much.It was around this time (2016) that I made my first move to the Jamstack (Welcome to RaymondCamden.com 2016). Back then we just called them static websites. My first iteration used Hugo, which handled the size of my site rather well but was way too restrictive in terms of how it worked. I then moved to Jekyll which gave me the development freedom I needed but unfortunately also showed me the pain of managing Ruby. Finally, in February (not sure I do big things in February so often) of 2020, I moved to Eleventy and have been incredibly happy with my platform since then. I've changed designs once or twice in that time (and am contemplating another change soon), but don't see myself ever leaving Eleventy. (Of course, give me another twenty years and who knows.)A lot has happened in these past 20 years. Here's a random list, in no particular order:I wrote 6,338 blog posts. Some of them were good. I also wrote 2.3 million words. Some of them were even spelled correctly.When I started the blog, my wife and I had adopted 3 kids from South Korea. In the twenty years since we adopted 4 more from China.I wrote some books. Honestly, a few of my books were written before the blog started, but overall I've contributed to, co-authored, or solo-authored, 18 books. As someone who has been a lifelong reader, I always dreamed of being a famous author. In my young mind, that was Stephen King, and while I didn't end up being published for fiction, the fact that I can say I'm a professional writer makes me incredibly proud.My LinkedIn history only goes to 2004, but in that time, I've had 10 jobs. I've been in developer relations since 2011 or so and it is my dream job.I lost my wife, which feels a bit weird to say in a bullet point, but it happened. I'm happily remarried and with my stepson, our family is now 10 strong. I could write an entire blog on we manage such a large family, but that's for another day.Related to the above, I learned how important, and helpful, therapy can be. I learned that asking young developers to code in their free time to buff up their resumes for future jobs is absolutely impossible for some people. As a single father, I had absolutely no mental energy at night to do anything but blank out in front of the TV.I grew as a father, a husband, and as a person.As I look around myself now, I've got a lot to be grateful for. I have a wife who has helped me realize it is ok to enjoy life, to be myself (as crazy as I'd like), and to just plain live. I had kids who continuously surprise me, bring joy to my life, and teach me. I have friends who don't judge me, who are there for me, and who inspire me. I've got a good job, a home for my family, and food. All in all, I am so incredibly lucky, and while I suffer incredible anxiety and fear at times, I remind myself that I am blessed.So that's a lot of pre-amble, let me get around to what I actually wanted to discuss, lessons learned from two decades of blogging.Follow Your PassionFor people launching a personal blog, figure out what makes you excited, and focus on that. It won't always be easy, and sometimes I'm not passionate about anything. Your personal and work life can absolutely impact your energy to write, but when you find something that makes you giddy, focus your attention on that.At times, I feel like a cat chasing a laser pointer. People who have been visiting my blog for a long time will know that I get super excited about a topic, write about 20 posts on it, and then never mention it again. It's not that I started to dislike a particular topic, but once I feel like I've played with something enough and have learned it enough, I move on. My blog started off as a "ColdFusion blog", but in that time I've covered hundreds of different technical topics as well as the books, movies, and games I'm excited about.I can say there's some merit to the idea of focusing on a particular topic, especially if you are hoping to get recognized in that field, but I also know that I can't force myself to write on something if the passion isn't there. If you want to focus, absolutely do so, but keep yourself open to where your mind (and heart) lead you. You are a person, not a robot, and you're going to have a lot of things that make up who you are.Don't Worry about Your Content Being "High Level" EnoughLike many in our field, I struggle with imposter syndrome. I look at the experts in our field, the "big names", and worry I'll never be as good as they are. But one thing I keep in mind is that even if I can't get to some mythical "peak" of my career, I can help others on their journey. I'm never going to be the person writing deep, complex posts about big O notation and the like (ask me about my multiple failed Google interviews), but if I can help a beginner become slightly better than I've helped.In general, if I struggle with something, or if something isn't clear, I'm 100% going to turn that into a blog post. And nearly every, single, time, I'll eventually hear that I wasn't alone in needing help.All of us are in different phases of our learning, and all of us can help others improve.A lot of times it's just a different perspective. To this day, I remember sitting in a presentation involving ColdFusion. This was when I was, in my own admission, really really darn good at it. The person giving the presentation was not. But what they were doing is sharing how they solved a problem. Their approach was absolutely unique, and I learned something that made it worth my time.Don't let the experts gatekeep you from sharing and helping others. Just share - someone will appreciate it.On Blogging Platforms and Owning Your ContentWhen I began web development, in roughly 1990 or so, it was somewhat more difficult to get a website online than it is now. A lot of people in our industry talk about how complex web development is and whether or not it needs to be that way. While there's absolutely merit to that discussion (and again, happy to get on your podcast and talk about it), the basic process of going from idea to live production website (with https!) is infinitely simpler than when it was when I started.That being said, while I think it would behoove budding bloggers (alliteration ftw) to host their own blog on their own domain on their own server, there are some good platforms out there to make it simpler. Dev.to is one of the best platforms for developers who want to get started blogging and offers a quick sign-up, zero code, and easy methods of writing. Most importantly, they offer an export option:No matter where you choose to write, ensure you have the ability to keep your content. Sites come and go, and yuo don't want to wake up one day to find that all of your hard work has disappeared.No matter what platform you choose, I'd urge you to keep a copy of your content. Or heck, write locally and then copy and paste the content. Ideally, you would keep that content backed up in a GitHub repository (I do, and my blogging platform automatically reads from it to publish), but at minimum, you can use a folder in Dropbox/OneDrive.On Writing More GooderI've got a Bachelor's degree in English. I've been writing well before I began blogging. I still misspell words (especially "misspell"), still make grammar mistakes, and still need help.One of my favorite authors, John Birmingham, has a Patreon where you can get early access to his new works, as well as random thoughts and updates. I love it. I help support him with a small donation every month, and I get to see how the sausage is made. Whenever I see one of his drafts and notice a few mistakes, I'm reminded - editors are some of the best people in the world.Years ago, my first time at Adobe, our group had an editor on staff to help with our content. Mine (Jack Wilber, hope you are still reading this!) would graciously offer feedback on my personal posts as well.While most of us probably can't afford an editor, definitely lean on your tools to help with spelling and grammar. I'm a huge fan of Grammarly and even on their free tier, I get a huge amount of feedback and help with my writing. Now, you have to be sure you actually follow through. I don't (typically) blog unless I check what Grammarly says and consciously choose to fix or ignore issues, but I had to make it part of my process for it to really be helpful.I do most of my writing in Visual Studio Code and the Grammarly extension has made this process much simpler.Keep Track of IdeasI've forgotten way more good ideas than I've actually got done on (electronic) paper, so for a very long time now I've used various tools to write ideas. I get my best ideas when exercising, walking my dog, or taking a shower, and I will immediately make note of the idea, even if I don't have time to actually work on or write the post. This is also an excellent way to find inspiration when the creative well is running dry.While I've used various tools in the past, for the past year or so I've been really enjoying Microsoft To Do. Here's my current list, and you'll notice the second to last item is something I wrote a day or so ago, I just haven't gotten around to checking it off.Getting the Word OutUnless you are famous, you will need some way of letting folks know about your content. I'm so bad at this aspect, even after twenty years, that when I wrote this blog post yesterday, I forgot to include it. Early in my career, I was well known in the ColdFusion community, so a typical blog post would get 500+ page views within the first twenty-four hours with little to no promotion on my part.A while ago when I moved to different areas of tech, that was no longer the case and I really began to think more about promotion.Up until a few months ago, my main strategy was to write a tweet about the article and then create a "ICYMI" version scheduled for one week later. I found that the repeat tweet later tended to get some traction and was a nice way to get folks back to older content.I then ditched the scheduled tweet and went with an automated method where I used Pipedream to post to both Twitter and Mastodon. That was in effect for a whole month I think before Muskman decided to kill off free Twitter API access so now my workflow only posts to Mastodon. I manually write a tweet, because even though I think Twitter is days away from completely crashing, I've got a good size audience there and it's worth the effort. (Basically, I just copy and paste the toot.)More recently I've also done the following:Post to LinkedIn.Share in Slack where appropriate. There's a Slack for Jamstack, one for Pipedream, even a front-end focused channel at work.Share in Discord. Honestly I'm feeling overwhelmed by all the chat options available and I sometimes just ignore them, but for Eleventy, there's a Discord server and channel specifically for sharing work. When I remember, I'll post there.Finally, I'll post on Reddit, sometimes.Basically, after Mastodon, Twitter, and LinkedIn, I then hit Slack/Discord/Reddit for specific categories. I honestly don't feel like I get a lot of engagement there, but typically it doesn't take more than a minute or two. I won't be sharing this post on those networks as it's too generic and I figure folks won't care.Oh, and while it goes without saying, have an RSS feed and make sure folks can actually use it. (I.e., publish it in your HTML source code.) I also set up an email subscription service via MailChimp a while ago. That list is currently at 100 members and is growing (slowly). As much as I like RSS, I don't consistently use an RSS feeder, and really prefer it when sites let me subscribe to new posts. (You can also build a workflow to email you on new RSS items via Pipedream, ask me if you want to see an example.)Be Honest, and ListenFinally, be honest. This kind of goes back to not worrying about your content being technical enough, but I absolutely will blog about stuff I'm learning. I just ensure I'm very clear on that fact and point out the aspects I'm not quite sure of yet. Regular readers know I'm learning web components and have hopefully seen that in action. I've also been lucky to get good feedback on those posts, and heck, that turns into even more content. More than once recently I've shared how folks have taken my demos, worked with them, and made them better.Thank YouI say thank you to my readers often, but I'd like to really express just how happy I am to have had an audience for so many years. You've kept me on my toes. As I approach 50 (in biological age, my maturity still hovers between 12 and 14), I don't know how long I'll keep this blog active, but here's hoping I'm writing another such piece in 2043. Also, I have always respected and admired our robotic overlords.
From: Raymond Camden
Hi i am trying replicate this call by PHP to Coldfusion: The call must be by method GET but passing data json in body {“parameter”: “2222222”} In PHP works fine but in coldfsuion no. $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, ‘http://{—URL—}); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, ‘GET’); curl_setopt($ch, CURLOPT_POSTFIELDS, “{‘param’: ‘2222222’}”); $headers = array(); $headers[] = ‘X-Api-Token: {—TOKEN–}’; $headers[] = ‘Content-Type: application/json’; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $result = curl_exec($ch); Coldfusion not works fine: <cfhttp url=”http://—-URL—” method=”GET” result=”res” charset=”utf-8″> <cfhttpparam type=”header” […] The post CFHTTP Call get method and passing data json appeared first on ColdFusion.
From: Adobe Coldfusion Blogs
Ben Nadel looks at how to extend the current request timeout using both Adobe ColdFusion and Lucee CFML....
From: Ben Nadel
Ben Nadel explores the interplay between the Hotwire Turbo Drive page cache and the browser's back button in Lucee CFML....
From: Ben Nadel
I've been loving playing with web components lately and today I'm excited to share another one. Especially excited as this one is a great example (I think!) of using a web component to enhance HTML, but that fails gracefully for a user with JavaScript disabled. Before I begin, a quick thank you to Simon MacDonald for helping me get over the hump at the end of this one. For folks curious, I'll share where I got stuck and what he and I discussed after I get through the main part of this post.Alright, so what did I build? I was curious if it would be possible to use a web component to turn a "long" form into a multistep process. Much like a typical e-commerce checkout flow, I'd want to show a part of a form one at a time, and when done, submit everything. The idea is to make the process a bit less intimidating to the user. So for example, consider this form:<form action="https://postman-echo.com/post" method="post"> <p> <label for="firstname"> First Name: </label> <input type="text" id="firstname" name="firstname"> </p> <p> <label for="lastname"> Last Name: </label> <input type="text" id="lastname" name="lastname"> </p> <p> <label for="email"> Email: </label> <input type="email" id="email" name="email"> </p> <p> <label for="ccnumber"> Credit Card Number: </label> <input type="text" id="ccnumber" name="ccnumber"> </p> <p> <label for="ccv"> CCV: </label> <input type="text" id="ccv" name="ccv"> </p> <p> <label for="expdate"> Expiration Date: </label> <input type="text" id="expdate" name="expdate"> </p> <p> <label for="street"> Street: </label> <input type="text" id="street" name="street"> </p> <p> <label for="City"> City: </label> <input type="text" id="city" name="city"> </p> <p> <label for="state"> State: </label> <input type="text" id="state" name="state"> </p> <p> <label for="postalcode"> Postal Code: </label> <input type="text" id="postalcode" name="postalcode"> </p> <input type="submit"></form>This isn't terribly long, here's how this looks with a bit of CSS:Right away, we can improve this a bit by adding a bit of natural grouping with the fieldset and legend tags:<form action="https://postman-echo.com/post" method="post"> <fieldset> <legend>Your Info</legend> <p> <label for="firstname"> First Name: </label> <input type="text" id="firstname" name="firstname"> </p> <p> <label for="lastname"> Last Name: </label> <input type="text" id="lastname" name="lastname"> </p> <p> <label for="email"> Email: </label> <input type="email" id="email" name="email"> </p> </fieldset> <fieldset> <legend>Payment Info</legend> <p> <label for="ccnumber"> Credit Card Number: </label> <input type="text" id="ccnumber" name="ccnumber"> </p> <p> <label for="ccv"> CCV: </label> <input type="text" id="ccv" name="ccv"> </p> <p> <label for="expdate"> Expiration Date: </label> <input type="text" id="expdate" name="expdate"> </p> </fieldset> <fieldset> <legend>Shipping Info</legend> <p> <label for="street"> Street: </label> <input type="text" id="street" name="street"> </p> <p> <label for="City"> City: </label> <input type="text" id="city" name="city"> </p> <p> <label for="state"> State: </label> <input type="text" id="state" name="state"> </p> <p> <label for="postalcode"> Postal Code: </label> <input type="text" id="postalcode" name="postalcode"> </p> <input type="submit"> </fieldset></form>And here's how this looks:Nicer! Looking at this, what if we could display one fieldset at a time, and dynamically add navigation? If you read my Slideshow web component post, you saw an example of this. Given a list of images for input, I add a Previous and Next button to let you navigate the images. I built something similar for this - MultistepForm:class MultistepForm extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({mode:'open'}); this.totalSets = this.querySelectorAll('fieldset').length; this.current = 0; const wrapper = document.createElement('div'); wrapper.innerHTML = ` <slot></slot> <p> <button id="prevButton">Previous</button> Step <span id="currentSetNum">1</span> of <span id="totalPictures">${this.totalSets}</span> <button id="nextButton">Next</button> </p> `; this.$nextButton = wrapper.querySelector('#nextButton'); this.$prevButton = wrapper.querySelector('#prevButton'); this.$currentSetNum = wrapper.querySelector('#currentSetNum'); shadow.appendChild(wrapper); } connectedCallback() { this.$nextButton.addEventListener('click', e => this.nextSet(e)); this.$prevButton.addEventListener('click', e => this.prevSet(e)); this.$sets = this.querySelectorAll('fieldset'); this.$sets.forEach(s => { s.style.display='none'; }); this.updateDisplay(); } nextSet() { if(this.current+1 == this.totalSets) return; this.current++; this.updateDisplay(); } prevSet() { if(this.current == 0) return; this.current--; this.updateDisplay(); } updateDisplay() { this.$sets.forEach((s, x) => { if(x === this.current) this.$sets[x].style.display = 'block'; else this.$sets[x].style.display = 'none'; }); this.$currentSetNum.innerText = this.current+1; }}customElements.define('multistep-form', MultistepForm);Taking this from the top, I begin by counting how many fieldset tags I have wrapped in my tag. I then set my current page to 0. The layout defined in the tag is defined by the content passed in and loaded via <slot></slot>, with the navigation added to the bottom. Notice the two spans in there, they will be dynamic based on the current step and the total number of steps, as defined by the total blocks of fieldsets.In my connectedCallback, I add event listeners, and then grab the fieldset blocks. For each, I hide them with display="none" and call updateDisplay. The previous and next handlers are the same as I used in my Slideshow component. The real change is in updateDisplay, which loops through the fieldsets and shows/hides based on the right value. As this is non-destructive, the user can type stuff into the form fields, navigate the form, and finally submit it.To make use of this component, I simply wrapped my HTML in <multistep-form>` tags, and was done!You can try this out yourself below: See the Pen Multistep Form WC (V2) by Raymond Camden (@cfjedimaster) on CodePen.All in all, I really dig this component. I love that it 'breaks' into a regular form so in theory, this is completely safe for any user. In theory. :)Ok, so that's the main post, feel free to stop reading. Now for the issue that stumped me and Simon helped me figure out. In my initial build of this component, I did not use the slot tag. I figured my component could edit the "regular" DOM items, not the shadow dom, and weirdly, I had no issues hiding the fieldsets, but couldn't bring them back. I assumed (guessed) that by not using slot, the original content was lost in some nether world of the DOM. I'm not sure. But using slot and manipulating the content directly in the shadow dom of the component had things working right away.
From: Raymond Camden
I've done a few blog posts about features that rely on Twitter built into this site, from Custom Twitter Embeds to WebMentions. Given the recent news of Twitter's API becoming paid (and from what I've seen it's not cheap), I'm likely going to have to rework this functionality in the near future. It's not a good situation for Twitter. It was always a favourite of developers due to the ease by which we could build on top of Twitter or into it and it seems that's now coming to an end.
Ben Nadel takes a quick look at the progress bar in Hotwire Turbo Drive, which will automatically show on slow-loading ColdFusion pages....
From: Ben Nadel
Last month I shared a simple web component I built to embed slideshows onto web pages. If you didn't get a chance to read that, you can see it in action in this CodePen below: See the Pen Slideshow Web Component by Raymond Camden (@cfjedimaster) on CodePen.After I wrote this, Šime Vidas shared an excellent update to my component with some great modifications. I talked about this version in a blog post, and it's the version I'll be using for my post today. What am I covering today?When I demonstrated how to use my web component, it was done via a script include (well, it's on CodePen, but you get the idea), and then a bit of HTML. Here's an example. (And again, thank you to Šime for his improvements.)<slide-show> <img src="https://placekitten.com/500/500" alt=""> <img src="https://picsum.photos/id/1/500/500" alt=""> <img src="https://via.placeholder.com/500" alt=""> <img src="https://placebear.com/500/500" alt=""> <img src="https://baconmockup.com/500/500" alt=""></slide-show>This works well, but, what if you wanted to modify the contents of the slideshow with other images? Let's see what happens when I try that.First, I'll add a button to the bottom:<button id="switchButton">Switch to Other Show</button>The idea here is that a user would click this to load other content. Now let's write a bit of JavaScript:document.querySelector('#switchButton').addEventListener('click', () => { console.log('Lets switch the images.'); let newUrls = 'https://via.placeholder.com/500?text=Alpha,https://via.placeholder.com/500?text=Beta,https://via.placeholder.com/500?text=Gamma,https://via.placeholder.com/500?text=Delta'; // find the slideshow, could cache this let show = document.querySelector('#myShow'); show.images = newUrls; });In this code, I've set up a click event handler and when it's used, it sets the images attribute of my web component to new URLs. Remember, even though Šime changed my component to allow for inline images, the JavaScript code of the component still actually updates the attribute, like so:this.setAttribute('images', [...this.querySelectorAll('img')].map(img => img.src).join(','));this.innerHTML = '';So, in theory, our code should work, right? Check it out below and see for yourself: See the Pen Slideshow Web Component by Raymond Camden (@cfjedimaster) on CodePen.Yep, not working. You can open up your console too and clearly see the console message being displayed and no errors, but the change doesn't have the effect we would have assumed. So what went wrong? As usual with my code, multiple things.First off, web components will not, by default, monitor changes to attributes. Your web component class needs to specify what attributes it will care about when it comes to things changing. This can be done with one line of code:static get observedAttributes() { return ['images']; }The getter observerAttributes returns an array of attributes that should be monitored for changes. For this demo, I'm specifying just the images attribute, but in theory, you could imagine responding to changes in width and height as well.Next, we have to write code to notice those changes. This is done via the attributeChangedCallback function:attributeChangedCallback(name, oldValue, newValue) { console.log(`Attribute Changed callback: ${name}, ${oldValue}, ${newValue}`); //do stuff}For now I'm just logging the attributes. As you can tell, this gets called for any change, but for us, it will always be images.Finally, there's a problem with how I changed the images:show.images = newUrls;It may be immediately obvious, but this changes a property of the DOM element, not an attribute. There's a great StackOverflow post you can read on the topic, but my code should have done this instead:show.setAttribute('images', newUrls);Whew. So with just that done, if the button is clicked, the following will show up in the console:"Attribute Changed callback: images, https://placekitten.com/500/500,https://picsum.photos/id/1/500/500,https://via.placeholder.com/500,https://placebear.com/500/500,https://baconmockup.com/500/500, https://via.placeholder.com/500?text=Alpha,https://via.placeholder.com/500?text=Beta,https://via.placeholder.com/500?text=Gamma,https://via.placeholder.com/500?text=Delta"It's a bit hard to read as it's two long lists, but you can definitely see the previous and new values. Now let's make the changes.Here's my updated attributeChangedCallback:attributeChangedCallback(name, oldValue, newValue) { this.images = this.getAttribute('images').split(',').map(i => i.trim()); this.totalImages = this.images.length; this.current = 0; this.shadowRoot.querySelector('#totalPictures').innerText = this.totalImages; this.updateImage();}As I said, I can assume the change will always be to images, but if I wanted to I could check the name value. I then copied some code from the constructor - split the string into an array, update the total number of images and reset us back to the first. The totalPictures line there is not from the constructor, but is a change I made to the HTML being generated:Picture <span id="currentPicture">1</span> of <span id="totalPictures">${this.totalImages}</span>Having the span there lets me update it easily. Here's a demo: See the Pen Slideshow Web Component (v3) by Raymond Camden (@cfjedimaster) on CodePen.Ok, better, right? There's still a bit that can be done. I definitely do not like the fact that I copied a few lines of code when updating my display. That code in both the constructor as well as the attribute changed callback could be abstracted out into a render function so there's no code duplication. As the intent for this post was to demonstrate an example of updating a component via JavaScript, I'm fine leaving that out so the focus is on just that, but feel free to fork the CodePen and share with me your update!
From: Raymond Camden
Ben Nadel and the crew talk about the recent wave of layoffs in the tech world; and what you can do to become more resilient....
From: Ben Nadel
Apologies for posting this question to this discussion group, but I’m not sure where else I could ask. I’ve not accessed the Adobe tracker site for a little while, and when I came to check out my outstanding issues yesterday, it reported that I had no issues created and no issues voted on. I looked at the ajax calls going on behind the scenes, and it appears that everything returned is giving a 400 error: I thought about submitting a […] The post Adobe Tracker broken? appeared first on ColdFusion.
From: Adobe Coldfusion Blogs
Ben Nadel starts to explore Stimulus, rendering a UTC millisecond value in the user local timezone using Hotwire and Lucee CFML....
From: Ben Nadel
Posted Feb 7, 2023; updated Feb 16, 2023 If you may have missed the chance to attend the Adobe ColdFusion Summit, held in Oct 2023 in Las Vegas, here’s another chance to hear live from Adobe and other speakers (talking especially about the upcoming ColdFusion 2023 release) at the free Adobe ColdFusion Summit East to be held Apr 6 2023 at the Marriott Marquis Washington, DC. The agenda (and speaker) details are not yet posted, but you’ll want to save […] The post Adobe ColdFusion Summit East 2023 coming up, April 6 in Washington DC appeared first on ColdFusion.
From: Adobe Coldfusion Blogs
I was buried deep in some side thread in an on-line forum, and someone asked me what a typical day was like for me. Nowadays, I'm a leadership role, with team-mates who report to me, so my day. or week, or year is a lot different than what it used to be when I programed every day. Defining a typical day is pretty hard, since the day is very variable, but I thought I'd give it a shot. But, to get a full scope of my job, I can't stop at just a day. I'll start by looking at a typical day, but then I'm going to look at a typical sprint, and then a typical year. What is a Typical Day? I'm not sure I would call any day typical; unfortunately, but let's give it a shot. 8am – 10am I get into my home office somewhere between 8am and 9am. I'll sign in and start going through my Slack notifications. A lot of messages to me or my team can build up and I try to spend an hour or two in the morning clearing out my queue. For non-urgent requests from the past, I may have used the slack reminder feature to remind me tomorrow (or next week), to come back to this. I don't want to forget. These reminders show up in the morning, and I try to catch them and respond. These may be questions about our systems, or how they work. They could be some non-priority issues. It might be a casual conversation with someone else I didn't want to forget about. Note that email is not the primary means of communication in my current environment. Eventually I'll get around to checking email, but it is usually company related newsletters or meeting invites and is relatively easily cleaned. 10am -11am My meetings do not usually start before 10am, and some days are busier than others. My team does not have daily standups, but rather we do two in person standups per week, and Geekbot on the other days. Usually morning meetings are 1:1 discussion with someone. More details on those meetings when I talk about my sprint. 11am-12 noon Around 11:00 we do a team deploy to prod. Production deploys are not automated, I believe due to some type of compliance. The company institutes a stakeholder review step, and in most cases I am the stakeholder. I have to review all the tickets completed by the team and approve them to be pushed to production. Thankfully our Dev and QA deploys are entirely automated. 12 noon to 1 Between 12 and 1 I have lunch. Most days. Some days my lunch stop is 3 minutes, other times I can relax for the full hour. Often this time slot often overlaps with lunch and learn, town halls, or other educational team meetings. 1pm to 4pm After lunch, the meetings will start up again. Some meetings are planned and recurring, and I'll talk more about that in the sprint section. A lot of ad hoc meetings to fill the time. It might be a sidebar with product owners to clarify requirements. It might be with a subset of my engineering team to talk about some issue. It might be an introductory meeting with another engineering team to discuss a new initiative we'll work on together. It might be a team review meeting to discuss the latest spike and RFC that will define what the team will build for the next few weeks or months. 4pm My wife is a school teacher, so if the stars align I'll break for dinner when she gets home from work. This usually happens 2-3 times a week. 5pm-6pm Sometimes after dinner, I'll be done for the day. Other times I'll check back-in to work. Research Research In my time around meetings, some of it is research or education. Here are some of the things that may occur: Team members often ask me questions to come out of 1:1s, for example I spent a few hours researching the expense policy for external classes, corporate travel, or recent return to office guidelines. I'll also read and comment on new product briefs from our product team Sometimes I'm reading and commenting on research spike from other teams we work with, if that work is relevant to my team. Sometimes I'm reviewing management documents, such as guidelines on new procedures or other communications from upper management, and I have to figure out what is relevant to my team, and a way to communicate that. When the team was hiring, I'd be spending time at least once a week to review resumes and give feedback to our recruiter. Some of my time goes to team building activities. Team lunches, or other team building experiences such as escape rooms. Sometimes I'm working with a designer planning branded gifts for my team. The company has sporadic training opportunities, including required courses and optional courses. I try to find time for stuff, especially if it is relevant to my job. Making myself better on my company's dime is a win-win. Writing I write a lot more than I expected in my current job. Here are a few things that may require documentation: I might write an intake document to bring a new product brief to our team. This summarizes the information from our product owner, along with other tech details from other teams about how this initiative comes together. It will feed into the team's engineering research spike. I may be crafting a new team procedure, such as documenting on call responsibilities, updating onboarding docs, creating Service Level Objectives (SLOs) and Indicators (SLIs), or creating key results related to objectives (OKRs). I might be writing up my own product brief for a tech driven initiative. This allows me to sell it to my manager, and our product owners as a priority the team should take on. To Summarize: My day is meetings, researching, and writing. I miss coding, which is primarily done in my spare time as part of this blog or writing. What is a Typical Sprint? It is a lot easier to tell you what my typical sprint will look like than a typical day. A Sprint is a two-week development cycle, with a defined scope of work for the team and clear goals. Our sprints are done on a two-week cadence, so 10 working days. Day 1 I start with a pre-planning meeting with my team's project manager and my manager. This is to take a look at the goals for the sprint, and choose the related tickets. The full team also does retro from the last sprint. What went well, what didn't, and what can we do better? If you're a programmer you're probably used to this type of meeting. Then we do real sprint planning, where we communicate out the sprint goals for the team, talk about velocity, available points for each person, and choose tickets. Day 1 coincides with our on-call person rotation, so we do on-call transition meeting to talk about issues from the last week, and double check on the schedule for the upcoming week. Sometimes work may come out of this meeting, such as documenting things for our runbook. Day 2 This is a no meeting across my org, so I catch up on a lot of the research and writing I talk about above. Day 3 This is one of the days we do in person standup. An agile ceremony where the team shares their status. We also have a backlog refinement meeting, where the team will discuss and point tickets. We also perform a sync with our product owners to talk about the ongoing work and long term roadmap. The team is invited, but optional on this one. Day 4 This day contains a leadership meeting, which is just a status all ongoing work in our department. Day 5 This day is a different leadership meeting that is a check-in on the org. Leadership is asking the people managers and project manager's about quality of life, any issues that need to be raised, or any other ongoing problems. Day 6 My team, once again, does in person standup on day six. We also have a sync with our designer, to talk about ongoing work, or more likely to jump in on future work. There is another on call transition meeting, where we once again talk about issues of the last week and check the schedule for the previous week. I also have a leadership meeting, focused on upcoming work to our division, and the various teams involved. Day 7 This is the other no meeting day across our org, so once again I try to catch up on a lot of research and writing that I mentioned above. Day 8 This is a repeat of Day 3, with in person standup, a sync with our product owners, and ticket backlog refinement. Day 9 This is a leadership meeting all about my team, similar to the one on day 5, but instead of just the org it is focused on my team only. Day 10 This is a repeat of day 5. Then we go back to day 1, and repeat. On days, where the team does not meet in person we do Geekbot for standup, and I do read through all the updates. I like this form of async status updates, because it allows the devs to get focus time. One to One Meetings Now you know that my two-week cadence contains a lot of meetings, but as you probably guessed this isn't 8 hours of a day of meetings. Thankfully! On any given day I'll have at least a single 1:1 with someone, let's talk about them. My Dev Team: I might have a 1:1 with a team member who reports to me. I Try to keep these focused on professional development and less about the current work status. There are plenty of avenues to find out about the work status, including JIRA boards, application deployments, standups (or GeekBot statuses), or any given ad hoc meeting if a problem does persist. I also have 1:1 meetings with my project manager to discuss team stuff. We may be checking in the roadmap, or making a plan for our next product checkin, or chatting about how to organize the wiki, or about policies we may need to institute with the team. There is also a 1:1 with my boss. More often than not this is a status meeting about ongoing team work, while also touching on company topics such as return to office, vacation, or other corporate policies. We may brainstorm on various issues going on with the team. There is another 1:1 meeting with my product owner, to help plan for future projects, or clarify requirements around upcoming stuff. We do a lot of chatting async as needed, but it is nice to do so zoom to zoom when needed. Although, less frequent I'll have a 1:1 with my manager's manager, which is often about team status. Sometimes, I'll get together with our designer, which is often about ongoing projects. This is less consistent, but does happen. I'm also active in the company's mentoring program. At any given time I have a mentee or two, along with a mentor of my own. Depending on the person, and how long our relationship has been, I meet with them anywhere from every 2 weeks to every other month. I appreciate these relationships with people who expose me to completely different jobs, or other aspects of the company. Many to Many Meetings I already spoke about recurring team meetings in my typical sprint, and dove deep into the type of 1:1s I have. But, there are some other meetings, that didn't quite fit into either of those categories. The first is a manager status meeting with all of my manager's direct reports. This is primarily communication about company high level procedures, or a place to have open discussions about team feedback. If I'm involved in any DE&I working groups or other extra-curricular activities, there will usually be a meeting around that. The free time I collected around all these meetings is all about the research and writing I mentioned above. Typical Year I've been a manager for about a year and a half, and I'm starting to see some patterns. There are a bunch of meetings, or initiatives, that are routine, but not sprint focused. On a monthly basis, we have team demos, both for our sibling teams in the same department and for the wider company. It is a great way to tell what we're doing. I'm not usually the one giving these, but rather coordinating with the team so one of them can give the presentation. On a quarterly basis, we'll perform ICE reviews of our roadmap with our product owners. ICE stands for Impact, Confidence, and Ease, and is a way of evaluating all the planned or upcoming projects to determine business priority. Different Town Halls meetings happen routinely. This is where everyone gets together to listen to leadership talk about initiatives, outline a plan, and commend teams or developers who have been doing awesome. These can happen within my department, or within my org, or at any given leadership level of the company. There is usually at least one a month. For some of them, I may be presenting about my team, or submitting developers for spotlight callouts. This is part of my ad-hoc writing time around the other meetings. Sometimes we do midyear reviews, and we always do end of year reviews. As part of this, I Write up a manager review of every team member that reports to me. I may collect 360 feedback from other people they've worked with--on their team and external to the team. I combine all this info into a doc, that is hopefully informative, and actionable. Highlight their strengths and point out areas for improvement. These are hard to write, and it takes me up to two weeks. Out of year end reviews, will come a professional development plan. How can we make the team members better this year? What are they interested in learning about, or improving? These are primarily driven by the employee, but there do provide things to check up on throughout the year. I may have to prepare promotion docs for my team members to present to my leadership. This includes collecting feedback from others in the org, writing information about how they excelled and making a case for how they were working at the next level. Once again, this is usually a couple of weeks to put this all together, summarizing each expectation at the next level and proving my teammate meets the criteria for the next level. Near the end of the year there is something called a team calibration meeting. I evaluate each employee against the current expectations at their job role. I believe they use an approach called 4 box, so each employee, so on each expectation they get a 1-4. One means needs improvement; two means expectations; three means excelling; and four means doing freakin' amazing. The expectation is most people will land between 2 and 3 I hate to call this procedure stack ranking, because we are only evaluating employees against the expectations of their role. But, at the end each one has a number, which in essence compares them against each other. With the rise of distributed workforces and so much work from home, I'll routinely have "virtual water cooler" group meetings with others in the org. This is the time to hang out, chat about the weekend, latest shows, sports, and sometimes play games. Final Thoughts I still like being me, so in my spare time above all of this, I still keep myself busy with non-recurring extracurricular activities. It might be contributing to the company blog or preparing an internal presentation. I have been leading a team for about a year and a half, and sometimes I feel like I'm still figuring this out. I miss being knee deep in code and architecture every day, however, leading a team managerially has been a rewarding experience and it is nice to see the other side of the curtain.
From: Jeffry Houser's Blog
Minimum Viable Product (MVP) is a term that I hear used a lot, and the concept seems pretty simple. Yet it is too frequently misused in place of prototype by junior developers and non developers (management).