<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ion Prodan</title>
    <description>The latest articles on DEV Community by Ion Prodan (@wanoo21).</description>
    <link>https://dev.to/wanoo21</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F94602%2Fe396bc07-c9dc-4490-ae44-7aeb85aaa6e6.jpg</url>
      <title>DEV Community: Ion Prodan</title>
      <link>https://dev.to/wanoo21</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wanoo21"/>
    <language>en</language>
    <item>
      <title>I asked Gemini for a prototype… and Snipsco happened!</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Mon, 02 Mar 2026 08:17:37 +0000</pubDate>
      <link>https://dev.to/wanoo21/i-asked-gemini-for-a-prototype-and-snipsco-happened-5fg4</link>
      <guid>https://dev.to/wanoo21/i-asked-gemini-for-a-prototype-and-snipsco-happened-5fg4</guid>
      <description>&lt;p&gt;It doesn't matter, until it does - this is how I feel about this article and the &lt;a href="https://snipsco.com/about" rel="noopener noreferrer"&gt;Snipsco&lt;/a&gt; canvas tool.&lt;/p&gt;

&lt;p&gt;You might know me, or not, but likely have seen some of my posts (code snippets on X, some of them &lt;a href="https://x.com/ipwanciu/status/1983892914150265269" rel="noopener noreferrer"&gt;have reached a hundred thousand impressions&lt;/a&gt;), so you might know I'm passionate about sharing code examples - about nice tricks, solutions, code that made me laugh, and sad.&lt;/p&gt;

&lt;p&gt;I've been a front-end developer for quite a long time (not an indie hacker, or at least I didn't use to be); back then (when I started), things worked differently, so I'm &lt;em&gt;basically&lt;/em&gt; a senior developer trying to &lt;em&gt;keep a foot in the fast-changing world of AI coding&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So for all these coding snippets I share on X, I used to use &lt;a href="https://snappify.com/" rel="noopener noreferrer"&gt;Snappify&lt;/a&gt;, which is the one I'm most familiar with, allowing me to add many elements, such as text, arrows, and so on!&lt;/p&gt;

&lt;p&gt;The problem with Snappify is that it's &lt;em&gt;more focused on slides than just code snippets&lt;/em&gt;, and has limits on elements to use, ex, you can't use many arrows on a code snippet if you are on the free tier, but paying for pro just for some more arrows doesn't make any sense.&lt;/p&gt;

&lt;p&gt;Then I tried the free classics - &lt;a href="https://ray.so/" rel="noopener noreferrer"&gt;Ray.so&lt;/a&gt; and &lt;a href="https://carbon.now.sh/" rel="noopener noreferrer"&gt;Carbon.now.sh&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;They are beautiful, super fast, and I still respect them a lot. But they only give you one fixed code window. Nothing more. No arrows, no written explanations, no shapes around important parts, no moving blocks freely. They are perfect for simple shares, but not enough when you want to teach, explain, or make your code look really professional and clear.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So I was looking for something more than that!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There was no plan for me to build something like Snipsco. But one day, on a whim, I asked Gemini Pro on &lt;a href="https://aistudio.google.com" rel="noopener noreferrer"&gt;Google Studio&lt;/a&gt; to create a prototype using Angular, and surprisingly, it did a good job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That was the time when my (it might be quite challenging) had broken!&lt;/strong&gt; In a matter of a second, I understood I can make it, and make it so much better that everyone will want to use it, simply everyone!&lt;/p&gt;

&lt;p&gt;From that moment, everything went fast. I took the Gemini prototype, migrated it to a real Angular application, rewrote many parts, fixed bugs, made the canvas smooth with snapping, added gradients, Prism highlighting, Prettier formatting, layers, rotate, resize - everything I needed.&lt;/p&gt;

&lt;p&gt;Got the idea for the domain using &lt;a href="https://vercel.com/domains" rel="noopener noreferrer"&gt;Vercel domains&lt;/a&gt; (a very nice tool) and bought it on Cloudflare. &lt;/p&gt;

&lt;p&gt;That's how fast &lt;a href="https://snipsco.com/" rel="noopener noreferrer"&gt;Snipsco&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;I MUST mention here that AI made me code faster than EVER, I need to mention it again: &lt;strong&gt;FASTER THAN EVER!&lt;/strong&gt; No joke!&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Snipsco is right now
&lt;/h2&gt;

&lt;p&gt;Right now, Snipsco is a working preview. You paste your code, it gets formatted, you open the sidebar and add shapes, arrows, text, and images. You drag, change themes, gradients, and colors. Export PNG or to the clipboard.&lt;/p&gt;

&lt;p&gt;It is still free for everyone, and the workspace will remain free forever, with no limits. &lt;strong&gt;Use it to share beautiful code, teach others - this is the most important part for me.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But of course, this is just the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Snipsco is heading
&lt;/h2&gt;

&lt;p&gt;Snipsco's route is a long, long path, and of course, it includes AI!&lt;/p&gt;

&lt;p&gt;First, &lt;strong&gt;Snapshots&lt;/strong&gt; - like frames in history. With every &lt;strong&gt;important change, you can save as a snapshot&lt;/strong&gt;. If you want to go back or compare versions, click. &lt;/p&gt;

&lt;p&gt;Super useful when you experiment with different designs.&lt;/p&gt;

&lt;p&gt;Then, maybe - perhaps - when you have multiple snapshots, you can animate between them and turn the whole thing into a short video. I want to use advanced AI video models for smooth transitions. It could be a real breakthrough for tutorials and presentations (or maybe not). What do you think?&lt;/p&gt;

&lt;p&gt;I also want a much better workflow that never bothers you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Settings window becomes floating - you can move it anywhere or close it.&lt;/li&gt;
&lt;li&gt;The left sidebar can be collapsed, leaving you with only the clear workspace and full focus.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, &lt;strong&gt;mobile support&lt;/strong&gt; - not just responsive design. I want people to be able to create and edit on a phone or tablet as much as possible.&lt;/p&gt;

&lt;p&gt;And then small Copilot actions: auto-detect the language you pasted, suggest quick improvements, small smart helps - nothing big yet.&lt;/p&gt;

&lt;p&gt;And finally - the &lt;strong&gt;BIG COPILOT&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The big Copilot will be like a senior designer and teacher who lives inside your canvas. You can type or even speak:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;'Add arrows to explain this React hook.'&lt;/li&gt;
&lt;li&gt;'Turn this algorithm into a clear 5-step visual.'&lt;/li&gt;
&lt;li&gt;'Make it perfect for Twitter.'&lt;/li&gt;
&lt;li&gt;'Learn my company brand style from this screenshot and apply it.'&lt;/li&gt;
&lt;li&gt;'Take my blurry phone photo of code on paper and turn it into an editable canvas.'&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will give you suggestions as a preview. You always decide: apply, edit, or delete. You stay in full control.&lt;/p&gt;

&lt;p&gt;All these AI features (and the video export) will be available only for Pro users. But the workspace itself stays completely free and unlimited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I don't want to put limits on free users&lt;/strong&gt;. I remember how it felt when I hit limits in other tools. I don't want anyone to feel that with Snipsco.&lt;/p&gt;

&lt;p&gt;One thing worth mentioning is that the workflow data is stored in your browser (localStorage, soon to be IndexedDB), which limits you to using only one device (per project). Pro users will have the synchronisation and be able to see their work on any device.&lt;/p&gt;

&lt;p&gt;My mind is full of ideas - big and small. The list grows faster than I can write it.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's the Snipsco small story - now I want to hear from you.
&lt;/h2&gt;

&lt;p&gt;This is where Snipsco comes from, where it is right now, and where I see it going. I hope you like the direction.&lt;/p&gt;

&lt;p&gt;If you read until here, thank you from the bottom of my heart!&lt;/p&gt;

&lt;p&gt;Please try the preview, play with the canvas, break it, tell me what you love and what is missing. Your feedback will help me decide what to build next.&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://x.com/ipwanciu" rel="noopener noreferrer"&gt;X&lt;/a&gt; or leave a comment below.&lt;/p&gt;

&lt;p&gt;Let's teach others to code with beautiful code snippets!&lt;/p&gt;

</description>
      <category>gemini</category>
      <category>webdev</category>
      <category>ai</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>AI Story Generator in 24 Hours: Here's How I've Done It</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Thu, 04 Apr 2024 06:50:24 +0000</pubDate>
      <link>https://dev.to/wanoo21/ai-story-generator-in-24-hours-heres-how-ive-done-it-3mbk</link>
      <guid>https://dev.to/wanoo21/ai-story-generator-in-24-hours-heres-how-ive-done-it-3mbk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6x2hie0ujoiczfoilwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6x2hie0ujoiczfoilwh.png" alt="AI Story Generator in 24 Hours" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How often did you see tools like AI story generators or any AI-related tools and think, how hard is that tool to build?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Well, not so hard!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built my &lt;a href="https://aistory.tools/" rel="noopener noreferrer"&gt;free AI story generator&lt;/a&gt; based on a prompt in two days, a few hours per day, using nothing fancy, only HTML/CSS and Javascript.&lt;/p&gt;

&lt;p&gt;AI is generally quite affordable these days; my tool shows you how much it costs me to generate a few stories.&lt;/p&gt;

&lt;p&gt;Go &lt;a href="https://aistory.tools/" rel="noopener noreferrer"&gt;generate some stories&lt;/a&gt;, and check how much it costs.&lt;/p&gt;

&lt;p&gt;You can see it on the right side like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05d16usiiiy9mb100jh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05d16usiiiy9mb100jh5.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="712" height="266"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The price for around 335 words generated by AI (+20% fees)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you generate more stories, you'll see how the price increases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The price also includes a 20% fee&lt;/strong&gt; that covers the fees for the payment processor and other fees I'm unaware of. This way, I have a &lt;em&gt;buffer&lt;/em&gt; for any unexpected costs.&lt;/p&gt;

&lt;p&gt;This is why I can keep it free, with no signup required, and consider other monetization models, like ads and/or donations. However, this can be changed when OpenAI sends some "big invoices." 😎&lt;/p&gt;

&lt;p&gt;If you are not a developer, &lt;em&gt;you should know you don't have to pay a fortune for AI.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, enough talking, let's see how I built it.&lt;/p&gt;

&lt;p&gt;This is a brief description of how I built this AI tool. It's not a step-by-step guide, but it should give you a good idea of creating your own.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I built my AI story generator
&lt;/h2&gt;

&lt;p&gt;I used several tools, such as Astro, SolidJs, OpenAI, and Cloudflare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I used Astro to create the project and add integrations like Tailwind CSS, SolidJs, and MDX.&lt;/li&gt;
&lt;li&gt;I used &lt;strong&gt;SolidJs&lt;/strong&gt; &lt;strong&gt;to add some interactivity&lt;/strong&gt; to the application.&lt;/li&gt;
&lt;li&gt;I used &lt;strong&gt;OpenAI&lt;/strong&gt; &lt;strong&gt;to generate the stories using the GPT-3 model&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;I used &lt;strong&gt;Cloudflare&lt;/strong&gt; to deploy the application and handle the API requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll add some brief explanations of how I used each tool. If you want to know more about them, please ask me in the comments.&lt;/p&gt;
&lt;h3&gt;
  
  
  Astro
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Astro is a new static site generator that allows you to build your application using any framework you want, like React, Vue, or Svelte.&lt;/em&gt; It's an excellent tool for creating static sites with a dynamic feel.  &lt;/p&gt;

&lt;p&gt;To create a new Astro project, you can use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm create astro@latest // or npx create astro@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the project, you can add some integrations. I added &lt;strong&gt;Cloudflare, Tailwind CSS, SolidJs, and MDX&lt;/strong&gt; to my project.  &lt;/p&gt;

&lt;p&gt;To add these integrations, run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpx astro add cloudflare
pnpx astro add tailwind
pnpx astro add solidJs
pnpx astro add mdx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, In the end, you should have something like this in your &lt;code&gt;astro.config.mjs&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8i670tzs4pvvdforj9i3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8i670tzs4pvvdforj9i3.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="800" height="412"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Astro astro.config.mjs file&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mdx&lt;/code&gt; is a personal choice to write some stuff in Markdown rather than HTML, but you can live without it if you don't like writing in Markdown.&lt;/p&gt;

&lt;p&gt;Oh, I almost forgot: I also installed &lt;a href="https://daisyui.com/?ref=yon.fun" rel="noopener noreferrer"&gt;DaisyUI&lt;/a&gt;. It's a plugin for Tailwind CSS that adds some excellent components to your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  SolidJs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.solidjs.com/?ref=yon.fun" rel="noopener noreferrer"&gt;SolidJs&lt;/a&gt; is a reactive UI library that allows you to build fast and reactive applications with a small bundle size.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It's a great alternative to React or Vue if you want something lighter.&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;I used SolidJs to add some interactivity to the application. I created a form to input the "What's the story about" question and sent the request to the API to generate the story.&lt;/p&gt;

&lt;p&gt;Here's a short example of what the form logic looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3wbe1411qh6v0ycx4a2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3wbe1411qh6v0ycx4a2.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="800" height="326"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;SolidJS logic example&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In short, it contains three signal-like functions, and &lt;code&gt;handleSubmit&lt;/code&gt; function, which handles the form submission and sends the request to API.&lt;/p&gt;

&lt;p&gt;The first signal function (&lt;code&gt;stories&lt;/code&gt;) is to store the stories and sync them to &lt;code&gt;localStorage&lt;/code&gt; , the second (&lt;code&gt;isLoading&lt;/code&gt;) adds some interactivity until the story is generated, and the last (&lt;code&gt;price&lt;/code&gt;) calculates the price of all stories.&lt;/p&gt;

&lt;p&gt;Since I asked the GPT-3 model to respond in markdown format, I also integrated &lt;code&gt;marked&lt;/code&gt; , so the story is formatted in paragraphs and sometimes contains some titles.&lt;/p&gt;

&lt;p&gt;Some improvements are needed here because the title has to be generated separately from the story content. The users should be able to regenerate the titles they want until they like them.  &lt;/p&gt;

&lt;p&gt;But this is another story and maybe another article!&lt;/p&gt;

&lt;p&gt;And here's the form HTML:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl7ua4ngdo1yjzn9lmfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl7ua4ngdo1yjzn9lmfu.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="800" height="446"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Solidjs HTML example&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nothing is fancy here; it is just a form with a significant textarea element and some select tags.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45efmvlxrzy1oaf03lfp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45efmvlxrzy1oaf03lfp.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="800" height="481"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The form creation of an AI story&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I included optional parameters for &lt;em&gt;Genre, Story Size, Narrative Style, Tone, and Mood&lt;/em&gt; in the form to make the story more personalized.  &lt;/p&gt;

&lt;p&gt;With these parameters, users can customize the generated story to their liking. For example, they can develop a &lt;em&gt;short horror story with a dark tone and a suspenseful mood&lt;/em&gt;, a long romance story with a light tone and a happy mood, and so on.  &lt;/p&gt;

&lt;p&gt;There's a lot of room for creativity and personalization with these parameters.&lt;/p&gt;

&lt;p&gt;Users can experiment with combinations to see what kind of stories they can generate.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenAI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openai.com/product?ref=yon.fun" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; is a research lab that focuses on artificial intelligence. They have developed the GPT-3, a powerful language model that can generate human-like text.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I used OpenAI to generate the stories using the GPT-3 model.&lt;/em&gt; Using an Astro page like an API endpoint, I send the form from Solidjs to &lt;code&gt;gpt-3.5-turbo-0125&lt;/code&gt; model.&lt;/p&gt;

&lt;p&gt;You can choose your desired model; I've chosen it because it's cheaper, and the output seems fine.  &lt;/p&gt;

&lt;p&gt;Here's a short example of how the API endpoint looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nz7psv5wk4kok1juyc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nz7psv5wk4kok1juyc7.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="800" height="425"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Solving Captcha and sending a request to GPT-3&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I've forgotten to mention Captcha, which is a must. I use &lt;a href="https://developers.cloudflare.com/turnstile/?ref=yon.fun" rel="noopener noreferrer"&gt;Cloudflare's Turnstile&lt;/a&gt;. A good captcha will protect your website from robots and other malicious actors.&lt;/p&gt;

&lt;p&gt;So, what's happening in here?&lt;/p&gt;

&lt;p&gt;First, I get the sent &lt;code&gt;formData&lt;/code&gt; and captcha token (which also comes as part of form data). Second, I validate if the Captcha is correct; if not, a &lt;code&gt;403&lt;/code&gt; status is returned.&lt;/p&gt;

&lt;p&gt;Then the magic happens: I create the &lt;code&gt;messages&lt;/code&gt; array and send it to &lt;code&gt;gpt-3&lt;/code&gt; model, and wait 🙂.&lt;/p&gt;

&lt;p&gt;When I have the response, I return it to Solidjs, including the usage and story body.&lt;/p&gt;

&lt;p&gt;This article can be finished here, but we must host it somewhere, right? I've chosen Cloudflare!&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudflare
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.cloudflare.com/en-gb/?ref=yon.fun" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; is a web infrastructure and security company that provides content delivery network (CDN) services, DDoS mitigation, and internet security services.  &lt;/p&gt;

&lt;p&gt;I used Cloudflare to deploy and host the application.  &lt;/p&gt;

&lt;p&gt;To deploy an Astro project to Cloudflare, I use their in-house tool called &lt;a href="https://pages.cloudflare.com/?ref=yon.fun" rel="noopener noreferrer"&gt;Pages&lt;/a&gt;. It can deploy your project to the Cloudflare network straight from the Git repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvv95buea2h38oaj736cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvv95buea2h38oaj736cc.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="800" height="206"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Cloudflare Pages&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After deploying the project, you should have a URL to access the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0115sng86tqzuyu2xiaa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0115sng86tqzuyu2xiaa.png" alt="AI Story Generator in 24 Hours: Here's How I've Done It" width="800" height="138"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Domain names after successful deploy&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I attached a custom domain: &lt;code&gt;aistory.tools&lt;/code&gt; in this case, but Cloudflare also creates a &lt;code&gt;pages.dev&lt;/code&gt; subdomain. You don't need a custom domain to see your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's how I built my AI story generator. I hope this brief explanation helps you understand how to create your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building an AI story generator is not as complicated as it seems. Simple tools are often the suitable response to achieving complex tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't be afraid to experiment and try new things. You never know what you might discover along the way.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hope this article has inspired you to finally ship that project you've been considering for so long.&lt;/p&gt;

&lt;p&gt;If you have any questions or need help building your AI story generator, please ask me in the comments. I'll be happy to help you get started.&lt;/p&gt;

&lt;p&gt;Ultimately, I wanted to ask you what I should do next with this project.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I keep or open-source it and let others use it, too? Or should I turn it into a product and sell it to others?&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Let me know your thoughts in the comments. I'm curious to hear what you think.   &lt;/p&gt;

&lt;p&gt;What you decide will be &lt;strong&gt;the next step for this project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>generativeai</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>Required Inputs in Angular: A Comprehensive Guide</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Mon, 07 Aug 2023 08:07:51 +0000</pubDate>
      <link>https://dev.to/wanoo21/required-inputs-in-angular-a-comprehensive-guide-598k</link>
      <guid>https://dev.to/wanoo21/required-inputs-in-angular-a-comprehensive-guide-598k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubdd65clt2zlx132vj6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubdd65clt2zlx132vj6g.png" alt="Required Inputs in Angular: A Comprehensive Guide" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Angular, has introduced a new feature in version 16 that allows developers to define required inputs for components and directives.&lt;/p&gt;

&lt;p&gt;This feature ensures that all necessary data is present before the component or directive logic is executed, resulting in better code quality, fewer errors, and an overall more efficient development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the Required Inputs?
&lt;/h2&gt;

&lt;p&gt;Required inputs in Angular are a new feature that allows developers to specify that specific inputs are mandatory for a component or directive to function properly.&lt;/p&gt;

&lt;p&gt;This ensures that the required properties are passed, and &lt;strong&gt;if missing, a compilation error is thrown.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This feature is a significant improvement over the previous versions where there was no simple way to ensure that the name property is passed from the parent, which was not ideal.&lt;/p&gt;

&lt;p&gt;The code would work without any errors, but the rendered template would be missing a name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importance of Required Inputs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error Reduction&lt;/strong&gt; : By defining required inputs, developers can reduce the number of errors in the code. This is because &lt;strong&gt;Angular will throw a compilation error if a required input is not provided&lt;/strong&gt; , preventing the code from running with missing data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Quality&lt;/strong&gt; : Ensures that all necessary data is present, improving the overall code quality. This leads to more robust and reliable applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Development&lt;/strong&gt; : This makes the development process more streamlined and efficient. Developers can &lt;strong&gt;catch and fix errors at compile time, reducing the time spent debugging at runtime.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What was the problem?
&lt;/h2&gt;

&lt;p&gt;Before the required inputs were available, there wasn't a real solution to tell Angular that some specific inputs are required.&lt;/p&gt;

&lt;p&gt;For instance, let's say we have a component with an Input &lt;code&gt;userId&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;p&amp;gt;User ID: {{userId}}&amp;lt;/p&amp;gt;
 `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="nx"&gt;FooComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we include &lt;code&gt;FooComponent&lt;/code&gt; in another component, and do not provide &lt;code&gt;userId&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-foo&amp;gt;&amp;lt;/app-foo&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Angular won't throw any errors because the &lt;strong&gt;Angular compiler always sees the Inputs as optional&lt;/strong&gt;. This is perfectly fine until we want to tell that this &lt;strong&gt;Input must be provided&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's see how we can write the code with the usage of the required inputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Required Input
&lt;/h2&gt;

&lt;p&gt;We'll get the same code from the previous example and add the support of the new feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;p&amp;gt;User ID: {{userId}}&amp;lt;/p&amp;gt;
 `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="nx"&gt;FooComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, &lt;strong&gt;userId&lt;/strong&gt; is a required input.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Handling and Message
&lt;/h3&gt;

&lt;p&gt;If a required input is not passed, a new error will be thrown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This helps in identifying missing inputs at compile time rather than runtime.&lt;/strong&gt; This is a significant improvement as it allows developers to catch and fix errors earlier in the development process.&lt;/p&gt;

&lt;p&gt;If the consumer doesn't initialize this input, the Angular compiler will throw an error message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pvdc3hxk1vnvbz1fei2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pvdc3hxk1vnvbz1fei2.png" alt="Required Inputs in Angular: A Comprehensive Guide" width="800" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This ensures that the necessary data is always defined for the component.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;there is a pitfall in using the required inputs, note &lt;code&gt;!&lt;/code&gt; in the example, yes, it's there for a reason.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's a short answer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjaqlgaves11mwddegg0y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjaqlgaves11mwddegg0y.png" alt="Required Inputs in Angular: A Comprehensive Guide" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See what &lt;a href="https://www.youtube.com/@MonsterlessonsAcademy" rel="noopener noreferrer"&gt;&lt;strong&gt;Monsterlessons Academy&lt;/strong&gt;&lt;/a&gt; has to say about this in his &lt;a href="https://youtu.be/PAvg6T7hhKU?t=160" rel="noopener noreferrer"&gt;video&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alias Inputs
&lt;/h2&gt;

&lt;p&gt;Alias inputs allow developers to have a different name for the DOM property than the name of the component's property that is bound to it.&lt;/p&gt;

&lt;p&gt;For instance, you might want a more descriptive name in your component but a shorter, more convenient name in your template.&lt;/p&gt;

&lt;p&gt;An alias can be used with the required input as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;p&amp;gt;User ID: {{id}}&amp;lt;/p&amp;gt;
  `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FooComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, &lt;strong&gt;id&lt;/strong&gt; is the alias for the required input &lt;strong&gt;userId&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-foo&lt;/span&gt; &lt;span class="na"&gt;[userId]=&lt;/span&gt;&lt;span class="s"&gt;"132"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/app-foo&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be particularly useful when you want to have a different name for the DOM property than the name of the component's property that is bound to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional Inputs
&lt;/h2&gt;

&lt;p&gt;Not all inputs need to be required. As I mentioned before, the &lt;strong&gt;Angular compiler always sees the Inputs as optional.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Basically, all old Inputs are optional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optional inputs are not mandatory and can be left undefined without causing any errors.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This can be useful when certain properties are only needed under specific conditions. By marking these properties as optional, you can ensure that your component remains flexible and easy to use.&lt;/p&gt;

&lt;p&gt;Here's how to define an optional input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
   &amp;lt;p *ngIf="userId"&amp;gt;User ID: {{userId}}&amp;lt;/p&amp;gt;
  `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FooComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, &lt;strong&gt;userId&lt;/strong&gt; is an optional input. It can be left undefined without causing any errors.&lt;/p&gt;

&lt;p&gt;Make sure you add &lt;code&gt;ngIf&lt;/code&gt; or use another conditional function to display an optional Input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Required inputs in Angular provide a robust way to ensure that all necessary data is present in components and directives. It's a valuable feature that enhances code quality, reduces errors, and makes the development process more efficient.&lt;/p&gt;

&lt;p&gt;With examples and clear guidelines, implementing required inputs becomes a straightforward task for developers.&lt;/p&gt;

&lt;p&gt;With this in mind, the required inputs are a game changer in the Angular world, and I hope it'll get better and better in time.&lt;/p&gt;

&lt;p&gt;You should definitely use it, and as always, Happy Coding!&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>JavaScript Generators: Unleashing the Power of Iterables</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Tue, 18 Jul 2023 09:54:48 +0000</pubDate>
      <link>https://dev.to/wanoo21/javascript-generators-unleashing-the-power-of-iterables-nk7</link>
      <guid>https://dev.to/wanoo21/javascript-generators-unleashing-the-power-of-iterables-nk7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07e6gtrm68drj3ba5khv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07e6gtrm68drj3ba5khv.png" alt="JavaScript Generators: Unleashing the Power of Iterables" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JavaScript Generators might not be the most popular feature of JavaScript, but they sure pack a punch!&lt;/p&gt;

&lt;p&gt;These special functions, which can pause and resume their execution, are like hidden gems in the JavaScript landscape.&lt;/p&gt;

&lt;p&gt;They might not be in every developer's toolbox, but once you understand their power, you'll wonder how you ever coded without them.&lt;/p&gt;

&lt;p&gt;Generators can make your code cleaner and easier to understand, especially when you're dealing with complex tasks or asynchronous operations. But despite their benefits, they're often overlooked and underused in the JavaScript community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, why not give generators a chance?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/AnjanaVakil" rel="noopener noreferrer"&gt;Anjana Vakil&lt;/a&gt; talked about the awesome power of JS Generators in her &lt;a href="https://www.youtube.com/watch?v=gu3FfmgkwUc" rel="noopener noreferrer"&gt;JSConf presentation&lt;/a&gt;. This article is all about the examples she shared.&lt;/p&gt;

&lt;p&gt;If you don't feel like reading, &lt;em&gt;I highly recommend watching her presentation instead&lt;/em&gt;. But if you do want to read, &lt;em&gt;don't forget to check out her presentation too&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding JavaScript Generators
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://yon.fun/js-generators/" rel="noopener noreferrer"&gt;JavaScript Generators&lt;/a&gt; are special functions that can pause execution and resume at any time, creating a powerful way to manage synchronous and asynchronous tasks in a more readable and maintainable way.&lt;/p&gt;

&lt;p&gt;They were introduced in ECMAScript 2015 and have since become a fundamental part of the language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A generator function is defined with a function keyword followed by an asterisk.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When called, it does not execute its code immediately. Instead, it returns a special type of iterator, called a generator.&lt;/p&gt;

&lt;p&gt;Here's a simple example of a generator function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;simpleGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first yield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;second yield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;third yield&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;simpleGenerator&lt;/code&gt; function is a generator function, as indicated by the asterisk (*) after the function keyword.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;yield&lt;/code&gt; keyword is used to pause and resume the generator function. Each &lt;code&gt;yield&lt;/code&gt; keyword represents a stage of the generator's execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Generators
&lt;/h2&gt;

&lt;p&gt;To use a generator, you first have to initialize it. This is done by calling the generator function, which returns a generator object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;simpleGenerator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned generator object has a &lt;code&gt;next()&lt;/code&gt; method, which resumes the generator function until the next &lt;code&gt;yield&lt;/code&gt; statement is reached.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;next()&lt;/code&gt; method returns an object with two properties: &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;done&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// { value: 'first yield', done: false }&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// { value: 'second yield', done: false }&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// { value: 'third yield', done: false }&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// { value: undefined, done: true }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;value&lt;/code&gt; property contains the value yielded by the &lt;code&gt;yield&lt;/code&gt; statement, and &lt;code&gt;done&lt;/code&gt; is a boolean indicating whether the generator function has been fully completed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leveraging Generators as Iterables
&lt;/h2&gt;

&lt;p&gt;Generators can be used to create complex iterable objects.&lt;/p&gt;

&lt;p&gt;For instance, consider a scenario where you need an object representing a deck of cards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instead of manually enumerating all 52 card values, you can create a generator function that computes all permutations of the different suits and numbers, yielding each one by one.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;deckGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;suits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;♠&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;♣&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;♥&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;♦&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ranks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;9&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;J&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Q&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;K&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;suits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;suits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deckGenerator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "2♠"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "3♠"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're creating a generator function &lt;code&gt;deckGenerator&lt;/code&gt; that represents a deck of cards.&lt;/p&gt;

&lt;p&gt;The generator function uses two &lt;code&gt;yield&lt;/code&gt; statements to produce all possible combinations of suits and ranks in a deck of cards.&lt;/p&gt;

&lt;p&gt;When we call &lt;code&gt;deck.next().value&lt;/code&gt;, the generator function resumes, returning the next card in the deck.&lt;/p&gt;

&lt;p&gt;This makes it easy to iterate over the deck of cards without having to generate all possible combinations upfront.&lt;/p&gt;

&lt;p&gt;What about if we want to show all 52 cards? ♠️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nf"&gt;deckGenerator&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt; &lt;span class="c1"&gt;// Generate all possible variants&lt;/span&gt;

&lt;span class="c1"&gt;// Result: (52) ["2♠", "3♠", "4♠", "5♠", "6♠", "7♠",...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of the best examples of how using js generators simplifies devs' life!&lt;/p&gt;

&lt;h2&gt;
  
  
  Generators and Asynchronous Operations
&lt;/h2&gt;

&lt;p&gt;With ES7, we got async versions of generators and iterators.&lt;/p&gt;

&lt;p&gt;This allows us to handle asynchronous operations with generators. For instance, you can create an async generator function to load paginated data from an API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;asyncGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncGen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;asyncGenerator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;asyncGen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// { value: 0, done: false }&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;asyncGen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// { value: 1, done: false }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're using an async generator function &lt;code&gt;asyncGenerator&lt;/code&gt; to simulate loading paginated data from an API.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;yield&lt;/code&gt; statement is used in conjunction with &lt;code&gt;await&lt;/code&gt; to pause the generator function until the Promise resolves.&lt;/p&gt;

&lt;p&gt;This allows us to handle asynchronous operations in a synchronous manner, making the code easier to read and understand.&lt;/p&gt;

&lt;p&gt;When we call &lt;code&gt;asyncGen.next()&lt;/code&gt;, it returns a Promise that resolves to the next piece of data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generators as State Machines
&lt;/h2&gt;

&lt;p&gt;Generators can also function as state machines due to their ability to remember their state.&lt;/p&gt;

&lt;p&gt;For example, you can create a generator function that represents a bank account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;bankAccount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bankAccount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// initialize the generator&lt;/span&gt;
&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// deposit 100&lt;/span&gt;
&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// deposit 50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're using a generator function &lt;code&gt;bankAccount&lt;/code&gt; to represent a bank account.&lt;/p&gt;

&lt;p&gt;The generator function uses a &lt;code&gt;yield&lt;/code&gt; statement inside a &lt;code&gt;while (true)&lt;/code&gt; loop, allowing it to run indefinitely.&lt;/p&gt;

&lt;p&gt;Each time we call &lt;code&gt;account.next(deposit)&lt;/code&gt;, we're depositing money into the account.&lt;/p&gt;

&lt;p&gt;The generator function remembers its state (the account balance), making it an effective way to represent a state machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Generator Usage
&lt;/h2&gt;

&lt;p&gt;Generators can also be used to handle asynchronous tasks in a synchronous manner.&lt;/p&gt;

&lt;p&gt;This is done by &lt;strong&gt;combining generators with Promises.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This combination allows us to write asynchronous code as if it were synchronous, making it much easier to understand and maintain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;asyncGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;async data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;asyncGenerator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;asyncGenerator&lt;/code&gt; function yields a Promise that resolves after 1 second.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;next()&lt;/code&gt; method is then called on the generator, which returns the Promise.&lt;/p&gt;

&lt;p&gt;Once the Promise resolves, the &lt;code&gt;next()&lt;/code&gt; method is called again with the resolved value, which is then logged to the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Generators are a powerful feature of JavaScript that can help us manage asynchronous operations, implement custom iterable objects, and handle complex control flows.&lt;/p&gt;

&lt;p&gt;They can yield control and regain control, functioning as co-routines, passing information back and forth, and doing co-op multitasking.&lt;/p&gt;

&lt;p&gt;Watch &lt;a href="https://www.youtube.com/watch?v=gu3FfmgkwUc" rel="noopener noreferrer"&gt;Anjana Vakil's JSConf presentation&lt;/a&gt; for an in-depth understanding of the Power of JS Generators. Her presentation provides comprehensive insights and explanations that will greatly enhance your knowledge in this area.&lt;/p&gt;

&lt;p&gt;Remember, practice is the key to mastering generators, like any programming concept. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, don't hesitate to experiment with generators in your own code and explore the many possibilities they offer.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>tricks</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Native Internationalization (Intl) in Angular</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Tue, 17 Jan 2023 09:05:06 +0000</pubDate>
      <link>https://dev.to/wanoo21/intl-and-angular-pipes-3a07</link>
      <guid>https://dev.to/wanoo21/intl-and-angular-pipes-3a07</guid>
      <description>&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl" rel="noopener noreferrer"&gt;The Internationalization (Intl)&lt;/a&gt; is a built-in JavaScript library that provides a number of useful internationalisation (i18n) and localisation (l10n) features for web applications.&lt;/p&gt;

&lt;p&gt;Some of the features provided by the Intl API include support for formatting and parsing numbers, dates, and currencies according to the conventions of different locales, as well as support for collation and case-insensitive sorting of strings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://caniuse.com/?search=Intl" rel="noopener noreferrer"&gt;The Intl is supported by all modern web browsers&lt;/a&gt;, and it is widely used in web applications to ensure that they can be easily localised and adapted to different languages and cultures.&lt;/p&gt;

&lt;p&gt;Initially, I did not pay much attention to the Intl API as browser support was not as strong, but now (in my opinion) we should take advantage of it as the support has improved.&lt;/p&gt;

&lt;p&gt;As I work only in Angular, I decided to build a small library, that wraps some &lt;a href="https://github.com/wanoo21/ngx-intl-helper/tree/main/helpers" rel="noopener noreferrer"&gt;Intl APIs to Angular Pipes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There's nothing magic in there, simple pipes with custom configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ListFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultOptions&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's not a library to replace the standard Angular &lt;code&gt;currency&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt; pipes, is just a way to play around with the new Intl features within Angular applications.&lt;/p&gt;

&lt;p&gt;It can be used in production as well, if lazy loading poly fills will be implemented.&lt;/p&gt;

&lt;p&gt;Here's the link to GitHub repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/wanoo21" rel="noopener noreferrer"&gt;
        wanoo21
      &lt;/a&gt; / &lt;a href="https://github.com/wanoo21/ngx-intl-helper" rel="noopener noreferrer"&gt;
        ngx-intl-helper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This is a collection of pipes for Angular applications that use the Intl API.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Angular Intl API Pipes&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;This is a simple guide how to run the project. For documentation on how to use the library, please visit the &lt;a href="https://github.com/helpers/README.md" rel="noopener noreferrer"&gt;library's README&lt;/a&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Start the project&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;This project was generated with nx. To start the project, run &lt;code&gt;npm start&lt;/code&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Build the library&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;To build the library, run &lt;code&gt;npm run build helpers&lt;/code&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contributing&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;If you want to contribute to this project, please read the &lt;a href="https://github.com/helpers/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contributing guidelines&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/wanoo21/ngx-intl-helper" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Feel free to contribute or ask questions.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>career</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>ChatGPT and Tech articles</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Mon, 02 Jan 2023 11:11:26 +0000</pubDate>
      <link>https://dev.to/wanoo21/chatgpt-and-tech-articles-1ca3</link>
      <guid>https://dev.to/wanoo21/chatgpt-and-tech-articles-1ca3</guid>
      <description>&lt;p&gt;It seems &lt;strong&gt;ChatGPT is getting started to be a trend in writing, editing, and suggesting good articles&lt;/strong&gt;. I saw many videos on youtube already about how to write a blog post with the help of &lt;a href="https://yon.fun/tag/chatgpt/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;, and it's not bad, in my opinion, to have such a good tool, but let's be honest, are we ready to let him write the whole body of the article and have the confidence the post is relevant and informative?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unfortunately (or fortunately) NO!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1548630435-998a2cbbff67%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fHN0b3B8ZW58MHx8fHwxNjcyNjUwNjUx%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1548630435-998a2cbbff67%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fHN0b3B8ZW58MHx8fHwxNjcyNjUwNjUx%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" alt="Photo by Nadine Shaabana / Unsplash" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is good, is a thing it must be, otherwise why would you still be writing on your blog, whereas copy and paste or programmatically tell ChatGPT to do it?&lt;/p&gt;

&lt;p&gt;What would be the reason for doing this? Don't you write the articles for yourself first, for your mind, and your body?&lt;/p&gt;

&lt;p&gt;This seems to be strange, but &lt;strong&gt;ChatGPT mustn't replace you and your mind&lt;/strong&gt; while you're writing, this is not what it's meant to be, don't do it!&lt;/p&gt;

&lt;p&gt;Well, this doesn't mean you shouldn't make use of it, it's still a powerful machine that can help with many other small tasks, &lt;em&gt;like generating short descriptions, telling the difference between this and that (even though it's not relevant in many cases), helping with some random data, suggesting you how to solve some tech bugs or even can give you a full function solution if you need&lt;/em&gt;, you name it - but no more than that!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's a machine that should assist not replace you&lt;/strong&gt;, it's a GitHub Copilot but not for coding.&lt;/p&gt;

&lt;p&gt;If you leave GitHub Copilot to write your code, you'll end up with a mess, and that's totally fine - &lt;strong&gt;it's meant to assist you, not replace you.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's try it anyway
&lt;/h2&gt;

&lt;p&gt;To prove my words, let's try to write a technical article about &lt;code&gt;@ngrx/component-store&lt;/code&gt; library &lt;code&gt;ngrxPush&lt;/code&gt;, &lt;code&gt;ngrxLet&lt;/code&gt; and built-in Angular &lt;code&gt;async&lt;/code&gt; pipe.&lt;/p&gt;

&lt;p&gt;We assume we don't have deep knowledge in &lt;code&gt;ngrxPush&lt;/code&gt;, &lt;code&gt;ngrxLet&lt;/code&gt; but we understand more or less how Angular built-in &lt;code&gt;async&lt;/code&gt; pipe works.&lt;/p&gt;

&lt;p&gt;Question: &lt;em&gt;Hello, why should I use ngrxPush and ngrxLet against the Angular async pipe?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ChatGPT response: &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finow3ehqcdtc5hbe1noa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finow3ehqcdtc5hbe1noa.png" alt="ChatGPT response about ngrxPush and ngrxLet" width="793" height="842"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I won't get into more descriptive details about what's wrong and not here, but I'll try to leave some notes here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ngrxPush and ngrxLet are two operators from the @ngrx/component-store library that can be used in Angular applications to manage state and data flow in a reactive way. [...]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sorry, ChatGPT, &lt;code&gt;ngrxPush&lt;/code&gt; and &lt;code&gt;ngrxLet&lt;/code&gt; can't be operators, first is a &lt;code&gt;Pipe&lt;/code&gt; and second is a &lt;code&gt;Directive&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Both ngrxPush and ngrxLet can be used in combination with the async pipe to manage async data in an Angular application. [...]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hmmm, aren't they meant to replace Angular built-in &lt;code&gt;async&lt;/code&gt; Pipe in case of &lt;code&gt;ngrxPush&lt;/code&gt; and Angular built-in &lt;code&gt;ngIf&lt;/code&gt; directive (maybe not in all circumstances) in case of &lt;code&gt;ngrxLet&lt;/code&gt; ?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ngrxPush is an operator that allows you to push a new value into a store path. [...]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay ... let's stop here!&lt;/p&gt;

&lt;p&gt;If you want to learn more about these topics to better understand what is wrong with these sentences, &lt;a href="https://dev.to/ngrx/building-reactive-angular-templates-with-ngrx-component-4m1e"&gt;here's a good article&lt;/a&gt; I found, just go over it.&lt;/p&gt;

&lt;p&gt;You'll see, nothing here ChatGPT can teach you (at least about these topics) moreover, it gives more misunderstanding and confusion.&lt;/p&gt;

&lt;p&gt;Surprisingly, I was pretty sure ChatGPT will mention &lt;code&gt;Zone.js&lt;/code&gt;, which is (mostly) the main reason why would you switch to &lt;code&gt;ngrxPush&lt;/code&gt; and &lt;code&gt;ngrxLet&lt;/code&gt;, but this is not the case.&lt;/p&gt;

&lt;p&gt;In the nutshell, I'm very much hoping this article will convince somebody to not give up on keep writing articles based on his knowledge, experience, ideas, and (why not) emotions he has - &lt;strong&gt;this is what makes us humans&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1650735311314-dffc8dfbaa48%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDJ8fGRvbiUyN3QlMjBkbyUyMGl0fGVufDB8fHx8MTY3MjY1NDIxNw%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1650735311314-dffc8dfbaa48%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDJ8fGRvbiUyN3QlMjBkbyUyMGl0fGVufDB8fHx8MTY3MjY1NDIxNw%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" alt="Photo by dlxmedia.hu / Unsplash" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please, don't!&lt;/p&gt;

&lt;p&gt;We'll end this article with some good suggestions from ChatGPT which I totally agree with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0h0ll0b354z16pnv8gov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0h0ll0b354z16pnv8gov.png" alt="Why not use ChatGPT to write a full article body" width="762" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>monitoring</category>
      <category>learning</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Generate and Download files using JavaScript</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Mon, 20 Apr 2020 13:12:22 +0000</pubDate>
      <link>https://dev.to/wanoo21/generate-and-download-files-using-javascript-3ob3</link>
      <guid>https://dev.to/wanoo21/generate-and-download-files-using-javascript-3ob3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1542831371-29b0f74f9713%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1542831371-29b0f74f9713%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D2000%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="Generate and Download files using JavaScript" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you're used to be working only on JavaScript and sometimes needed to keep some data on your computer, you might have to implement some &lt;strong&gt;server-side code or some tricky HTML&lt;/strong&gt; which weren't working all times. Thanks to &lt;strong&gt;Blob API,&lt;/strong&gt; nowadays we can achieve that more efficiently and painlessly ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  What's a Blob?
&lt;/h2&gt;

&lt;p&gt;MDN says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;Blob&lt;/strong&gt; object represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data or converted into a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream" rel="noopener noreferrer"&gt;ReadableStream&lt;/a&gt; so its methods can be used for processing the data.&lt;/p&gt;

&lt;p&gt;Blobs can represent data that isn't necessarily in a JavaScript-native format. The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/File" rel="noopener noreferrer"&gt;&lt;code&gt;File&lt;/code&gt;&lt;/a&gt;interface is based on &lt;code&gt;Blob&lt;/code&gt;, inheriting blob functionality and expanding it to support files on the user's system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Read more about Blob on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate and Download data using JavaScript
&lt;/h2&gt;

&lt;p&gt;As we already know what's a Blob, let's have a look at how to download any type of data just using JavaScript Blob API.&lt;/p&gt;

&lt;p&gt;Consider we have a JSON format object which contains some application configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;showButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firstly we have to convert out &lt;code&gt;configuration&lt;/code&gt; object into a &lt;code&gt;Blob&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blobConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/json;charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After we need to create a &lt;code&gt;blob://...&lt;/code&gt;  link using &lt;code&gt;URL.createObjectUrl&lt;/code&gt; method and sending &lt;code&gt;blobConfig&lt;/code&gt; as parameter,  it's dynamic and always different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blobUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blobConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we have a &lt;code&gt;blob://...&lt;/code&gt; URL, we just simply create an &lt;code&gt;a&lt;/code&gt; element with corresponding &lt;code&gt;href&lt;/code&gt; attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anchor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;blobUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-configurations.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Auto click on a element, trigger the file download&lt;/span&gt;
&lt;span class="nx"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// This is required&lt;/span&gt;
&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blobUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind, always do &lt;code&gt;URL.revokeObjectURL(blobUrl)&lt;/code&gt; when you don't need that URL anymore. &lt;strong&gt;This is very important for performance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's it! Here's the full code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Configurations object&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;showButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;

&lt;span class="c1"&gt;// Convert object to Blob&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blobConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/json;charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Convert Blob to URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blobUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blobConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create an a element with blobl URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anchor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;blobUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-configurations.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Auto click on a element, trigger the file download&lt;/span&gt;
&lt;span class="nx"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Don't forget ;)&lt;/span&gt;
&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blobUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Always use this trick when you need to download a file with some data from your application. Don't complicate yourself with any server-side code, or third-party libraries anymore.&lt;/p&gt;

&lt;p&gt;Need help? Leave a comment!&lt;/p&gt;

</description>
      <category>tricks</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Angular HTTP best practices (AsyncPipe)</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Fri, 21 Feb 2020 09:14:39 +0000</pubDate>
      <link>https://dev.to/wanoo21/angular-http-best-practices-asyncpipe-3gic</link>
      <guid>https://dev.to/wanoo21/angular-http-best-practices-asyncpipe-3gic</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1wvGunz8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://yon.fun/content/images/2020/01/angular-http-async-req.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1wvGunz8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://yon.fun/content/images/2020/01/angular-http-async-req.png" alt="Angular HTTP best practices (AsyncPipe)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we'll cover some best practices to &lt;strong&gt;create HTTP requests just using the Angular AsyncPipe.&lt;/strong&gt; If you ever thought about making HTTP requests without calling &lt;code&gt;.subscribe()&lt;/code&gt;, then you're on the right page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AsyncPipe?
&lt;/h2&gt;

&lt;p&gt;According to Angular &lt;a href="https://angular.io/api/common/AsyncPipe"&gt;AsyncPipe&lt;/a&gt; documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; pipe subscribes to an &lt;code&gt;Observable&lt;/code&gt; or &lt;code&gt;Promise&lt;/code&gt; and returns the latest value it has emitted. When a new value is emitted, the &lt;code&gt;async&lt;/code&gt; pipe marks the component to be checked for changes. When the component gets destroyed, the &lt;code&gt;async&lt;/code&gt; pipe unsubscribes automatically to avoid potential memory leaks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The most important part here is "when the component gets destroyed, the &lt;br&gt;
 &lt;a href="https://angular.io/api/common/api/core/testing/async"&gt;&lt;code&gt;async&lt;/code&gt;&lt;/a&gt; pipe unsubscribes automatically to avoid potential memory leaks." These being said, we don't have to worry about &lt;strong&gt;unsubscribing&lt;/strong&gt; the Observables, the AsyncPipe will take care for of it us - good practice (and the most important).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Observables
&lt;/h2&gt;

&lt;p&gt;Let's create some observables and get started:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;onDestroy$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;user$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Create new &lt;strong&gt;Subject&lt;/strong&gt; and source &lt;strong&gt;BehaviorSubject.&lt;/strong&gt;





&lt;p&gt;As you can see, I defined two Observables, &lt;code&gt;onDestroy$&lt;/code&gt; and &lt;code&gt;user$&lt;/code&gt;. It's a good practice to have an observable which will be called when the component gets destroyed, but I'll talk later more about it.&lt;/p&gt;

&lt;p&gt;Based on &lt;code&gt;user$&lt;/code&gt; BehaviorSubject, we'll create &lt;strong&gt;a new Observable&lt;/strong&gt; &lt;code&gt;getUserInfo$&lt;/code&gt; which sends a server request - each time the &lt;code&gt;user$&lt;/code&gt; gets emitted:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;getUserInfo$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IUser&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;exhaustMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
      &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onDestroy$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Create a new &lt;strong&gt;Observable&lt;/strong&gt; from &lt;strong&gt;BehaviorSubject.&lt;/strong&gt;





&lt;p&gt;If you don't understand what's going on in this code and the &lt;code&gt;.pipe&lt;/code&gt; function is unclear for you, maybe you should first take a look at &lt;a href="https://www.learnrxjs.io/learn-rxjs/concepts/rxjs-primer#pipe"&gt;this article&lt;/a&gt; and then continue reading!&lt;/p&gt;

&lt;p&gt;There are two &lt;strong&gt;Operators&lt;/strong&gt; to pay attention, &lt;code&gt;exhaustMap&lt;/code&gt; and &lt;code&gt;takeUntil&lt;/code&gt;. Of course, you can add more operators, but &lt;em&gt;these two are the most important&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Using an &lt;code&gt;exhaustMap&lt;/code&gt; operator we can be sure that &lt;code&gt;getUserInfo$&lt;/code&gt; &lt;strong&gt;will always wait for the server response&lt;/strong&gt;, even if the &lt;code&gt;user$&lt;/code&gt; emits a new value, it's the opposite of the &lt;code&gt;switchMap&lt;/code&gt; operator. See the picture below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--47w3u-D3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://yon.fun/content/images/2020/02/12-exhaustMap-before.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--47w3u-D3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://yon.fun/content/images/2020/02/12-exhaustMap-before.png" alt="Angular HTTP best practices (AsyncPipe)"&gt;&lt;/a&gt;RxJs exhaustMap operator. Credits &lt;strong&gt;Angular University.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can read more about &lt;a href="https://blog.angular-university.io/rxjs-higher-order-mapping/"&gt;RxJs Mapping here&lt;/a&gt;, to have a better idea of why we used &lt;code&gt;exhaustMap&lt;/code&gt; and not other mapping operators.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;takeUntil&lt;/code&gt; subscribes and begins mirroring the &lt;code&gt;user$&lt;/code&gt; Observable. It also monitors a second Observable, &lt;code&gt;this.onDestroy$&lt;/code&gt; that we provided. If the &lt;code&gt;this.onDestroy$&lt;/code&gt; emits a value, the &lt;code&gt;getUserInfo$&lt;/code&gt; Observable stops mirroring the &lt;code&gt;user$&lt;/code&gt; Observable and complete. For more info about &lt;code&gt;takeUntil&lt;/code&gt;, see the &lt;a href="https://rxjs.dev/api/operators/takeUntil"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subscribing via Angular AsyncPipe
&lt;/h2&gt;

&lt;p&gt;Now as we created the &lt;code&gt;getUserInfo$&lt;/code&gt; Observable, let's see how to subscribe to it using &lt;strong&gt;AsyncPipe&lt;/strong&gt; :&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"getUserInfo$ | async as user"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ user | json }}
&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Use Angular &lt;strong&gt;AsyncPipe&lt;/strong&gt; to subscribe to the &lt;em&gt;getUserInfo$&lt;/em&gt;.





&lt;p&gt;And then just emit a new value for &lt;code&gt;user$&lt;/code&gt; in order to trigger the server request:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;mat-icon-button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"user$.next({ id: 2, name: 'John Doe' })"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Get user with id 2
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Emit new &lt;em&gt;user info,&lt;/em&gt; to trigger a server request.





&lt;p&gt;Now, if we click the button, even if we double-click, the &lt;code&gt;getUserInfo$&lt;/code&gt; will send a server request and emit new &lt;em&gt;user info&lt;/em&gt; which will be handled by Angular &lt;strong&gt;AsyncPipe&lt;/strong&gt; and in turn, will insert new &lt;em&gt;user info&lt;/em&gt; into the page.&lt;/p&gt;

&lt;p&gt;As we use &lt;code&gt;takeUntil&lt;/code&gt; operator, we have to emit some value for &lt;code&gt;this.onDestroy&lt;/code&gt; as well as complete it, &lt;code&gt;takeUntil&lt;/code&gt; is optional here, as we subscribed to &lt;code&gt;getUserInfo$&lt;/code&gt; via Angular &lt;strong&gt;AsyncPipe&lt;/strong&gt; which takes care of &lt;em&gt;unsubscribing when element gets destroyed&lt;/em&gt;, but anyway, it's &lt;strong&gt;a good practice and it's good to know about it&lt;/strong&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onDestroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onDestroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Make sure we &lt;strong&gt;unsubscribe from Observable&lt;/strong&gt; when &lt;strong&gt;component gets destroyed&lt;/strong&gt;.





&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now we don't have to worry about memory leaking, as we did the best practices for subscribing and unsubscribing from Observables. We can be sure that our code will work faster as &lt;strong&gt;AsyncPipe&lt;/strong&gt; allows us to change the &lt;code&gt;changeDetection&lt;/code&gt; of our component to &lt;code&gt;ChangeDetectionStrategy.Push&lt;/code&gt;, which (after me) is the best way to optimize a component and as well a good practice.&lt;/p&gt;

&lt;p&gt;Haven't you tried yet? Try it and let me know how it works for you 💻.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>reactiveextensions</category>
    </item>
    <item>
      <title>WebSocket, RxJS and other bad things</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Tue, 10 Dec 2019 20:11:07 +0000</pubDate>
      <link>https://dev.to/wanoo21/websocket-rxjs-and-other-bad-things-306d</link>
      <guid>https://dev.to/wanoo21/websocket-rxjs-and-other-bad-things-306d</guid>
      <description>&lt;p&gt;There are so many tutorials over the internet about different JS frameworks, API's and technologies, each day I come across to different JS articles, but almost none of them are about RxJS, even more about &lt;a href="https://yon.fun/websocket-with-rxjs" rel="noopener noreferrer"&gt;WebSockets with RxJS&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebSocket&lt;/strong&gt;, for more of Javascript developers, is something inexperienced and strange thing, even if they understand how it works, they almost never used it, and it's clear why - &lt;em&gt;not all of them needs to create web-chats!&lt;/em&gt; But, if we would look more deeply into this technology, we can understand that WebSocket is not only for "Online Chats" but much more, for example &lt;a href="https://medium.com/samsung-internet-dev/being-fast-and-light-using-binary-data-to-optimise-libraries-on-the-client-and-the-server-5709f06ef105" rel="noopener noreferrer"&gt;sending binary data to the server&lt;/a&gt; or &lt;a href="https://medium.com/outsystems-engineering/making-magic-with-websockets-and-css3-ec22c1dcc8a8" rel="noopener noreferrer"&gt;making cool things like this&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;These being said, &lt;a href="https://rxjs-dev.firebaseapp.com" rel="noopener noreferrer"&gt;RxJS&lt;/a&gt; has the same story, we are used to having it only on &lt;a href="https://angular.io/guide/rx-library" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; projects (for developers who write in Angular - for those who not, I am pretty sure they could never use it) and that's it, I haven't seen any other popular libraries to be implemented it - &lt;em&gt;is it so bad? it weighs so much? it is not reactive enough?&lt;/em&gt; I would like to know the answers to these questions 😒.&lt;/p&gt;

&lt;p&gt;What would be the reasons of un-exploring these two things, we are going today to see an example of integrating both of them and see that it is not so bad, even more - I see it &lt;strong&gt;more efficient and optimised way&lt;/strong&gt; to work with WebSockets - of course, we don't talk about simple projects, otherwise is much better to use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" rel="noopener noreferrer"&gt;the WebSocket API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  RxJS WebSocket Package
&lt;/h2&gt;

&lt;p&gt;Listening for messages from the server:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Pushing messages to the server:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;All these examples have been taken from &lt;a href="https://rxjs-dev.firebaseapp.com/api/webSocket/webSocket" rel="noopener noreferrer"&gt;RxJS official documentation&lt;/a&gt; WebSocket page, so it is available for everyone. If you are a JS developer and haven't tried RxJS yet, it is time to try it, just give it a try - you will see, it'll worth your time.&lt;/p&gt;

&lt;p&gt;Begin with surfing this &lt;a href="https://www.learnrxjs.io/" rel="noopener noreferrer"&gt;cool website&lt;/a&gt;, write some tests, &lt;em&gt;think as Observable,&lt;/em&gt; (start writing in TypeScript, &lt;strong&gt;get more sleep&lt;/strong&gt;, go to &lt;a href="https://confs.tech/javascript?topics=javascript" rel="noopener noreferrer"&gt;JS conferences&lt;/a&gt;, read &lt;a href="https://github.com/getify/You-Dont-Know-JS" rel="noopener noreferrer"&gt;JS books&lt;/a&gt; and do not stop here) in that way we will build better websites, web-applications, web-servers, mobile-applications and everything which JavaScript allows us to build.&lt;/p&gt;

&lt;p&gt;Make the internet a safer and better place.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>rxjs</category>
      <category>typescript</category>
      <category>websocket</category>
    </item>
    <item>
      <title>Detect chrome dev tools (working trick)</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Thu, 27 Jun 2019 19:53:35 +0000</pubDate>
      <link>https://dev.to/wanoo21/detect-chrome-dev-tools-working-trick-2obl</link>
      <guid>https://dev.to/wanoo21/detect-chrome-dev-tools-working-trick-2obl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F585s76jhlb3bapl2z4xb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F585s76jhlb3bapl2z4xb.png" alt="Detect chrome dev tools (working trick)" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever thought about how to detect if the &lt;em&gt;chrome dev tools is opened&lt;/em&gt; or not, even more, &lt;em&gt;listen when it's opening&lt;/em&gt;? I have, and today I'm going to show a simple trick.&lt;/p&gt;

&lt;p&gt;After some Google researches, I found many tricks but unfortunately, many of them aren't working anymore. There's just one solution (after me) which can deal with that. Take a look to this (copy and paste it to your code, it's ready to use solution):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* Call callback function here */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Detect Chrome Dev Tools Javascript Code





&lt;p&gt;Let's dive into it a bit and understand what's going on there. So, first of all, we create an &lt;em&gt;element&lt;/em&gt; (it doesn't require to be &lt;code&gt;new Image()&lt;/code&gt;, I think &lt;code&gt;new Audio()&lt;/code&gt; would work just as well), we use &lt;code&gt;Object.defineProperty&lt;/code&gt; to define the &lt;code&gt;id&lt;/code&gt; property of the &lt;em&gt;element&lt;/em&gt; and add a &lt;em&gt;function callback&lt;/em&gt; on &lt;code&gt;get&lt;/code&gt;. Pretty clever, right? Now every time when the &lt;em&gt;element.id&lt;/em&gt; is taken, the &lt;em&gt;callback function&lt;/em&gt; will run - that's what we need, put there the functions to run when &lt;em&gt;chrome dev tools&lt;/em&gt; will be opened.&lt;/p&gt;

&lt;p&gt;So the interesting part is the last line, why &lt;em&gt;callback function&lt;/em&gt; is not running if the &lt;code&gt;console.log&lt;/code&gt; is already called which means &lt;em&gt;element.id&lt;/em&gt; as well? Well, it's not true, &lt;code&gt;console.log&lt;/code&gt; is called &lt;strong&gt;only&lt;/strong&gt; when &lt;strong&gt;chrome dev console tool&lt;/strong&gt; is opened which tries to &lt;code&gt;log&lt;/code&gt; &lt;em&gt;element&lt;/em&gt; as well as &lt;code&gt;id&lt;/code&gt; &lt;em&gt;property&lt;/em&gt; - and what's happening when &lt;code&gt;id&lt;/code&gt; &lt;em&gt;property&lt;/em&gt; is taken? Right, it triggers the (&lt;code&gt;get&lt;/code&gt;) callback function.&lt;/p&gt;

&lt;p&gt;Do you know other tricks that nowadays really work? Share them with us, I'll include in this article.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>JavaScript Countdown, is it that simple?</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Tue, 25 Jun 2019 14:19:07 +0000</pubDate>
      <link>https://dev.to/wanoo21/javascript-countdown-is-it-that-simple-31ge</link>
      <guid>https://dev.to/wanoo21/javascript-countdown-is-it-that-simple-31ge</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1523350703530-161b46e28e24%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1523350703530-161b46e28e24%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="JavaScript Countdown, is it that simple?" width="1080" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes writing a simple &lt;strong&gt;countdown timer&lt;/strong&gt; is not so simple as it looks. You must play with “new Date” almost as an expert, and not every time you will have the preferred result. Fortunately, there are plenty of countdown plugins for JavaScript on the npm registry, and now I want to show you one of them.&lt;/p&gt;

&lt;p&gt;I believe the future of javascript is within &lt;strong&gt;Web Components&lt;/strong&gt; so each plugin which is created nowadays should support the standards of Web Components. These being said, I have chosen this cool &lt;a href="https://www.webcomponents.org/element/@wanoo21/countdown-time" rel="noopener noreferrer"&gt;countdown time plugin&lt;/a&gt;, and yes, it’s made by me.&lt;/p&gt;

&lt;p&gt;Before showing some great examples, I’m going to explain to you more specifically the installing methods and what properties and methods does he have. So let’s dive into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Countdown into your project
&lt;/h2&gt;

&lt;p&gt;There are 2 simple ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Through script tag in the head section - this is the best and easy way! Please be aware that the current version in 1.2.0, you should include the latest version at this time.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://unpkg.com/@wanoo21/countdown-time@1.2.0/dist/countdown-time.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Through npm package - This solution is best for actual frameworks, like &lt;strong&gt;Vue, Angular or React&lt;/strong&gt; and not only, you can use it with &lt;strong&gt;Vanilla JS&lt;/strong&gt; as well.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm install @wanoo21/countdown-time&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Import it &lt;code&gt;import “@wanoo21/countdown-time”&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then include &lt;code&gt;&amp;lt;countdown-time&amp;gt;&amp;lt;/countdown-time&amp;gt;&lt;/code&gt; element anywhere in your template, JSX, HTML, etc to show a countdown timer. Of course, you must add some properties in order to start it, about them we are talking in the next section.&lt;/p&gt;

&lt;p&gt;P.S. It supports &lt;strong&gt;TypeScript&lt;/strong&gt; , Thanks &lt;a href="https://stenciljs.com/" rel="noopener noreferrer"&gt;StencilJS&lt;/a&gt; for such a good opportunity!&lt;/p&gt;

&lt;h2&gt;
  
  
  Countdown Properties [Attributes]
&lt;/h2&gt;

&lt;p&gt;It has five custom properties, let’s see what they are and what they represent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[autostart]&lt;/code&gt; - Whether start or not when the countdown is ready, if not, you must start it manually, default is &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[datetime]&lt;/code&gt; - DateTime to countdown, must be a valid date represented by &lt;strong&gt;string&lt;/strong&gt; or &lt;strong&gt;number&lt;/strong&gt; , ex: &lt;code&gt;Date.now()&lt;/code&gt;, default is &lt;code&gt;Date.now()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[add]&lt;/code&gt; - Add more time to current DateTime separated by spaces, ex: add="1h 30m" - this will add 1 hour and 30 minutes to &lt;code&gt;datetime&lt;/code&gt; time, by default this attribute is empty.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/wanoo21/embed/RzZRWE/?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;[format]&lt;/code&gt; - Use this attribute to change the showing format, ex: “{m}min. and {s}sec.”, default is “{h}:{m}:{s}”. These placeholders are available:

&lt;ol&gt;
&lt;li&gt;{w} - number of weeks.&lt;/li&gt;
&lt;li&gt;{d} - number of days.&lt;/li&gt;
&lt;li&gt;{h} - number of hours.&lt;/li&gt;
&lt;li&gt;{m} - number of minutes.&lt;/li&gt;
&lt;li&gt;{s} - number of seconds.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/wanoo21/embed/orexOE/?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;[utc]&lt;/code&gt; - Using this attribute you will convert the &lt;code&gt;datetime&lt;/code&gt; time to UTC format, default is &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/wanoo21/embed/QXMEdN/?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Countdown Methods
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;getCountDownTime() =&amp;gt; Promise&amp;lt;ITimeObject&amp;gt;&lt;/code&gt; - Get a Promise of &lt;code&gt;ITimeObject&lt;/code&gt; which has &lt;code&gt;{ weeks: string; days: string; hours: string; minutes: string; seconds: string; }&lt;/code&gt; properties.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;restart() =&amp;gt; Promise&amp;lt;void&amp;gt;&lt;/code&gt; - Restart countdown.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setAsExpired() =&amp;gt; Promise&amp;lt;void&amp;gt;&lt;/code&gt; - Set as expired, this action will stop and call &lt;code&gt;expire&lt;/code&gt; custom event.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;start() =&amp;gt; Promise&amp;lt;void&amp;gt;&lt;/code&gt; - Start countdown, &lt;code&gt;autostart&lt;/code&gt; attribute is doing the same action.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stop() =&amp;gt; Promise&amp;lt;void&amp;gt;&lt;/code&gt; - Stop countdown, this action will stop countdown, but won’t call &lt;code&gt;expired&lt;/code&gt; custom event.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Countdown Events [CustomEvents]
&lt;/h2&gt;

&lt;p&gt;There are two custom events, &lt;code&gt;expire&lt;/code&gt; and &lt;code&gt;ready&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;expire&lt;/code&gt; - Is emitted when the countdown expires.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ready&lt;/code&gt; - Is emitted when the countdown is ready to start.
Both of them return &lt;code&gt;CustomEvent&amp;lt;void&amp;gt;&lt;/code&gt;. See some examples:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/wanoo21/embed/OejRyb/?height=600&amp;amp;default-tab=js,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Available 'Slots'
&lt;/h2&gt;

&lt;p&gt;There is an option to hide or show some content based on the current countdown’s state. Add any content inside &lt;code&gt;&amp;lt;countdown-time&amp;gt;&amp;lt;/countdown-time&amp;gt;&lt;/code&gt; and add the following attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[show-on-expired]&lt;/code&gt; - Show this element only when the countdown expired.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[hide-on-expired]&lt;/code&gt; - Show this element only when the countdown is running and hide it when it is expired.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/wanoo21/embed/WqEoxL/?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Not bad, huh? With some simple steps, you can have a plain and powerful countdown timer in your site. Try to play with it and tell me what you think, is it compatible with your ideas?&lt;/p&gt;

</description>
      <category>stencil</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Difference between encodeURI and encodeURIComponent</title>
      <dc:creator>Ion Prodan</dc:creator>
      <pubDate>Fri, 15 Mar 2019 12:08:57 +0000</pubDate>
      <link>https://dev.to/wanoo21/difference-between-encodeuri-and-encodeuricomponent-j3j</link>
      <guid>https://dev.to/wanoo21/difference-between-encodeuri-and-encodeuricomponent-j3j</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxwi8quj9qi4bkolj697.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxwi8quj9qi4bkolj697.png" alt="Difference between encodeURI and encodeURIComponent" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was pretty sure I'm using &lt;strong&gt;encodeURI&lt;/strong&gt; and &lt;strong&gt;encodeURIComponent&lt;/strong&gt; rightly till I faced a big problem! LOL 😂. When I solved my issue, I finally understood what's the difference between them. So let's find out!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are they
&lt;/h2&gt;

&lt;p&gt;As you may know, in javascript &lt;strong&gt;encodeURI&lt;/strong&gt; and &lt;strong&gt;encodeURIComponent&lt;/strong&gt; are used to encode &lt;em&gt;Uniform Resource Identifier&lt;/em&gt; (URI) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character. (MDN)&lt;/p&gt;

&lt;h2&gt;
  
  
  The difference
&lt;/h2&gt;

&lt;p&gt;There aren't big differences, the unique difference is that encodeURI() function encodes &lt;em&gt;special characters&lt;/em&gt;, except: &lt;code&gt;, / ? : @ &amp;amp; = + $ #&lt;/code&gt; whereas encodeURIComponent() function encodes &lt;em&gt;special characters&lt;/em&gt; and in &lt;strong&gt;additional the characters which encodeURI doesn't encode&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  When and what to use
&lt;/h2&gt;

&lt;p&gt;If you're encoding a string to put in a URL component (a query string parameter), you should use &lt;strong&gt;encodeURIComponent&lt;/strong&gt;, and if you're encoding an existing URL, use &lt;strong&gt;encodeURI&lt;/strong&gt;. It's simple! 😎&lt;/p&gt;

&lt;h3&gt;
  
  
  Some references:
&lt;/h3&gt;

&lt;p&gt;MDN &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent" rel="noopener noreferrer"&gt;encodeURIComponent&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
MDN &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI" rel="noopener noreferrer"&gt;encodeURI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have you had any bad experiences with them by now?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
