<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://davdifr.com/</id>
  <title>Davide Di Francesco</title>
  <subtitle>Personal site of Davide Di Francesco, a frontend developer working with Angular, TypeScript and RxJS — notes on front-end architecture and AI-assisted coding.</subtitle>
  <updated>2026-10-28T23:48:39+01:00</updated>
  <author>
    <name>Davide Di Francesco</name>
    <uri>https://davdifr.com/</uri>
  </author>
  <link rel="self" type="application/atom+xml" href="https://davdifr.com/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://davdifr.com/blog/"/>
  <entry>
    <title>Vibecoding in Practice: Building SortDocs with AI</title>
    <link href="https://davdifr.com/posts/building-sortdocs/"/>
    <id>https://davdifr.com/posts/building-sortdocs/</id>
    <published>2026-03-26T00:00:00+01:00</published>
    <updated>2026-03-26T00:00:00+01:00</updated>
    <category term="AI Development"/>
    <category term="Coding Experiments"/>
    <summary>A while ago, I started experimenting with vibecoding — building software by relying mostly on AI prompts instead of manually writing every part of the code.</summary>
    <content type="html">&lt;p&gt;A while ago, I started experimenting with &lt;strong&gt;vibecoding&lt;/strong&gt; — building software by relying mostly on AI prompts instead of manually writing every part of the code.&lt;/p&gt;

&lt;p&gt;My first experiment was playful: a small multiplayer 3D prototype. It was useful mostly because it showed me both sides of the workflow: AI could get me surprisingly far, but it could also break things just as quickly.&lt;/p&gt;

&lt;p&gt;This time, I wanted to try the same mindset on something more practical.&lt;/p&gt;

&lt;p&gt;Not a demo.&lt;br /&gt;
Not a toy.&lt;br /&gt;
A tool I could actually use.&lt;/p&gt;

&lt;p&gt;That’s how &lt;strong&gt;sortdocs&lt;/strong&gt; was born.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href=&quot;https://github.com/davdifr/sortdocs&quot;&gt;https://github.com/davdifr/sortdocs&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-idea&quot;&gt;The Idea&lt;/h2&gt;

&lt;p&gt;Like many people, I have folders that slowly turn into chaos.&lt;/p&gt;

&lt;p&gt;Downloads, PDFs, markdown notes, screenshots, scanned documents, text files — everything accumulates in the same place until finding anything becomes annoying.&lt;/p&gt;

&lt;p&gt;So the idea was simple:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Could I build a tool that organizes local documents safely, using AI to understand what the files actually are?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That last part mattered a lot.&lt;/p&gt;

&lt;p&gt;I did &lt;strong&gt;not&lt;/strong&gt; want a sorter that only looks at file extensions. I wanted something that could make better decisions by using a mix of:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;file content&lt;/li&gt;
  &lt;li&gt;metadata&lt;/li&gt;
  &lt;li&gt;AI-powered classification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That requirement shaped the whole project.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-sortdocs-actually-does&quot;&gt;What SortDocs Actually Does&lt;/h2&gt;

&lt;p&gt;At a high level, the workflow is intentionally simple:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Move into the folder you want to organize&lt;/li&gt;
  &lt;li&gt;Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sortdocs .&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Let the tool scan recursively and build a plan&lt;/li&gt;
  &lt;li&gt;Review the plan&lt;/li&gt;
  &lt;li&gt;Confirm the changes only if they make sense&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That “plan first, apply second” approach was one of the most important parts of the project.&lt;/p&gt;

&lt;p&gt;I didn’t want an AI tool making filesystem changes without showing its reasoning through actual proposed actions.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;first-look-at-the-cli&quot;&gt;First Look at the CLI&lt;/h2&gt;

&lt;p&gt;Here’s what the CLI experience looks like when running a scan and reviewing the plan:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/sortdocs/cli.png&quot; alt=&quot;SortDocs CLI Screenshot&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-this-was-a-better-vibecoding-test&quot;&gt;Why This Was a Better Vibecoding Test&lt;/h2&gt;

&lt;p&gt;Compared to my earlier vibecoding experiments, this project felt more realistic from the start.&lt;/p&gt;

&lt;p&gt;A game prototype is fun, but a document organizer forces you to deal with more practical concerns:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;safe file operations&lt;/li&gt;
  &lt;li&gt;ambiguity&lt;/li&gt;
  &lt;li&gt;naming collisions&lt;/li&gt;
  &lt;li&gt;bad input data&lt;/li&gt;
  &lt;li&gt;project folder protection&lt;/li&gt;
  &lt;li&gt;repeat runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That made it a much better test of whether AI could help build something I would genuinely trust on my machine.&lt;/p&gt;

&lt;p&gt;And trust was the key word here.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;starting-with-the-cli&quot;&gt;Starting with the CLI&lt;/h2&gt;

&lt;p&gt;I started from the smallest useful version: a terminal command that could analyze a target folder and propose actions.&lt;/p&gt;

&lt;p&gt;Very early on, the shape of the product became a CLI instead of a full UI-first app. That choice made iteration faster and kept the project focused on the core pipeline:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;scan → extract → classify → plan → execute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A CLI removes distractions. If the core logic works there, everything else can come later.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-core-challenge-understanding-files-not-just-extensions&quot;&gt;The Core Challenge: Understanding Files, Not Just Extensions&lt;/h2&gt;

&lt;p&gt;One of the most interesting parts of sortdocs is that it is not meant to be a dumb file sorter.&lt;/p&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pdf&lt;/code&gt; could be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;an invoice&lt;/li&gt;
  &lt;li&gt;a manual&lt;/li&gt;
  &lt;li&gt;a contract&lt;/li&gt;
  &lt;li&gt;a scanned document&lt;/li&gt;
  &lt;li&gt;or something with almost no readable content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the problem was never just “where should &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pdf&lt;/code&gt; files go?”&lt;/p&gt;

&lt;p&gt;The real question was:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;How can the tool infer a reasonable destination from incomplete evidence?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That led to a more layered approach:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;extract what can be extracted&lt;/li&gt;
  &lt;li&gt;use metadata where useful&lt;/li&gt;
  &lt;li&gt;classify with AI&lt;/li&gt;
  &lt;li&gt;lower confidence when evidence is weak&lt;/li&gt;
  &lt;li&gt;fall back conservatively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the tool is uncertain, it should become &lt;strong&gt;more careful&lt;/strong&gt;, not more creative.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;building-guardrails-early&quot;&gt;Building Guardrails Early&lt;/h2&gt;

&lt;p&gt;This was probably the most important lesson of the whole project.&lt;/p&gt;

&lt;p&gt;When you let AI help build a tool that touches the filesystem, guardrails are not a polish step. They are the product.&lt;/p&gt;

&lt;p&gt;SortDocs includes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;confirmation before applying changes&lt;/li&gt;
  &lt;li&gt;rename and extension safeguards&lt;/li&gt;
  &lt;li&gt;collision handling&lt;/li&gt;
  &lt;li&gt;project-folder protection&lt;/li&gt;
  &lt;li&gt;ignore rules&lt;/li&gt;
  &lt;li&gt;conservative fallback behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where the project stopped feeling like a prototype and started feeling like real software.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;project-folder-protection&quot;&gt;Project Folder Protection&lt;/h2&gt;

&lt;p&gt;One feature I particularly like is protecting software projects by default.&lt;/p&gt;

&lt;p&gt;If the root folder looks like a project, the tool blocks execution. Nested project folders like Git repos, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.venv&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dist&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; are skipped automatically.&lt;/p&gt;

&lt;p&gt;If the user really wants to run it anyway, they must explicitly opt in.&lt;/p&gt;

&lt;p&gt;This is a small detail, but it says a lot about the philosophy of the tool:&lt;/p&gt;

&lt;p&gt;It prefers being safe over being clever.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;improving-repeat-runs&quot;&gt;Improving Repeat Runs&lt;/h2&gt;

&lt;p&gt;Another important aspect was handling repeated usage.&lt;/p&gt;

&lt;p&gt;Many prototypes work once but break in real-world scenarios.&lt;/p&gt;

&lt;p&gt;SortDocs adds:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;local memory to improve consistency&lt;/li&gt;
  &lt;li&gt;incremental cache for unchanged files&lt;/li&gt;
  &lt;li&gt;automatic invalidation when configs change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means unchanged files can skip processing entirely on later runs.&lt;/p&gt;

&lt;p&gt;Less flashy than AI — but much more useful.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;onboarding-matters-more-than-expected&quot;&gt;Onboarding Matters More Than Expected&lt;/h2&gt;

&lt;p&gt;One thing I’ve learned is that onboarding often matters more than the core logic.&lt;/p&gt;

&lt;p&gt;If the OpenAI API key is missing, the tool:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;shows a guided setup&lt;/li&gt;
  &lt;li&gt;allows pasting the key directly in the terminal&lt;/li&gt;
  &lt;li&gt;explains how to generate it&lt;/li&gt;
  &lt;li&gt;optionally saves it locally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, it feels like a repo.&lt;br /&gt;
With it, it feels like a product.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-optional-gui&quot;&gt;The Optional GUI&lt;/h2&gt;

&lt;p&gt;Originally, the project was CLI-first.&lt;/p&gt;

&lt;p&gt;Later, it evolved into an optional macOS GUI using PySide6.&lt;/p&gt;

&lt;p&gt;Here’s a preview of the GUI showing the planned actions before applying changes:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/sortdocs/gui.png&quot; alt=&quot;SortDocs GUI Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The GUI includes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;folder selection&lt;/li&gt;
  &lt;li&gt;API key setup&lt;/li&gt;
  &lt;li&gt;live analysis progress&lt;/li&gt;
  &lt;li&gt;preview of planned actions&lt;/li&gt;
  &lt;li&gt;detailed decision view&lt;/li&gt;
  &lt;li&gt;confirmation before applying changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI is still the core, but the GUI makes it more approachable.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-vibecoding-helped-the-most&quot;&gt;Where Vibecoding Helped the Most&lt;/h2&gt;

&lt;p&gt;AI was especially helpful for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;scaffolding the CLI&lt;/li&gt;
  &lt;li&gt;iterating on logic&lt;/li&gt;
  &lt;li&gt;handling edge cases&lt;/li&gt;
  &lt;li&gt;improving UX flows&lt;/li&gt;
  &lt;li&gt;speeding up repetitive work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest gains came from using it on &lt;strong&gt;small, well-defined problems&lt;/strong&gt;, not from asking it to build everything at once.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-it-still-needed-direction&quot;&gt;Where It Still Needed Direction&lt;/h2&gt;

&lt;p&gt;AI still needed strong guidance on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;how conservative the tool should be&lt;/li&gt;
  &lt;li&gt;how to handle uncertainty&lt;/li&gt;
  &lt;li&gt;acceptable risk levels&lt;/li&gt;
  &lt;li&gt;product decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not coding problems. They are product decisions.&lt;/p&gt;

&lt;p&gt;AI accelerates implementation — but it doesn’t replace judgment.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;SortDocs ended up being a much better vibecoding experiment than I expected.&lt;/p&gt;

&lt;p&gt;Not because it’s complex.&lt;br /&gt;
But because it’s useful.&lt;/p&gt;

&lt;p&gt;It forced me to focus on something more important than generation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;reliability.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this point, I don’t see vibecoding as “letting AI build everything.”&lt;/p&gt;

&lt;p&gt;I see it as collaboration:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I define constraints&lt;/li&gt;
  &lt;li&gt;AI accelerates implementation&lt;/li&gt;
  &lt;li&gt;I guide the decisions&lt;/li&gt;
  &lt;li&gt;safety defines the quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SortDocs is probably the clearest example I have so far of that balance.&lt;/p&gt;

&lt;p&gt;It started as an experiment.&lt;br /&gt;
It became a real tool.&lt;/p&gt;

&lt;p&gt;And more than anything else, it showed me this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;AI is most useful when paired with strong guardrails — not blind trust.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>Vibecoding, One Year Later: Trying the Same Multiplayer Prototype Again</title>
    <link href="https://davdifr.com/posts/vibecoding-one-year-later/"/>
    <id>https://davdifr.com/posts/vibecoding-one-year-later/</id>
    <published>2026-03-16T00:00:00+01:00</published>
    <updated>2026-03-16T00:00:00+01:00</updated>
    <category term="AI Development"/>
    <category term="Coding Experiments"/>
    <category term="Game Development"/>
    <summary>A year ago, I tried a simple experiment: build a small real-time 3D multiplayer app by relying almost entirely on AI prompts instead of writing the code myself. Back then, the best setup I had for that kind of workflow was GitHub Copilot with Claude 3.7, and while the result was honestly impressive, the whole process was still pretty rough around the edges.</summary>
    <content type="html">&lt;p&gt;A year ago, I tried a simple experiment: build a small real-time 3D multiplayer app by relying almost entirely on AI prompts instead of writing the code myself. Back then, the best setup I had for that kind of workflow was GitHub Copilot with Claude 3.7, and while the result was honestly impressive, the whole process was still pretty rough around the edges.&lt;/p&gt;

&lt;p&gt;It worked, but it also broke in annoying ways. New features often meant new bugs, and a lot of the progress came from prompting the model again and again until things stopped falling apart.&lt;/p&gt;

&lt;p&gt;This time, I wanted to try the same idea again with gpt 5.3-codex.&lt;/p&gt;

&lt;p&gt;More than the final result, I was curious about the overall experience. Is it actually better now? Does it need less hand-holding? Can it make decent decisions on its own, or does it still need to be dragged through every step?&lt;/p&gt;

&lt;h2 id=&quot;starting-from-the-same-prompt&quot;&gt;Starting from the same prompt&lt;/h2&gt;

&lt;p&gt;To keep the comparison fair, I started with almost the same prompt I used last year:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I want to create a real-time interactive 3D web application. The project should feature a simple multiplayer environment where multiple users can connect, move a 3D object in real-time, and see updates from others instantly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only real difference is that this time I left out the stack. Last year, I explicitly mentioned Three.js and Socket.IO in the prompt; this time I wanted to see what the model would do without that hint.&lt;/p&gt;

&lt;h2 id=&quot;the-first-interesting-difference&quot;&gt;The first interesting difference&lt;/h2&gt;

&lt;p&gt;Right away, the model did something I thought was worth noting: instead of immediately generating code, it proposed two implementation paths.&lt;/p&gt;

&lt;p&gt;One was a simple Node.js + Express + Socket.IO + Three.js setup, which it also recommended. The other was a slightly more structured option with Vite on the frontend and a separate WebSocket server.&lt;/p&gt;

&lt;p&gt;I went with the first one, mostly because it matched the setup I had used last year anyway, when I explicitly asked for Three.js and Socket.IO. So even without me naming the tools this time, it still landed in roughly the same place.&lt;/p&gt;

&lt;p&gt;That may sound like a small detail, but to me it already felt different. Last year, I had to define the direction. This time, the model got there on its own.&lt;/p&gt;

&lt;h2 id=&quot;first-result&quot;&gt;First result&lt;/h2&gt;

&lt;p&gt;The first result was also very familiar.&lt;/p&gt;

&lt;p&gt;Just like in the original experiment, it quickly produced a minimal 3D multiplayer scene with simple player objects moving around in a shared space. If you put the two versions side by side, the overall idea is basically the same.&lt;/p&gt;

&lt;p&gt;Still, this one felt a little more put together from the start. Not dramatically different, just cleaner.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-one-year-later/initial-prototype.png&quot; alt=&quot;Initial prototype&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What really stood out, though, was what happened next. Instead of stopping after the first working prototype, the model suggested a few logical next steps on its own: nicknames above players, room/lobby support, simple collisions, and even one-click deploy options.&lt;/p&gt;

&lt;p&gt;That caught my attention because some of those were exactly the kind of things that only came later in last year’s experiment, after several additional prompts.&lt;/p&gt;

&lt;h2 id=&quot;letting-it-keep-going&quot;&gt;Letting it keep going&lt;/h2&gt;

&lt;p&gt;At that point, I decided not to over-direct it.&lt;/p&gt;

&lt;p&gt;Instead of rewriting its plan in my own words, I just replied:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sounds good, please go ahead with the suggested implementations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was intentional. I wanted to see what happened if I stopped acting like a prompt micromanager and just approved the direction.&lt;/p&gt;

&lt;h2 id=&quot;faster-than-last-year&quot;&gt;Faster than last year&lt;/h2&gt;

&lt;p&gt;This is where the comparison started to get interesting.&lt;/p&gt;

&lt;p&gt;After the initial prompt and that one short confirmation, the project already had player nicknames, a simple lobby flow, basic room support, lightweight collisions, deploy config for Render and Railway, and updated documentation.&lt;/p&gt;

&lt;p&gt;That is a lot of ground to cover in basically two interactions.&lt;/p&gt;

&lt;p&gt;In the original experiment, getting to a similar level took more back-and-forth. I had to add features one by one, deal with breakages, and keep nudging the model back into shape as new problems appeared.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-one-year-later/lobby-nickname-collision.gif&quot; alt=&quot;Lobby / nickname / collision&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This time, the prototype started to feel usable much earlier.&lt;/p&gt;

&lt;h2 id=&quot;adding-chat&quot;&gt;Adding chat&lt;/h2&gt;

&lt;p&gt;To keep the comparison going, I reused one of the same prompts from the original article:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Implement a real-time chat system with global and private messaging. The UI should feature a tabbed chat system at the bottom of the screen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last year, this was one of the points where things got messy. The feature itself worked, but it also came with several issues: the chat UI was not always in the foreground, the username input was awkward, typing could still move the player, and the generation even hit a time limit before I had to resend the prompt.&lt;/p&gt;

&lt;p&gt;This time, the chat was added immediately and it worked much better right away.&lt;/p&gt;

&lt;p&gt;The interface was already there, the basic behavior was correct, and, maybe most importantly, none of the prompts up to this point had produced actual code errors.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-one-year-later/chat.gif&quot; alt=&quot;Chat system&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That changes the feel of the whole workflow more than I expected. A year ago, every new feature felt like a mix of progress and recovery. This time, it mostly just felt like progress.&lt;/p&gt;

&lt;h2 id=&quot;what-feels-different&quot;&gt;What feels different&lt;/h2&gt;

&lt;p&gt;So far, the biggest improvement is not that the model is doing something completely different.&lt;/p&gt;

&lt;p&gt;It is more that the whole loop feels less fragile.&lt;/p&gt;

&lt;p&gt;Last year, I spent a lot of time fixing weird side effects, recovering from regressions, and re-prompting around things that had almost worked but not quite. This time, the defaults have been better, the proposed next steps have made more sense, and the implementation has been much smoother overall.&lt;/p&gt;

&lt;p&gt;That does not mean the model can just be left alone. I am still reviewing every step, and I am still working within a fairly controlled scope. But the role feels different now. I am spending less time rescuing the process and more time deciding where to take it next.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;Repeating the same experiment after a year has been useful for one simple reason: it removes a lot of the novelty.&lt;/p&gt;

&lt;p&gt;Because the project is so similar, the differences are easier to notice.&lt;/p&gt;

&lt;p&gt;The biggest one so far is reliability. In the first experiment, I could already see why vibecoding was exciting, but I also had to wrestle with it constantly to keep things moving. In this version, the model has been better at choosing a reasonable stack, suggesting sensible next steps, and implementing features without immediately creating new problems.&lt;/p&gt;

&lt;p&gt;I would not call this autonomous software development, and I still would not trust it blindly. The project is small, the scope is controlled, and I am still the one judging every result.&lt;/p&gt;

&lt;p&gt;But compared to where this felt a year ago, the workflow is clearly more usable.&lt;/p&gt;

&lt;p&gt;Last year, it felt like an interesting experiment. This time, it feels a lot closer to something I could actually use on purpose.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Vibecoding: Letting AI Code for Me</title>
    <link href="https://davdifr.com/posts/vibecoding-let-ai-code-for-me/"/>
    <id>https://davdifr.com/posts/vibecoding-let-ai-code-for-me/</id>
    <published>2025-03-10T00:00:00+01:00</published>
    <updated>2025-03-12T02:24:47+01:00</updated>
    <category term="AI Development"/>
    <category term="Coding Experiments"/>
    <category term="Game Development"/>
    <summary>A friend recently introduced me to vibecoding—a concept where AI handles all the coding, relying solely on prompts.</summary>
    <content type="html">&lt;p&gt;A friend recently introduced me to &lt;strong&gt;vibecoding&lt;/strong&gt;—a concept where AI handles all the coding, relying solely on prompts.&lt;/p&gt;

&lt;p&gt;Despite the obvious limitations, my curiosity as a tech enthusiast got the best of me. With social media buzzing about it, I saw an opportunity to connect with other developers and challenge myself in a new way. The idea of pushing AI to its limits without writing a single line of code was too intriguing to ignore.&lt;/p&gt;

&lt;h2 id=&quot;setting-the-stage&quot;&gt;Setting the Stage&lt;/h2&gt;

&lt;p&gt;Before diving in, I needed to decide on a project—something practical yet simple enough for AI to handle. I also set a few ground rules:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;No manual coding—only AI-generated code.&lt;/li&gt;
  &lt;li&gt;Minimal editing—syntax fixes allowed, no major rewrites.&lt;/li&gt;
  &lt;li&gt;If AI got stuck, I had to prompt my way out.&lt;/li&gt;
  &lt;li&gt;The entire process should take no more than a couple of hours.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With that, I opened my AI coding assistant and got to work.&lt;/p&gt;

&lt;h2 id=&quot;the-experiment&quot;&gt;The Experiment&lt;/h2&gt;

&lt;h3 id=&quot;choosing-the-right-tools&quot;&gt;Choosing the Right Tools&lt;/h3&gt;

&lt;p&gt;I first tried &lt;strong&gt;Cursor&lt;/strong&gt;, an AI-powered editor, but it felt too much like a modded VS Code. Instead, I opted for &lt;strong&gt;GitHub Copilot&lt;/strong&gt; paired with &lt;strong&gt;Claude 3.7&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;picking-a-project&quot;&gt;Picking a Project&lt;/h3&gt;

&lt;p&gt;Scrolling through &lt;strong&gt;X&lt;/strong&gt;, I noticed many vibecoding projects focused on game development, particularly with &lt;strong&gt;Three.js&lt;/strong&gt; for 3D models. That seemed like a great challenge! So, I decided to build a &lt;strong&gt;3D multiplayer game&lt;/strong&gt; with real-time interactions via &lt;strong&gt;Socket.IO&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;first-steps&quot;&gt;First Steps&lt;/h3&gt;

&lt;p&gt;I started with this prompt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I want to create a real-time interactive 3D web application using Three.js and Socket.IO. The project should feature a simple multiplayer environment where multiple users can connect, move a 3D object in real-time, and see updates from others instantly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI generated a basic &lt;strong&gt;3D cube&lt;/strong&gt; on a plane, movable with &lt;strong&gt;WASD&lt;/strong&gt; keys, and even included a user counter.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/first-prompt.png&quot; alt=&quot;VS Code AI Prompt Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/first-result.gif&quot; alt=&quot;Project Running Screenshot&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;adding-a-chat-system&quot;&gt;Adding a Chat System&lt;/h3&gt;

&lt;p&gt;Next, I prompted the AI to implement a real-time chat system:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Implement a real-time chat system with global and private messaging. The UI should feature a tabbed chat system at the bottom of the screen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I worried about AI struggling with the &lt;strong&gt;tabbed UI&lt;/strong&gt;, and sure enough, it hit a &lt;strong&gt;time limit error&lt;/strong&gt;. I simply resubmitted the same prompt, and it picked up where it left off.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/first-chat-result.gif&quot; alt=&quot;Chat System Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The chat worked, but had a few quirks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The chat UI didn’t always stay in the foreground.&lt;/li&gt;
  &lt;li&gt;A misplaced username input field.&lt;/li&gt;
  &lt;li&gt;Typing in chat also moved the player (&lt;strong&gt;WASD&lt;/strong&gt; issue).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;refining-the-chat-system&quot;&gt;Refining the Chat System&lt;/h3&gt;

&lt;p&gt;I refined my prompt to address these issues:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The chat system is functional, but I need the following fixes:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Remove any button that toggles chat visibility.&lt;/li&gt;
    &lt;li&gt;Prompt users for a username at startup instead of placing an input field in the chat.&lt;/li&gt;
    &lt;li&gt;Prevent movement while typing in chat.&lt;/li&gt;
    &lt;li&gt;Re-enable movement when clicking outside the input.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;After applying fixes, I noticed a critical issue—&lt;strong&gt;players disappeared upon joining&lt;/strong&gt;. So I prompted:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Fix the issue where players are not visible after entering the game.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This restored proper rendering.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/player-and-chat-fix.gif&quot; alt=&quot;Player and Chat Fix&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;refactoring-the-code-structure&quot;&gt;Refactoring the Code Structure&lt;/h3&gt;

&lt;p&gt;The project was running from just three files—&lt;strong&gt;index.html, server.js, and game.js&lt;/strong&gt;—which made maintenance difficult. I prompted AI to split the code into multiple files following best practices.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/directory-structure.png&quot; alt=&quot;Directory Structure&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;expanding-the-game-area&quot;&gt;Expanding the Game Area&lt;/h3&gt;

&lt;p&gt;The playable area was too small. I asked AI to:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Expand the game area and add a boundary to prevent players from going beyond it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It responded by:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Increasing world size from &lt;strong&gt;20 to 40 units&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Adding semi-transparent boundary walls.&lt;/li&gt;
  &lt;li&gt;Restricting movement beyond limits.&lt;/li&gt;
  &lt;li&gt;Displaying a warning message near edges.&lt;/li&gt;
  &lt;li&gt;Implementing server-side validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/boundary-walls.gif&quot; alt=&quot;Boundary Walls&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;fixing-multiplayer-visibility-bug&quot;&gt;Fixing Multiplayer Visibility Bug&lt;/h3&gt;

&lt;p&gt;New players weren’t visible to those already connected. I prompted:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ensure that all connected users see new players upon joining.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This restored proper synchronization.&lt;/p&gt;

&lt;h3 id=&quot;implementing-player-collision&quot;&gt;Implementing Player Collision&lt;/h3&gt;

&lt;p&gt;I wanted to prevent players from passing through each other:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Add a collision system so players cannot pass through each other. Ensure consistency across all clients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This worked, but introduced a weird bug—&lt;strong&gt;player colors changed on collision&lt;/strong&gt;. Additionally, colors appeared differently for each client. I fixed this with:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Keep player colors static. Ensure color consistency across all clients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;debugging-ai-mistakes&quot;&gt;Debugging AI Mistakes&lt;/h3&gt;

&lt;p&gt;AI sometimes introduced syntax errors. At one point, I encountered this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Uncaught ReferenceError: handleCurrentPlayers is not defined&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked AI to review and fix it, and it successfully debugged itself.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/auto-fix-misstypo.png&quot; alt=&quot;Auto Fix&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;improving-camera-behavior&quot;&gt;Improving Camera Behavior&lt;/h3&gt;

&lt;p&gt;By default, the camera didn’t follow the player, making navigation frustrating. I prompted:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ensure the camera stays centered on the player.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This small tweak greatly improved the experience.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/camera-movement.gif&quot; alt=&quot;Camera Movement&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;jump-mechanic--ui-improvements&quot;&gt;Jump Mechanic &amp;amp; UI Improvements&lt;/h3&gt;

&lt;p&gt;To enhance movement, I added jumping:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Implement a jump mechanic using the space bar. Prevent infinite jumping.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jumping worked flawlessly.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/jump.gif&quot; alt=&quot;Jump&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The UI also felt cluttered, so I requested:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Organize the UI:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Move the player count to the top-right.&lt;/li&gt;
    &lt;li&gt;Hide control hints behind a toggle button.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/vibecoding-let-ai-code-for-me/ui-adjustment.gif&quot; alt=&quot;UI Adjustments&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This experiment was surprisingly effective. While &lt;strong&gt;AI-generated code isn’t perfect&lt;/strong&gt;, its ability to &lt;strong&gt;iterate and self-correct&lt;/strong&gt; was impressive.&lt;/p&gt;

&lt;p&gt;The final product could be a great base for a &lt;strong&gt;.IO-style multiplayer game&lt;/strong&gt;, with mechanics like player growth and competitive elements.&lt;/p&gt;

&lt;p&gt;The most fascinating part? This was all built &lt;strong&gt;in two hours&lt;/strong&gt;. Manual coding would have taken far longer. Instead of focusing on syntax, I focused on &lt;strong&gt;iterating through AI-generated results&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While vibecoding has &lt;strong&gt;clear limitations&lt;/strong&gt;, it’s a powerful tool for rapid prototyping. Who knows? With more improvements, it could become an even stronger development method.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Universal Middleware for Any Function</title>
    <link href="https://davdifr.com/posts/universal-middleware-for-any-function/"/>
    <id>https://davdifr.com/posts/universal-middleware-for-any-function/</id>
    <published>2024-10-22T20:13:00+02:00</published>
    <updated>2024-10-22T20:13:00+02:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>Middleware functions are no longer limited to backend systems; they bring tremendous value to front-end applications like Angular as well. From logging and input validation to managing global states, middleware functions can significantly improve code reuse, maintainability, and readability.</summary>
    <content type="html">&lt;p&gt;Middleware functions are no longer limited to backend systems; they bring tremendous value to front-end applications like Angular as well. From logging and input validation to managing global states, middleware functions can significantly improve code reuse, maintainability, and readability.&lt;/p&gt;

&lt;p&gt;In this article, we’ll dive into how you can use higher-order functions (HOFs) to create universal middleware that can be applied to any function. We’ll focus on logging as a practical example, but this pattern can be extended to countless other scenarios.&lt;/p&gt;

&lt;h2 id=&quot;why-middleware&quot;&gt;Why Middleware?&lt;/h2&gt;
&lt;p&gt;In Angular, middleware functions can be incredibly useful for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Logging&lt;/li&gt;
  &lt;li&gt;Input validation&lt;/li&gt;
  &lt;li&gt;Handling global loading states&lt;/li&gt;
  &lt;li&gt;Automatic data saving (local/session storage)&lt;/li&gt;
  &lt;li&gt;Sanitizing inputs&lt;/li&gt;
  &lt;li&gt;Feature flags and A/B testing&lt;/li&gt;
  &lt;li&gt;Caching&lt;/li&gt;
  &lt;li&gt;Batching function calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just a few examples where middleware can enhance your application’s logic without cluttering the core functionality of your code.&lt;/p&gt;

&lt;h2 id=&quot;the-challenge-consistent-logging&quot;&gt;The Challenge: Consistent Logging&lt;/h2&gt;
&lt;p&gt;Consistent logging is essential for debugging and understanding how data flows through your application. However, maintaining logging logic across various functions can result in repetitive and hard-to-manage code.&lt;/p&gt;

&lt;p&gt;Wouldn’t it be great if we could add logging universally, without touching every function individually? That’s where higher-order functions and middleware come to the rescue.&lt;/p&gt;

&lt;h2 id=&quot;the-solution-higher-order-functions-for-middleware&quot;&gt;The Solution: Higher-Order Functions for Middleware&lt;/h2&gt;
&lt;p&gt;A higher-order function (HOF) is a function that either takes other functions as arguments or returns a function. By using HOFs, we can apply middleware (such as logging) to any function in a reusable way.&lt;/p&gt;

&lt;p&gt;Here’s how it works:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Middleware&lt;/strong&gt; is simply a function that wraps another function, adding extra logic before and after the original function’s execution.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;applyMiddleware&lt;/strong&gt; is a higher-order function that can apply multiple middleware functions to any given function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;code-implementation&quot;&gt;Code Implementation&lt;/h2&gt;
&lt;p&gt;Let’s start with a logging middleware example:&lt;/p&gt;
&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;withLogging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extends &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Parameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Arguments:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Result:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isObservable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Result:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Result:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;explaining-withlogging&quot;&gt;Explaining &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;withLogging&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;withLogging&lt;/code&gt; function wraps any function (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt;) and logs both its arguments and return value.&lt;/li&gt;
  &lt;li&gt;It handles various types of results: synchronous values, Promises, and Observables.&lt;/li&gt;
  &lt;li&gt;If the result is an Observable, we use RxJS’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tap&lt;/code&gt; operator to log values as they are emitted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, we need a function to apply multiple middleware layers:&lt;/p&gt;
&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applyMiddleware&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extends &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;middlewares&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;middlewares&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;middleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;middleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;explaining-applymiddleware&quot;&gt;Explaining &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;applyMiddleware&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;This function takes a target function (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt;) and an array of middleware functions.&lt;/li&gt;
  &lt;li&gt;It sequentially applies each middleware, effectively wrapping the original function with additional logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;middleware-in-action&quot;&gt;Middleware in Action&lt;/h2&gt;
&lt;p&gt;Now that we’ve set up the middleware, let’s apply it to a simple function:&lt;/p&gt;
&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addWithLogging&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applyMiddleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;withLogging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;addWithLogging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Console output:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Arguments: [2, 3]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Result: 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With just a couple of lines, we’ve added logging to our add function without modifying its core logic. This is the magic of higher-order functions!&lt;/p&gt;

&lt;h2 id=&quot;why-use-middleware-in-angular&quot;&gt;Why Use Middleware in Angular?&lt;/h2&gt;
&lt;p&gt;By introducing middleware to your Angular app, you’ll gain multiple advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;No More Redundant Code&lt;/strong&gt;: Stop copying the same logging logic into every function.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cleaner Code&lt;/strong&gt;: Middleware allows functions to focus solely on their core purpose.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Consistent Debugging&lt;/strong&gt;: Centralized logging ensures that you have a uniform view of data flow across your application.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;DRY Principle&lt;/strong&gt;: Centralizing logic like logging, validation, and caching reduces code duplication and simplifies maintenance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;beyond-logging&quot;&gt;Beyond Logging&lt;/h2&gt;
&lt;p&gt;While we’ve demonstrated logging, the possibilities for middleware in Angular are endless. You could use this pattern for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Caching&lt;/strong&gt;: Cache results of expensive operations.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Debouncing API calls&lt;/strong&gt;: Delay and batch multiple calls to prevent unnecessary requests.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Apply global error handling without modifying each function.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Persistence&lt;/strong&gt;: Automatically save results to local or session storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key takeaway is that middleware makes your code more flexible and modular. You can enhance your functions without polluting their core logic.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Middleware is a pattern worth exploring for front-end development. By combining Angular with higher-order functions, you can implement reusable logic that will make your code cleaner, more maintainable, and scalable.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;A big thank you to &lt;a href=&quot;https://www.linkedin.com/in/roberto-heckers-2313453b/&quot;&gt;Roberto Heckers&lt;/a&gt; for his inspiration and reference code for the middleware implementation used in this article. His insights into higher-order functions have been a valuable resource for improving the way we write Angular code.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Conditional Routing in Angular with canMatch Guards</title>
    <link href="https://davdifr.com/posts/conditional-routing-in-angular-with-canmatch-guards/"/>
    <id>https://davdifr.com/posts/conditional-routing-in-angular-with-canmatch-guards/</id>
    <published>2024-10-02T20:06:00+02:00</published>
    <updated>2024-10-02T20:06:00+02:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>IntroductionRouting in Angular is essential for building feature-rich, user-friendly applications. Often, we need to conditionally load different components based on user-specific data, such as access levels, subscriptions, or even preferences. Angular’s canMatch guard provides a powerful way to control which routes are accessible by dynamically matching the route based on custom logic.</summary>
    <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Routing in Angular is essential for building feature-rich, user-friendly applications. Often, we need to conditionally load different components based on user-specific data, such as access levels, subscriptions, or even preferences. Angular’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; guard provides a powerful way to control which routes are accessible by dynamically matching the route based on custom logic.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; guard in Angular, with a practical example of showing different components based on user subscription status.&lt;/p&gt;

&lt;h2 id=&quot;what-is-canmatch&quot;&gt;What is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; guard in Angular allows you to dynamically control which route should be matched based on a function’s logic. Unlike &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canActivate&lt;/code&gt;, which decides whether a route can be activated, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; allows you to decide whether the route itself can be matched, before it’s even considered for activation.&lt;/p&gt;

&lt;h2 id=&quot;a-real-world-example-premium-content-access&quot;&gt;A Real-World Example: Premium Content Access&lt;/h2&gt;
&lt;p&gt;Let’s say we are building a video streaming platform, where some content is available only to users with a premium subscription. We want to ensure that premium users access a special component showing premium content, while regular users access a different component.&lt;/p&gt;

&lt;h2 id=&quot;step-1-defining-the-guard&quot;&gt;Step 1: Defining the Guard&lt;/h2&gt;
&lt;p&gt;We’ll create a guard function that checks the user’s subscription status using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubscriptionService&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isPremiumUserGuard&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canMatchFn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;segments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subscriptionService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SubscriptionService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subscriptionService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hasPremiumAccess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, we use Angular’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inject()&lt;/code&gt; function to access the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubscriptionService&lt;/code&gt;, which checks if the user has premium access.&lt;/p&gt;

&lt;h2 id=&quot;step-2-configuring-the-routes&quot;&gt;Step 2: Configuring the Routes&lt;/h2&gt;
&lt;p&gt;Now we set up our routes, ensuring that premium users access a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PremiumContentComponent&lt;/code&gt; and regular users access a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegularContentComponent&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;canMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isPremiumUserGuard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;loadComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./premium-content&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PremiumContentComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;loadComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./regular-content&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RegularContentComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this setup:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The first route will be matched if the user is a premium subscriber.&lt;/li&gt;
  &lt;li&gt;If the user doesn’t have premium access, the router falls back to the second route, loading the regular content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;why-use-canmatch-instead-of-canactivate&quot;&gt;Why Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; Instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canActivate&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;You might wonder why we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canActivate&lt;/code&gt;. The key difference is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; prevents the router from even considering a route if the guard returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canActivate&lt;/code&gt; still loads the route but decides whether or not to activate it. This makes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; more efficient for routes that should not even be matched in certain conditions.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; guard in Angular allows you to create dynamic and flexible routing based on user-specific data. Whether you’re managing subscription access, roles, or custom preferences, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canMatch&lt;/code&gt; gives you the power to control which components your users see, creating a smoother and more personalized experience.&lt;/p&gt;

</content>
  </entry>
  <entry>
    <title>Simplifying Angular Templates with combineLatest in NgRx</title>
    <link href="https://davdifr.com/posts/simplifying-angular-templates-with-combine-latest-in-ngrx/"/>
    <id>https://davdifr.com/posts/simplifying-angular-templates-with-combine-latest-in-ngrx/</id>
    <published>2024-08-16T15:00:00+02:00</published>
    <updated>2026-10-28T23:21:52+01:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>When working with Angular and NgRx, a common challenge is effectively managing and combining state selectors in a clean and readable way. The combineLatest function offers a powerful solution to this problem, especially when paired with Angular’s async pipe and ng-container. This approach allows you to create more streamlined and maintainable templates, improving both readability and performance.</summary>
    <content type="html">&lt;p&gt;When working with Angular and NgRx, a common challenge is effectively managing and combining state selectors in a clean and readable way. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;combineLatest&lt;/code&gt; function offers a powerful solution to this problem, especially when paired with Angular’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; pipe and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-container&lt;/code&gt;. This approach allows you to create more streamlined and maintainable templates, improving both readability and performance.&lt;/p&gt;

&lt;h2 id=&quot;understanding-combinelatest&quot;&gt;Understanding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;combineLatest&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;combineLatest&lt;/code&gt; function in RxJS, which NgRx relies on, is used to combine multiple observables into one. When using it with NgRx selectors, it allows you to combine multiple pieces of state into a single observable stream, which you can then subscribe to in your components.&lt;/p&gt;

&lt;p&gt;Here’s a basic example:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;data$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;combineLatest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sample1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sampleSelector1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sample2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sampleSelector2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data$&lt;/code&gt; is an observable that emits an object containing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sample1&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sample2&lt;/code&gt; whenever either selector emits a new value. This combined observable can then be used directly in your Angular template.&lt;/p&gt;

&lt;h2 id=&quot;leveraging-ng-conteiner-and-the-asyncpipe&quot;&gt;Leveraging &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-conteiner&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; Pipe&lt;/h2&gt;

&lt;p&gt;One of the most effective ways to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;combineLatest&lt;/code&gt; in your Angular template is by starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-container&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; pipe. This approach not only simplifies your template but also improves performance by reducing the number of async subscriptions.&lt;/p&gt;

&lt;p&gt;Here’s how you can do it:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;*ngIf=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;data$ | async as data&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ data.sample1 }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ data.sample2 }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-advantage&quot;&gt;The Advantage&lt;/h2&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;combineLatest&lt;/code&gt; together with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-container&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; pipe offers several benefits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single Subscription&lt;/strong&gt;: By using combineLatest, you only need one async pipe in your template, which reduces the number of subscriptions and simplifies your template logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clean Template&lt;/strong&gt;: The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-container&lt;/code&gt; directive allows you to directly access all the combined state selectors within a single data object, keeping your template concise and easy to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improved Performance&lt;/strong&gt;: Fewer subscriptions mean less overhead, leading to better performance, especially in complex components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduced Boilerplate&lt;/strong&gt;: Instead of managing multiple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*ngIf=&quot;observable$ | async as value&quot;&lt;/code&gt; directives, you only manage one, which reduces the amount of boilerplate code in your templates.&lt;/p&gt;

&lt;h2 id=&quot;putting-it-alltogether&quot;&gt;Putting It All Together&lt;/h2&gt;

&lt;p&gt;Consider a component that displays user details and preferences from two different selectors. Without combineLatest, your template might look something like this:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;*ngIf=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user$ | async as user&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ user.name }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;*ngIf=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;preferences$ | async as preferences&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ preferences.theme }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
By using combineLatest, you can simplify this to:
&lt;span class=&quot;nt&quot;&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;*ngIf=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;data$ | async as data&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ data.user.name }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ data.preferences.theme }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This approach not only looks cleaner but also scales better as your component grows in complexity.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;combineLatest&lt;/code&gt; in combination with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-container&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; pipe in Angular templates provides a more efficient, cleaner, and maintainable way to manage state selectors from NgRx. By adopting this pattern, you can reduce the complexity of your templates, leading to code that’s easier to read, write, and maintain.
Give this approach a try in your next Angular project and experience the difference it can make in your codebase!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Stop Using console.log and Start Using This Service!</title>
    <link href="https://davdifr.com/posts/stop-using-console-log-and-start-using-this-service/"/>
    <id>https://davdifr.com/posts/stop-using-console-log-and-start-using-this-service/</id>
    <published>2024-06-25T13:45:00+02:00</published>
    <updated>2024-06-25T13:45:00+02:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>Logging is an essential part of any software development process. It helps developers debug applications, understand workflows, and track down issues. However, relying solely on console.log for logging in an Angular application can quickly become problematic, especially when moving from development to production environments.</summary>
    <content type="html">&lt;p&gt;Logging is an essential part of any software development process. It helps developers debug applications, understand workflows, and track down issues. However, relying solely on console.log for logging in an Angular application can quickly become problematic, especially when moving from development to production environments.&lt;/p&gt;

&lt;p&gt;In this article, I will introduce a logging service that can be easily integrated into your Angular application. This service allows you to control the log level based on the environment configuration, ensuring that verbose logging is available during development but minimized or disabled in production.&lt;/p&gt;

&lt;h2 id=&quot;why-you-should-stop-using-consolelog&quot;&gt;Why You Should Stop Using console.log&lt;/h2&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; statements scattered throughout your codebase can lead to several issues:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Performance Issues&lt;/strong&gt;: Excessive logging in production can degrade performance.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Security Risks&lt;/strong&gt;: Sensitive information might be logged and exposed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clutter&lt;/strong&gt;: Logs can quickly become cluttered, making it difficult to find relevant information.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By using a structured logging service, you can mitigate these issues and have more control over what gets logged and when.&lt;/p&gt;

&lt;h2 id=&quot;introducing-the-logservice&quot;&gt;Introducing the Log Service&lt;/h2&gt;

&lt;p&gt;Here’s a simple but effective logging service for your Angular application. It uses an enumerated log level to control what messages are logged based on the current environment configuration.&lt;/p&gt;

&lt;h2 id=&quot;log-levelsenum&quot;&gt;Log Levels Enum&lt;/h2&gt;

&lt;p&gt;First, we define an enumeration for the different log levels:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;log-service&quot;&gt;Log Service&lt;/h2&gt;

&lt;p&gt;Next, we create the LogService that utilizes this enum to conditionally log messages:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Injectable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../../environments/environment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../models/log.interface&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Injectable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;providedIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionalParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;environment-configuration&quot;&gt;Environment Configuration&lt;/h2&gt;

&lt;p&gt;Finally, we configure the environments to use different log levels:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// environment.ts (Development)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;production&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;logLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;debug&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// environment.prod.ts (Production)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;production&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;logLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;how-to-use-the-logservice&quot;&gt;How to Use the Log Service&lt;/h2&gt;

&lt;p&gt;To start using the LogService, inject it into your components or services:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;OnInit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./services/log.service&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;app-root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;templateUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./app.component.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;styleUrls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./app.component.css&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AppComponent&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;OnInit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;logService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LogService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;ngOnInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Application initialized&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Debugging information&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;By using this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogService&lt;/code&gt;, you can gain better control over your logging output, ensuring that you have detailed logs in development while keeping your production environment clean and efficient. This approach not only enhances the maintainability of your application but also helps in adhering to best practices for logging in software development.&lt;/p&gt;

&lt;p&gt;Stop scattering &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; statements in your code today and start using a structured logging service for a more robust and manageable application!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Create Dynamic Forms in Angular Using a Dictionary Interface</title>
    <link href="https://davdifr.com/posts/how-to-create-dynamic-forms-in-angular-using-a-dictionary-interface/"/>
    <id>https://davdifr.com/posts/how-to-create-dynamic-forms-in-angular-using-a-dictionary-interface/</id>
    <published>2024-06-14T18:15:00+02:00</published>
    <updated>2026-10-28T23:21:52+01:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>Creating dynamic forms in Angular can be a powerful way to handle flexible data structures, especially when working with APIs that return complex or nested JSON objects. In this article, I will show you how to create dynamic forms in Angular using a Dictionary interface and a dynamic form generator service.</summary>
    <content type="html">&lt;p&gt;Creating dynamic forms in Angular can be a powerful way to handle flexible data structures, especially when working with APIs that return complex or nested JSON objects. In this article, I will show you how to create dynamic forms in Angular using a Dictionary interface and a dynamic form generator service.&lt;/p&gt;

&lt;h2 id=&quot;defining-the-dictionary-interface&quot;&gt;Defining the Dictionary Interface&lt;/h2&gt;

&lt;p&gt;First, let’s define the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dictionary&lt;/code&gt; interface. This interface allows us to have a recursive type that can contain either strings or nested dictionaries:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;creating-the-dynamic-form-generator-service&quot;&gt;Creating the Dynamic Form Generator Service&lt;/h2&gt;

&lt;p&gt;Next, we need a service that can create form controls based on the structure of the dictionary. This service will recursively create form groups for nested dictionaries and form controls for string values.&lt;/p&gt;

&lt;p&gt;Here is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DynamicFormGeneratorService&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Injectable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;providedIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DynamicFormGeneratorService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;#fb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;FormBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;createForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormGroup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formControls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createControls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#fb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formControls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createControls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AbstractControl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;controls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;controls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#fb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createControls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;controls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FormControl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Validators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;controls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AbstractControl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;creating-the-dynamic-form-group-component&quot;&gt;Creating the Dynamic Form Group Component&lt;/h2&gt;
&lt;p&gt;Now, let’s create a component that will use this service to generate a form based on the dictionary data. This component will be responsible for rendering the form and handling form submissions.&lt;/p&gt;

&lt;p&gt;Here’s the TypeScript for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DynamicFormGroupComponent&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;app-dynamic-form-group&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;standalone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ReactiveFormsModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;templateUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./dynamic-form-group.component.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DynamicFormGroupComponent&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;OnInit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formValues&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EventEmitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;initialData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormGroup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FormGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;#dynamicFormService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DynamicFormGeneratorService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;objectKeys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;ngOnInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initialData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formGroup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#dynamicFormService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initialData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initialData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;invalid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formValues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;isGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AbstractControl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;control&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormGroup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;control&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;getFormGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AbstractControl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FormGroup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;control&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;FormGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the corresponding HTML template:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;[formGroup]=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;formGroup&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;p-6 bg-indigo-50 border border-red-200 rounded-lg shadow-sm space-y-4&quot;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- This loop iterates over the keys of the formGroup.controls object. --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Each key represents a form control or a nested form group. --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;*ngFor=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;let key of objectKeys(formGroup.controls)&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- This condition checks if the current form control is a FormGroup. --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;*ngIf=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;isGroup(formGroup.get(key)); else singleControl&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- If it is a FormGroup, a fieldset is created for it. --&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;fieldset&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;[formGroupName]=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;border border-gray-300 rounded-lg p-4 bg-white&quot;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;legend&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text-lg font-semibold text-gray-700 mb-2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ key }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/legend&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- The nested FormGroup is passed to the component using the formGroup input property. --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;app-dynamic-form-group&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;[formGroup]=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;getFormGroup(formGroup.get(key))&quot;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/app-dynamic-form-group&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;#singleControl&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- If the current form control is not a FormGroup, an input field is created for it. --&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- The formControlName directive associates this input field with the form control. --&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;flex flex-col space-y-2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;[for]=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text-sm font-medium text-gray-600&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ key }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;[formControlName]=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ key }}&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500&quot;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- This condition checks if initialData is available and adds a submit button if it is. --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;*ngIf=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;initialData&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;(click)=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;onSubmit()&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;[disabled]=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;formGroup.invalid&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bg-indigo-500 text-white px-4 py-2 rounded-lg hover:bg-indigo-600 disabled:opacity-50 disabled:cursor-not-allowed&quot;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    Submit
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;putting-it-alltogether&quot;&gt;Putting It All Together&lt;/h2&gt;
&lt;p&gt;To use this dynamic form in your application, you would typically have a parent component that provides the dictionary data and handles the form submission:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AppComponent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dynamic-forms&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;onFormValues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Dictionary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;contractId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;C12345&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;contractType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Employment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;startDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2024-01-01&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;endDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2025-01-01&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;employer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Tech Corp Inc.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;456 Technology Drive, Silicon Valley, USA&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;555-1234&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hr@techcorp.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;jobDetails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;jobTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Senior Developer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;jobDescription&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Responsible for developing and maintaining web applications.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;salary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;75000&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;benefits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Health, Dental, Vision&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;preview&quot;&gt;Preview&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/posts/how-to-create-dynamic-forms-in-angular-using-a-dictionary-interface/preview.png&quot; alt=&quot;Dynamic Form Preview&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we have demonstrated how to create a dynamic form in Angular using a dictionary interface. By leveraging Angular’s reactive forms and a recursive approach, you can generate complex forms that adapt to any data structure. This method is particularly useful for handling dynamic data from APIs and creating flexible form components.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Streamlining Angular Route Configuration with APP_ROUTES</title>
    <link href="https://davdifr.com/posts/streamlining-angular-route-configuration-with-app-routes/"/>
    <id>https://davdifr.com/posts/streamlining-angular-route-configuration-with-app-routes/</id>
    <published>2024-06-09T14:50:00+02:00</published>
    <updated>2024-06-09T14:50:00+02:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>Handling routes in an Angular application can get pretty tricky, especially as your project grows larger. One way to keep things simple and organized is by putting all your routes in one place using constants.This approach not only makes your code easier to read but also saves you from the headache of having to update routes scattered all over your codebase. In this article, I’ll show you how to set up this system step by step.</summary>
    <content type="html">&lt;p&gt;Handling routes in an Angular application can get pretty tricky, especially as your project grows larger. One way to keep things simple and organized is by putting all your routes in one place using constants.
This approach not only makes your code easier to read but also saves you from the headache of having to update routes scattered all over your codebase. In this article, I’ll show you how to set up this system step by step.&lt;/p&gt;

&lt;h2 id=&quot;the-basicapproach&quot;&gt;The Basic Approach&lt;/h2&gt;
&lt;p&gt;The simplest way to define your routes is by using a constant object where each route is a string. Here’s an example:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;APP_ROUTES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;home&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ABOUT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;about&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;CONTACT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This approach allows you to reference your routes throughout your application using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_ROUTES.HOME&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_ROUTES.ABOUT&lt;/code&gt;, etc. This is a significant improvement over hardcoding strings everywhere.&lt;/p&gt;

&lt;h2 id=&quot;enhancing-flexibility-with-functions&quot;&gt;Enhancing Flexibility with Functions&lt;/h2&gt;

&lt;p&gt;While the basic approach is helpful, we can make it more powerful by using functions. This allows for more dynamic route construction, particularly useful for nested routes. Here’s how you can do it:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;APP_ROUTES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;home`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ABOUT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;about`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;CONTACT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contact`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;example-use-case-nestedroutes&quot;&gt;Example Use Case: Nested Routes&lt;/h2&gt;

&lt;p&gt;Consider a scenario where you have nested routes. For example, a sample child route under the home route. Using the function-based approach, you can easily manage this:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;APP_ROUTES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;home`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;SAMPLE_CHILD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;APP_ROUTES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/sample_child`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this setup, you can get the full path of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SAMPLE_CHILD&lt;/code&gt; by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_ROUTES.SAMPLE_CHILD()&lt;/code&gt;, and the relative path by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_ROUTES.SAMPLE_CHILD(true)&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;creating-a-central-route-definition-file&quot;&gt;Creating a Central Route Definition File&lt;/h2&gt;

&lt;p&gt;To keep your route definitions organized, create a dedicated file, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.routes.definition.ts&lt;/code&gt;. This file will contain all your route constants and functions.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// app.routes.definition.ts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;APP_ROUTES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;home`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ABOUT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;about`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;CONTACT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contact`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;SAMPLE_CHILD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;APP_ROUTES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/sample_child`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;benefits-of-thisapproach&quot;&gt;Benefits of This Approach&lt;/h2&gt;

&lt;h3 id=&quot;simplified-route-management&quot;&gt;Simplified Route Management&lt;/h3&gt;

&lt;p&gt;By centralizing your route definitions, you reduce the risk of inconsistencies and errors. If a route changes, you only need to update it in one place.&lt;/p&gt;

&lt;h3 id=&quot;cleaner-code&quot;&gt;Cleaner Code&lt;/h3&gt;

&lt;p&gt;When you use routes in your components or services, your code is cleaner and more readable. For example:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;navigateToHome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;navigate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;APP_ROUTES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;easier-refactoring&quot;&gt;Easier Refactoring&lt;/h3&gt;

&lt;p&gt;If you need to change a route, such as renaming home to dashboard, you can simply update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_ROUTES&lt;/code&gt; object. The change will propagate throughout your application, minimizing the need for extensive search-and-replace operations.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Configuring routes in Angular doesn’t have to be a daunting task. By centralizing your route definitions in one file and using constants and functions, you can keep your application organized and your code easy to maintain. This method simplifies updates and reduces the risk of errors, ensuring your app runs smoothly even as it grows.&lt;/p&gt;

&lt;p&gt;Give this approach a try in your next Angular project. You’ll find that managing your routes becomes a lot less stressful and a lot more efficient.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Structuring Your Angular Project for Scalability and Maintainability</title>
    <link href="https://davdifr.com/posts/structuring-your-angular-project/"/>
    <id>https://davdifr.com/posts/structuring-your-angular-project/</id>
    <published>2024-02-19T13:50:00+01:00</published>
    <updated>2024-02-19T13:50:00+01:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>In the world of Angular development, structuring your project can significantly influence the scalability and maintainability of your application. A well-thought-out folder structure ensures that your code is organized, clean, and intuitive, making it easier for you and your team to navigate and extend the project. In this article, we will explore an effective way to structure an Angular project, focusing on a folder setup that caters to projects of varying sizes and complexities.</summary>
    <content type="html">&lt;p&gt;In the world of Angular development, structuring your project can significantly influence the scalability and maintainability of your application. A well-thought-out folder structure ensures that your code is organized, clean, and intuitive, making it easier for you and your team to navigate and extend the project. In this article, we will explore an effective way to structure an Angular project, focusing on a folder setup that caters to projects of varying sizes and complexities.&lt;/p&gt;

&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;

&lt;p&gt;Before we dive into the specifics, it’s crucial to understand the importance of segregating your project into logical units. This not only helps in isolating functionalities but also in adhering to Angular’s modular architecture. The proposed structure is as follows:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dumb-components/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;containers/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pages/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shared/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interceptors/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s break down each of these directories to understand their purpose and contents.&lt;/p&gt;

&lt;h2 id=&quot;components&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components/&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;This directory houses the reusable components of your application. These are the building blocks that you’ll use across different parts of your application. Keeping them in a dedicated components/ folder makes it easy to locate and reuse them.&lt;/p&gt;

&lt;h2 id=&quot;dumb-components&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dumb-components/&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Dumb components, or presentational components, are those that do not depend on external services or direct data manipulations. They receive data through inputs and communicate through outputs. Segregating them into a dumb-components/ folder emphasizes their role in your application’s UI without cluttering the logic-heavy components.&lt;/p&gt;

&lt;h2 id=&quot;containers&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;containers/&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Containers are components that are aware of the application state and handle data fetching, state management, and interaction with services. They serve as the glue between your presentation components and services. Organizing them in a containers/ directory helps in distinguishing them from dumb components and streamlines state management.&lt;/p&gt;

&lt;h2 id=&quot;pages&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pages/&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The pages/ directory contains components that are tied to your routing. Each component here represents a different page within your application, making it straightforward to understand your application’s structure at a glance.&lt;/p&gt;

&lt;h2 id=&quot;shared&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shared/&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Shared resources such as services, decorators, and directives that are used across different parts of your application are kept in the shared/ directory. This directory often includes sub-folders like services/, decorators/, and directives/ to further organize these shared resources.&lt;/p&gt;

&lt;h2 id=&quot;interceptors&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interceptors/&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Interceptors are a powerful feature in Angular that allow you to intercept incoming or outgoing HTTP requests and responses. Keeping them in an interceptors/ directory centralizes your interceptors, making them easy to manage.&lt;/p&gt;

&lt;h2 id=&quot;store&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store/&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;For state management, especially when using libraries like NgRx, the store/ directory contains your actions, reducers, effects, and selectors. A typical structure inside this directory might look like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;store/
  sample/
    sample.actions.ts
    sample.effects.ts  
    sample.reducer.ts  
    sample.selectors.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This setup provides a clear overview of your state management strategies and how they relate to different components in your application.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Structuring your Angular project using the outlined folder structure provides a solid foundation for building scalable and maintainable applications. By organizing your codebase logically, you make it easier for developers to navigate, understand, and contribute to the project. As you grow your application, this structure can adapt to accommodate new features and modules, ensuring that your project remains well-organized and efficient.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Enhancing Angular Navigation with GlobalKeydown: A Guide to Keyboard-Driven Routes</title>
    <link href="https://davdifr.com/posts/enhancing-angular-navigation/"/>
    <id>https://davdifr.com/posts/enhancing-angular-navigation/</id>
    <published>2024-01-18T10:20:00+01:00</published>
    <updated>2024-01-18T10:20:00+01:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>Introduction to GlobalKeydownService</summary>
    <content type="html">&lt;h2 id=&quot;introduction-to-globalkeydownservice&quot;&gt;Introduction to GlobalKeydownService&lt;/h2&gt;

&lt;p&gt;Angular’s flexibility allows us to extend our application’s functionality with custom services. In this case, we’ll create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GlobalKeydownService&lt;/code&gt;. This service listens to global keydown events and filters out those triggered within input elements - ensuring that typing in a text field does not inadvertently trigger navigation.&lt;/p&gt;

&lt;h2 id=&quot;the-servicecode&quot;&gt;The Service Code&lt;/h2&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Injectable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fromEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;rxjs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;rxjs/operators&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Injectable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;providedIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GlobalKeydownService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;keydownEvents$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keydownEvents$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fromEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;KeyboardEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;keydown&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HTMLInputElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This service uses RxJS’s fromEvent to listen for keydown events on the window object, and then processes these events to output only the relevant key values.&lt;/p&gt;

&lt;h2 id=&quot;integrating-globalkeydownservice-with-navbarcomponent&quot;&gt;Integrating GlobalKeydownService with NavbarComponent&lt;/h2&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GlobalKeydownService&lt;/code&gt; in place, we can now modify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NavbarComponent&lt;/code&gt; to listen to keydown events and navigate accordingly.&lt;/p&gt;

&lt;h2 id=&quot;modifying-the-navbar-component&quot;&gt;Modifying the Navbar Component&lt;/h2&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;OnInit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RouterModule&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/router&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NavigationService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../../shared/services/navigation.service&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GlobalKeydownService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../../shared/services/global-keydown.service&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;takeUntil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;rxjs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ... Component Code ...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NavbarComponent&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;OnInit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ... Existing properties ...&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;#keydown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;GlobalKeydownService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;#destroy$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;ngOnInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ... Existing initialization code ...&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#keydown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keydownEvents$&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;takeUntil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#destroy$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;navigateByKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;navigateByKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#navigation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;navigateTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ... Remaining component code ...&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;ngOnDestroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#destroy$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#destroy$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this updated component, we are subscribing to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keydownEvents$&lt;/code&gt; observable from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GlobalKeydownService&lt;/code&gt;. When a key is pressed, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;navigateByKey&lt;/code&gt; method is called, which checks if the pressed key corresponds to a valid route index and, if so, triggers navigation to that route.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/enhancing-angular-navigation/preview.gif&quot; alt=&quot;Angular Navigation&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;By integrating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GlobalKeydownService&lt;/code&gt; with our navbar component, we’ve added a layer of keyboard-driven navigation to our Angular application. This approach not only enhances user experience by providing a quicker navigation method but also contributes to the accessibility of the application.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Fresh Take on Angular Session Management: Introducing SessionManagementService</title>
    <link href="https://davdifr.com/posts/introducing-session-management-service/"/>
    <id>https://davdifr.com/posts/introducing-session-management-service/</id>
    <published>2024-01-12T13:00:00+01:00</published>
    <updated>2024-01-12T13:00:00+01:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>IntroductionThis service focuses on maintaining a single active session in a multi-tab environment, enhancing the user experience and application efficiency. It started as an experiment, a simple concept to improve session management. To my surprise, the outcome was quite intriguing. This has motivated me to share it with the community. It’s possible that it could be useful to others, or at the very least, it might spark new use cases or ideas among fellow developers.</summary>
    <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This service focuses on maintaining a single active session in a multi-tab environment, enhancing the user experience and application efficiency. It started as an experiment, a simple concept to improve session management. To my surprise, the outcome was quite intriguing. This has motivated me to share it with the community. It’s possible that it could be useful to others, or at the very least, it might spark new use cases or ideas among fellow developers.&lt;/p&gt;

&lt;h2 id=&quot;service-overview&quot;&gt;Service Overview&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SessionManagementService&lt;/code&gt; utilizes Angular’s dependency injection and the power of RxJS for reactive programming. Its main goal is to identify and manage multiple instances of the same application in different browser tabs, ensuring a coherent and focused user interaction.&lt;/p&gt;

&lt;h2 id=&quot;key-features&quot;&gt;Key Features:&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Multi-Tab Session Detection&lt;/strong&gt;: Detects when the same application is opened in multiple tabs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Session State Management&lt;/strong&gt;: Keeps only the most recent session active.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reactive Event Handling&lt;/strong&gt;: Responds to browser events, maintaining up-to-date session states.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/introducing-session-management-service/preview.gif&quot; alt=&quot;Session Management Service Preview&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;service-inactiontechnical-insights&quot;&gt;Service in ActionTechnical Insights&lt;/h2&gt;

&lt;p&gt;The service’s functionality revolves around event listeners for browser activities. These listeners help in coordinating session states across tabs, essential for maintaining a consistent user experience.&lt;/p&gt;

&lt;h2 id=&quot;code-functionality&quot;&gt;Code Functionality&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Unique Session IDs&lt;/strong&gt;: Each tab generates a unique session ID. The service tracks these IDs to identify the active sessions.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createNewSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Browser Event Listeners&lt;/strong&gt;: The service listens to storage and beforeunload events to manage session updates and cleanup.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setupStorageEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;storage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StorageEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storageEventSubject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Determining the Active Session&lt;/strong&gt;: The service checks if the current tab is the active session, differentiating the user experience based on session activity.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;isCurrentSessionActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getSessionsFromStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#currentSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;complete-codelisting&quot;&gt;Complete Code Listing&lt;/h2&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Injectable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BehaviorSubject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fromEvent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;rxjs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Injectable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;providedIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SessionManagementService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;storageEventSubject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BehaviorSubject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;StorageEvent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;#currentSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;#sessionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setupStorageEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#currentSessionId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createNewSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#sessionIds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getSessionsFromStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#sessionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#sessionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#currentSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setSessionsToStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#sessionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;initializeFirstSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;fromEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;beforeunload&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getSessionsFromStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#currentSessionId&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setSessionsToStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setupStorageEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;storage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StorageEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storageEventSubject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createNewSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initializeFirstSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#sessionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#currentSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setSessionsToStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#sessionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;isCurrentSessionActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getSessionsFromStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#currentSessionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getSessionsFromStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessionsInStorage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessionsInStorage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sessionsInStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setSessionsToStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;potential-usecases&quot;&gt;Potential Use Cases&lt;/h2&gt;

&lt;p&gt;The service is ideal for applications where efficient session management and a focused user experience across multiple tabs are important.&lt;/p&gt;

&lt;h2 id=&quot;concluding-thoughts&quot;&gt;Concluding Thoughts&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SessionManagementService&lt;/code&gt; is an experimental concept, aiming to offer a new approach to session management in web applications. It’s a starting point to experiment and adapt in various contexts.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Theme Switcher in Angular: From Dark to Light and Back Again</title>
    <link href="https://davdifr.com/posts/theme-switcher-in-angular/"/>
    <id>https://davdifr.com/posts/theme-switcher-in-angular/</id>
    <published>2024-01-09T15:30:00+01:00</published>
    <updated>2024-01-09T15:30:00+01:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>Introduction</summary>
    <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Offering a choice between light and dark modes in web applications enhances user experience and accessibility. In this article, we’ll explore how to create a dynamic theme switcher in Angular, using a service and a component. Let’s dive into the code!&lt;/p&gt;

&lt;h2 id=&quot;understanding-the-themeservice&quot;&gt;Understanding the ThemeService&lt;/h2&gt;
&lt;p&gt;At the core of our theme-switching feature is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeService&lt;/code&gt;. This service manages the theme state and applies the appropriate styles.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Injectable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WritableSignal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;effect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;storageKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Injectable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;providedIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThemeService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;#path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/assets/themes&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HTMLLinkElement&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HTMLLinkElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;themeSignal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WritableSignal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;initializeThemeFromPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;effect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updateRenderedTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;toggleTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;themeSignal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isDarkThemeActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initializeThemeFromPreferences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;initializeStylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;storedTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storageKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storedTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;themeSignal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;storedTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initializeStylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;stylesheet&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;getToggleLabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Switch to &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isDarkThemeActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; mode`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;isDarkThemeActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;themeSignal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;updateRenderedTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#stylesheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;themeSignal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.css`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storageKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;themeSignal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This service initializes the theme based on user preferences, manages theme toggling, and dynamically updates the stylesheet link.&lt;/p&gt;

&lt;h2 id=&quot;building-the-themetogglecomponent&quot;&gt;Building the ThemeToggleComponent&lt;/h2&gt;

&lt;p&gt;The user interacts with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeToggleComponent&lt;/code&gt; to change the theme. It’s a standalone Angular component with a simple yet effective UI.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;inject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ThemeService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../../shared/services/theme.service&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;app-theme-toggle&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;standalone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`
    &amp;lt;input
      id=&quot;theme-toggle&quot;
      type=&quot;checkbox&quot;
      [checked]=&quot;isDarkThemeActive()&quot;
      (change)=&quot;switchTheme()&quot;
      [attr.aria-label]=&quot;getThemeToggleLabel()&quot;
    /&amp;gt;
  `&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThemeToggleComponent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;#theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ThemeService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ThemeService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;switchTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;isDarkThemeActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isDarkThemeActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;getThemeToggleLabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;#theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getToggleLabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This HTML template includes a checkbox that toggles the theme when clicked.&lt;/p&gt;

&lt;h2 id=&quot;how-they-worktogether&quot;&gt;How They Work Together&lt;/h2&gt;

&lt;p&gt;The synergy between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeService&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeToggleComponent&lt;/code&gt; is what makes the theme switching smooth and effective:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;User Action&lt;/strong&gt;: When a user clicks the theme toggle checkbox, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeToggleComponent&lt;/code&gt; calls toggleTheme from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeService&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;State Update&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeService&lt;/code&gt; updates the themeSignal, which triggers a change in the theme.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dynamic CSS Update&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThemeService&lt;/code&gt; then changes the href of the stylesheet link, loading the appropriate theme CSS.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Persistence&lt;/strong&gt;: The new theme preference is stored in local storage for future sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/theme-switcher-in-angular/preview.gif&quot; alt=&quot;Theme Switcher in Angular&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;switcher-inactionconclusion&quot;&gt;Switcher in actionConclusion&lt;/h2&gt;
&lt;p&gt;Implementing a theme switcher in Angular is not just about aesthetics; it’s about enhancing user experience and accessibility. With ThemeService and ThemeToggleComponent, you can offer a dynamic and responsive theme-switching feature in your Angular applications.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dynamic Navigation in Angular: Building a Navbar Using Route Configurations</title>
    <link href="https://davdifr.com/posts/dynamic-navigation-in-angular/"/>
    <id>https://davdifr.com/posts/dynamic-navigation-in-angular/</id>
    <published>2024-01-04T18:00:00+01:00</published>
    <updated>2026-10-28T23:21:52+01:00</updated>
    <category term="Web Development"/>
    <category term="Front-end"/>
    <summary>IntroductionIn modern web applications, navigation plays a critical role in guiding users through the interface. Angular, a popular front-end framework, offers robust tools for managing routes and navigation. This article delves into how Angular can dynamically build a navigation bar (navbar) based on route configurations. We’ll explore an implementation that uses Angular’s routing mechanism to populate a navbar component with links to different pages in the application.</summary>
    <content type="html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In modern web applications, navigation plays a critical role in guiding users through the interface. Angular, a popular front-end framework, offers robust tools for managing routes and navigation. This article delves into how Angular can dynamically build a navigation bar (navbar) based on route configurations. We’ll explore an implementation that uses Angular’s routing mechanism to populate a navbar component with links to different pages in the application.&lt;/p&gt;

&lt;h2 id=&quot;understanding-the-corefiles&quot;&gt;Understanding the Core Files&lt;/h2&gt;
&lt;p&gt;Our implementation involves three key files: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nav.service.ts&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;navbar.component.ts&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.routes.ts&lt;/code&gt;. Let’s break down each file to understand their roles.&lt;/p&gt;

&lt;p&gt;nav.service.ts:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Injectable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;providedIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NavigationService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  
  &lt;span class=&quot;nf&quot;&gt;getNavigationRoutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;…&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;children&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])])&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;showInNavbar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: This service file is responsible for retrieving the routes that should be displayed in the navbar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;: It uses Angular’s Router service to access the application’s route configurations. The function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getNavigationRoutes()&lt;/code&gt; filters these routes, selecting only those marked with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data[&quot;showInNavbar&quot;]&lt;/code&gt; property. This approach allows us to specify which routes appear in the navbar directly within the route configuration.&lt;/p&gt;

&lt;p&gt;navbar.component.ts:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;app-navbar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`
    &amp;lt;nav aria-label=&quot;Main navigation&quot;&amp;gt;
      &amp;lt;ul&amp;gt;
        @for (route of routes; track $index) {
          &amp;lt;li&amp;gt;
            &amp;lt;a routerLink=&quot;{{ route.path }}&quot;&amp;gt;{{ route.data?.[&apos;title&apos;] }}&amp;lt;/a&amp;gt;
          &amp;lt;/li&amp;gt;
        }
      &amp;lt;/ul&amp;gt;
    &amp;lt;/nav&amp;gt;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NavbarComponent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;navigation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;NavigationService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;ngOnInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;routes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRoutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getRoutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;navigation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getNavigationRoutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: This component file represents the visual element of the navbar in the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;: It imports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NavigationService&lt;/code&gt; to access the filtered routes. The component’s template uses Angular’s structural directives to iterate over these routes and dynamically create navigation links. This setup ensures that the navbar reflects the current route configuration of the application.&lt;/p&gt;

&lt;p&gt;app.routes.ts:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Routes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;first-page&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;First Page&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;showInNavbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// other properties...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// other routes...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: This file defines the routes of the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;: Each route object includes the path, component, and any child routes. Notably, routes meant for the navbar have a data property with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;showInNavbar: true&lt;/code&gt;. This design simplifies route management and makes the navbar’s content easily adjustable by modifying the route configurations.&lt;/p&gt;

&lt;h2 id=&quot;bringing-it-alltogether&quot;&gt;Bringing It All Together&lt;/h2&gt;
&lt;p&gt;The interaction between these files creates a cohesive navigation system. When the application initializes, NavbarComponent fetches the routes from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NavigationService&lt;/code&gt;, which in turn retrieves and filters them from the Angular Router. As a result, the navbar dynamically adjusts to changes in the route configuration, making the application more modular and easier to maintain.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Angular’s routing system provides a powerful way to manage navigation in web applications. By integrating services, components, and route configurations, developers can create dynamic, responsive navigation structures like the navbar we’ve explored. This approach enhances the scalability and maintainability of Angular applications, allowing for more efficient development workflows.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Creating an NFT Credential</title>
    <link href="https://davdifr.com/posts/creating-an-nft-credential/"/>
    <id>https://davdifr.com/posts/creating-an-nft-credential/</id>
    <published>2023-02-09T11:38:26+01:00</published>
    <updated>2024-09-25T12:34:02+02:00</updated>
    <category term="Tech Research"/>
    <category term="Digital Credentials"/>
    <summary>The NFTs created in the proposed solution are compliant with the ERC721 standard and can be created directly through Etherscan (the official Ethereum blockchain explorer).Additionally, like any other NFT of this standard, they can be viewed and read on any platform that interacts with these smart contracts.The creation of a new digital credential through Etherscan appears as follows:</summary>
    <content type="html">&lt;p&gt;The NFTs created in the proposed solution are compliant with the ERC721 standard and can be &lt;strong&gt;created directly through Etherscan&lt;/strong&gt; (the official Ethereum blockchain explorer).
Additionally, like any other NFT of this standard, they can be viewed and read on &lt;strong&gt;any platform&lt;/strong&gt; that interacts with these smart contracts.
The creation of a new digital credential through Etherscan appears as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/etherscan-mint.png&quot; alt=&quot;etherscan-mint&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this point, it is not necessary to have any coding experience to proceed.
All you need to do is &lt;strong&gt;connect the contract owner’s wallet&lt;/strong&gt; and fill out the form to &lt;strong&gt;create and send&lt;/strong&gt; the recipient their digital credential.&lt;/p&gt;

&lt;p&gt;Once the token is released, the recipient can &lt;strong&gt;share their wallet address&lt;/strong&gt;, allowing it to be easily found using &lt;strong&gt;various blockchain exploration tools&lt;/strong&gt;, including Etherscan, where information about the token can be viewed.&lt;/p&gt;

&lt;p&gt;Sharing the transaction details can also be sufficient to view the attributes of the issued NFT.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/transaction.png&quot; alt=&quot;transaction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of course, this is not a practical way to share the credential. It is &lt;strong&gt;recommended to use the OpenSea&lt;/strong&gt; platform instead, which in addition to providing an address for viewing on their site, also provides an embed code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/share.jpeg&quot; alt=&quot;transaction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Moreover, it is possible to &lt;strong&gt;build various web applications&lt;/strong&gt; using the &lt;strong&gt;web3js library&lt;/strong&gt;, which allows interaction with smart contracts.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/mint.png&quot; alt=&quot;dapp-mint&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A possible example, which will be demonstrated in the form of a demo, is the potential use of these credentials as a form of login to a platform.&lt;/p&gt;

&lt;h2 id=&quot;potential-use-as-login-demo&quot;&gt;Potential use as Login [DEMO]&lt;/h2&gt;

&lt;h4 id=&quot;1-checking-user-address&quot;&gt;1. Checking User Address&lt;/h4&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;web3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Web3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://goerli.infura.io/v3/22a66e24f1fb47599e326320feb4b424&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenContractAddress&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0x6c3C2C3ad1D11B518e132Ea794c6c796D51af2Ee&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Creating an &lt;strong&gt;instance of the Web3 class&lt;/strong&gt; and connecting to an Infura node and we are defining a constant variable for the smart contract address that we will be interacting with.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userAddress&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;checkUserAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ethereum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;userAddress&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ethereum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a variable called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userAddress&lt;/code&gt; and initialize it as an empty string.&lt;/p&gt;

&lt;p&gt;Next, we have an asynchronous function called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkUserAddress&lt;/code&gt;. This function first checks if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethereum&lt;/code&gt; object is available, and if it is, it enables access to wallet information using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethereum.enable()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;The first account in the resulting array is then assigned to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userAddress&lt;/code&gt; variable.
&lt;em&gt;If an error occurs, it will be logged in the console.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Upon opening the page, &lt;strong&gt;the user will be prompted to connect their wallet&lt;/strong&gt; first, thanks to this code.&lt;/p&gt;

&lt;h4 id=&quot;2-logging-into-the-platform-via-contract-interaction&quot;&gt;2. Logging into the platform via contract interaction&lt;/h4&gt;

&lt;p&gt;We manage a login interface that handles &lt;strong&gt;two scenarios&lt;/strong&gt;: the wallet owner &lt;strong&gt;doesn’t have any tokens&lt;/strong&gt; issued by our contract, and the owner &lt;strong&gt;has one or multiple tokens&lt;/strong&gt;, the details of which are also displayed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/login.png&quot; alt=&quot;login&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When the button is clicked, it performs the following actions:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;btn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenContract&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;web3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;abi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenContractAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;balanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textContent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;There is at least one NFT in your wallet from this contract&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textContent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;There are no NFTs in your wallet created by this contract&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Creates a new instance of a smart contract using the Ethereum JavaScript library web3.js and its Contract object.&lt;/li&gt;
  &lt;li&gt;Calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;balanceOf&lt;/code&gt; method on the smart contract instance and checks if the returned balance is greater than 0.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the balance is equal to or less than 0, the “msg” element is set to “There are no NFTs in your wallet created by this contract”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/not-owner.png&quot; alt=&quot;not-owner&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If the balance is greater than 0, the “msg” element is set to “There is at least one NFT in your wallet from this contract”.&lt;/p&gt;

&lt;p&gt;Additionally:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokens&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;walletOfOwner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenMetadataPromises&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tokenId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tokenId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenMetadatas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tokenMetadataPromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;tokenMetadatas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;metadata&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;walletOfOwner&lt;/code&gt; method on the smart contract instance to get an array of tokens owned by a specific user address.&lt;/li&gt;
  &lt;li&gt;Maps over the array of tokens and calls the metadata method on the smart contract instance for each token to retrieve its metadata.&lt;/li&gt;
  &lt;li&gt;Waits for all metadata requests to complete and stores the results in an array.&lt;/li&gt;
  &lt;li&gt;Iterates over the array of metadata, creating HTML elements for the owner name, title, and description of each token and appending them to the “details” element.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/owner.png&quot; alt=&quot;owner&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;creating-a-graphic-appearance&quot;&gt;Creating a Graphic Appearance&lt;/h2&gt;

&lt;p&gt;NFTs commonly come with an image that serves as a visual representation. However, the current on-chain metadata structure doesn’t support the inclusion of images. Fortunately, we can utilize an off-chain solution through IPFS to resolve this limitation.&lt;/p&gt;

&lt;p&gt;IPFS (&lt;strong&gt;InterPlanetary File System&lt;/strong&gt;) is a decentralized and distributed file storage system that is designed to enhance the speed, safety, and openness of the web. Unlike traditional server-based file storage, IPFS leverages a peer-to-peer network of computers to store and access files, leading to faster and more resilient file sharing. This technology is often integrated with blockchain technology to build decentralized applications and to store and transfer digital assets such as NFTs.&lt;/p&gt;

&lt;p&gt;Two files will need to be stored using an IPFS service: &lt;strong&gt;the image&lt;/strong&gt; we want to assign to the token, and &lt;strong&gt;the JSON file&lt;/strong&gt; containing the desired metadata.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Digital Credential&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;On-chain Digital Credentials through NFTs.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ipfs://QmNgdypgjW79BNj1aADctMakZGJqbjiTbKDyWC97smcXg8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The JSON file will in turn have the IPFS link that has been assigned to the image inside it.&lt;/p&gt;

&lt;p&gt;The final step is to call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setBaseURI&lt;/code&gt; function of the contract, providing the IPFS address of the JSON file as input. From this moment on, the graphical representation of the token will be visible on any platform. Here is an example on OpenSea:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/creating-an-nft-credential/opensea.png&quot; alt=&quot;etherscan-mind&quot; /&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>On-chain Digital Credentials through NFTs</title>
    <link href="https://davdifr.com/posts/on-chain-digital-credentials-through-nfts/"/>
    <id>https://davdifr.com/posts/on-chain-digital-credentials-through-nfts/</id>
    <published>2023-01-11T11:57:26+01:00</published>
    <updated>2024-09-25T12:34:02+02:00</updated>
    <category term="Tech Research"/>
    <category term="Digital Credentials"/>
    <summary>The proposed contract is built on the ERC721 standard, which allows for the creation of unique, non-fungible tokens (NFTs) on the Ethereum blockchain.</summary>
    <content type="html">&lt;p&gt;The proposed contract is &lt;strong&gt;built on the ERC721&lt;/strong&gt; standard, which allows for the creation of unique, non-fungible tokens (NFTs) on the Ethereum blockchain.&lt;/p&gt;

&lt;p&gt;The goal of this implementation is to &lt;strong&gt;create NFTs that represent digital credentials&lt;/strong&gt;, with all aspects of these credentials being implemented on the blockchain. 
To achieve this, a custom data structure called NFTMetadata was implemented.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;struct NFTMetadata {
  string name;
  string title;
  string description;
  address wallet;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The NFTMetadata structure contains important information about the digital credential, such as the name, title, and description of the credential. 
Additionally, it also stores the wallet address of the original recipient of the credential. 
This allows for &lt;strong&gt;easy identification&lt;/strong&gt; of whether or not the NFT has been transferred to a different wallet and thus, whether or not the current holder is the true and original recipient of the credential.&lt;/p&gt;

&lt;p&gt;It is also possible to add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;referenceId&lt;/code&gt; field that can be used to store the id of the certificate/credential already issued on a private storage system.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
string referenceId,
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this way, on-chain storage of the NFTMetadata ensures the &lt;strong&gt;authenticity and integrity&lt;/strong&gt; of the digital credentials represented by the NFTs.&lt;/p&gt;

&lt;h3 id=&quot;mapping-token-id-to-metadata&quot;&gt;Mapping token ID to metadata&lt;/h3&gt;

&lt;p&gt;In addition to the NFTMetadata structure, the contract also uses a mapping to associate each individual NFT with its corresponding metadata. The mapping is declared as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mapping(uint256 =&amp;gt; NFTMetadata) public metadata;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This creates a mapping from token ID to NFTMetadata.&lt;/p&gt;

&lt;p&gt;Each NFT is identified by a &lt;strong&gt;unique token ID&lt;/strong&gt;, which is of the type uint256. This ID is used as the key in the mapping to access the metadata associated with that particular NFT.&lt;/p&gt;

&lt;p&gt;When a new NFT is created and minted, an entry is added to the mapping with the token ID as the key and an instance of the NFTMetadata structure as the value. This allows the contract to easily look up the metadata associated with a given NFT, simply by using its token ID as the key in the mapping.&lt;/p&gt;

&lt;p&gt;This is how the contract links the data stored on the NFT with the metadata that allow the verification and understanding of the NFT.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example if someone want to access the metadata of the NFT, with id equals to 100, it can just access the metadata[100].&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-mint-function&quot;&gt;The mint function&lt;/h3&gt;

&lt;p&gt;The mint function is a crucial part of our NFT contract, and it allows the creation of new non-fungible tokens and their assignment to a specific recipient.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function mint(
	string memory _name,
	string memory _title,
	string memory _description,
	address _recipient
) public onlyOwner {
	uint256 supply = totalSupply();
	uint256 tokenId = supply + 1;
	require(!paused);
	metadata[tokenId] = NFTMetadata(_name, _title, _description, _recipient);
	_safeMint(_recipient, tokenId);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First, only the contract owner has the permission to execute this function, this is achieved by using the keyword &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onlyOwner&lt;/code&gt;. This measure guarantees that &lt;strong&gt;only authorized parties can create new NFTs&lt;/strong&gt;, providing a higher level of security.&lt;/p&gt;

&lt;p&gt;The function receives four parameters: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_name&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_title&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_description&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_recipient&lt;/code&gt;, these parameters are used to create an instance of the NFTMetadata struct, which stores the metadata associated with the NFT, including information such as name, title and description, and the address of the recipient.&lt;/p&gt;

&lt;p&gt;The metadata is then associated with the tokenId generated, which is calculated as the totalSupply + 1. 
This provides a &lt;strong&gt;unique and incremental tokenId for each NFT minted&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, the function contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require(!paused)&lt;/code&gt; statement, which ensures that the creation of new NFTs can only take place when the contract is not paused, this is an important security measure.&lt;/p&gt;

&lt;p&gt;Finally, the function uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_safeMint&lt;/code&gt; function, which is a helper function that guarantees that the NFT is minted and assigned to the correct recipient, avoiding security vulnerabilities.&lt;/p&gt;

&lt;p&gt;Overall, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mint&lt;/code&gt; function is a robust and secure mechanism for creating new NFTs and assigning them to specific recipients, by using this function, we have ensured that the NFTs minted by our contract are unique, incremental, and properly assigned to their intended recipients, providing a high degree of trust and transparency.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Hands-on Foo contract</title>
    <link href="https://davdifr.com/posts/hands-on-foo-contract/"/>
    <id>https://davdifr.com/posts/hands-on-foo-contract/</id>
    <published>2022-11-14T18:50:26+01:00</published>
    <updated>2024-09-25T12:34:02+02:00</updated>
    <category term="Tech Research"/>
    <category term="Blockchain"/>
    <summary>This article aims to give a complete overview of how to compile, deploy and test a smart contract. All the required tools are presented step by step to illustrate the necessary development environment setup.</summary>
    <content type="html">&lt;p&gt;This article aims to give a complete overview of how to compile, deploy and test a smart contract. All the required tools are presented step by step to illustrate the necessary development environment setup.&lt;/p&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;sc-boilerplate (&lt;a href=&quot;https://github.com/davdifr/sc-boilerplate&quot;&gt;https://github.com/davdifr/sc-boilerplate&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Node.js (&lt;a href=&quot;https://nodejs.org/en/&quot;&gt;https://nodejs.org/en/&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;index&quot;&gt;Index&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#creating-a-test-wallet&quot;&gt;Creating a Test Wallet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#installing-the-required-packages&quot;&gt;Installing the required packages&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#foo-smart-contract&quot;&gt;Foo Smart Contract&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#deployment-on-the-goerli-testnet&quot;&gt;Deployment on the Goerli testnet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#contract-verification-with-etherscan&quot;&gt;Contract verification with Etherscan&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;creating-a-test-wallet&quot;&gt;Creating a Test Wallet&lt;/h2&gt;

&lt;p&gt;MetaMask is a software wallet for cryptocurrencies used to interact with the Ethereum blockchain. It allows users to access their Ethereum wallet via a browser extension or mobile app, which can then be used to interact with decentralized applications.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Note: If you already have your own MetaMask wallet, you should create a new one for security reasons.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Using Google Chrome as a browser, Metamask is avaiable in the &lt;a href=&quot;https://chrome.google.com/webstore/category/extensions&quot;&gt;chrome web store&lt;/a&gt;.
Follow the instructions to create your wallet and write down the &lt;strong&gt;12 words&lt;/strong&gt; that make up the &lt;strong&gt;secret recovery phrase&lt;/strong&gt;, because they will be needed later for the deploy part.&lt;/p&gt;

&lt;p&gt;As a test, it shouldn’t be on the Ethereum mainnet, but on a testnet, specifically the Goerli testnet. The following part shows how to change the selected network:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;On the top right of the MetaMark interface click on Ethreum Mainnet;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Click on Show/hide test networks;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/metamask-1.png&quot; alt=&quot;MetaMask-1&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Enable “Show test networks”;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/metamask-2.png&quot; alt=&quot;MetaMask-2&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Go back and select “Goerli test network”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/metamask-3.png&quot; alt=&quot;MetaMask-3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now the wallet is ready to interact with the Goerli test network. Since funds are required for each transaction, you can receive GoerliETH tokens through these links:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://goerlifaucet.com/&quot;&gt;https://goerlifaucet.com/&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;ttps://faucets.chain.link/&quot;&gt;https://faucets.chain.link/&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copy and paste the wallet address from MetaMask on one or both the previous website to get 0.2 or 0.1 GoerliETH.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/metamask-4.png&quot; alt=&quot;MetaMask-4&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;installing-the-required-packages&quot;&gt;Installing the required packages&lt;/h2&gt;

&lt;p&gt;Thanks to Node.js the boilerplate can work properly with the required packages.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@truffle/hdwallet-provider&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.5.1&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ganache-cli&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^6.12.2&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mocha&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^9.1.2&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;solc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^0.8.9&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;web3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.6.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;🚨 All packages can be installed automatically with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; in the project folder, because they are already specified in the package.json.&lt;/p&gt;

&lt;p&gt;Required packages are listed below with a brief description:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;@truffle/hdwallet-provider&lt;/strong&gt; - HD Wallet-enabled Web3 provider.
It is necessary to use the wallet in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.js&lt;/code&gt; file. The first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&quot;&lt;/code&gt; must be filled with the &lt;strong&gt;12 words&lt;/strong&gt; that form the &lt;strong&gt;secret recovery phrase&lt;/strong&gt; of the MetaMask wallet, the second with the Infura endpoints, which will be explained later.&lt;/p&gt;

    &lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HDWalletProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Wallet secret recovery phrase&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Infura endpoints&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;The hdwallet-provider also allows you to select which wallet account should be used to perform the action.&lt;/p&gt;

    &lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;web3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAccounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Get all the accounts in the wallet&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;gas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Send the transaction from the first account&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ganache-cli&lt;/strong&gt; - Ganache CLI uses ethereumjs to &lt;strong&gt;simulate full client&lt;/strong&gt; behavior and make Ethereum application development faster, easier, and more secure. Ganache CLI is needed to test the smart contract without deploying it on a real blockchain (test or mainnet). Required in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test/Foo.test.js&lt;/code&gt; .&lt;/p&gt;

    &lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ganache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ganache-cli&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Web3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;web3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;web3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Web3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ganache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;mocha&lt;/strong&gt; - Mocha is a feature-rich JavaScript &lt;strong&gt;test framework&lt;/strong&gt; running on Node.js and in the browser, making asynchronous testing &lt;em&gt;simple&lt;/em&gt;. Mocha provide the following functions (used in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test/Foo.test.js&lt;/code&gt;):&lt;/p&gt;

    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th style=&quot;text-align: center&quot;&gt;Function&lt;/th&gt;
          &lt;th style=&quot;text-align: center&quot;&gt;Purpose&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td style=&quot;text-align: center&quot;&gt;it&lt;/td&gt;
          &lt;td style=&quot;text-align: center&quot;&gt;Run a test and make an assertion.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td style=&quot;text-align: center&quot;&gt;describe&lt;/td&gt;
          &lt;td style=&quot;text-align: center&quot;&gt;Groups togheter ‘it’ functions.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td style=&quot;text-align: center&quot;&gt;beforeEach&lt;/td&gt;
          &lt;td style=&quot;text-align: center&quot;&gt;Execute some general setup code before each test.&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;solc&lt;/strong&gt; - JavaScript bindings for the &lt;a href=&quot;https://github.com/ethereum/solidity&quot;&gt;Solidity compiler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;web3&lt;/strong&gt; - Web3.js is a collection of libraries which allow you to interact with a local or remote ethereum node, using a HTTP or IPC connection.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;foo-smart-contract&quot;&gt;Foo Smart Contract&lt;/h2&gt;

&lt;p&gt;The boilerplate contains a simple smart contract named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo.sol&lt;/code&gt; with the following code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

contract Foo {
    string public message;

    constructor(string memory defaultMessage) {
        message = defaultMessage;
    }

    function setMessage(string memory newMessage) public {
        message = newMessage;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As we can see, this smart contract is really simple and clear, it contains a string that we set with the constructor function when we deploy the contract, and a function that allows us to change the string. A basic smart contract like this is clearly good for understanding the process of deploying and testing.&lt;/p&gt;

&lt;h3 id=&quot;local-deployment&quot;&gt;Local deployment&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo.test.js&lt;/code&gt; first simulates the deployment in a local Ethereum chain (thanks to Ganache) with the string value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;This is a real foo contract, not smart at all.&quot;&lt;/code&gt; passed in the constructor:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;web3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAccounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;web3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;abi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;evm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bytecode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;This is a real foo contract, not smart at all.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;gas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;#deploy-details&quot;&gt;deploy details…&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then (using Mocha) tests if the contract is successfully deployed, the default message is present as expected, and also tests the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setMessage&lt;/code&gt; function by passing another string to check if it changes correctly.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Contract deployed successfully.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Default message correctly setted.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;This is a real foo contract, not smart at all.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;setMessage function works properly.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;The foo has been changed.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;The foo has been changed.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the project folder, a test can be run with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm run test&lt;/code&gt; and the output will look like the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/foo-testrun.png&quot; alt=&quot;Foo Test&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If the three tests are passed, the smart contract works as expected and can be deployed in a real blockchain (test or mainnet).&lt;/p&gt;

&lt;h2 id=&quot;deployment-on-the-goerli-testnet&quot;&gt;Deployment on the Goerli testnet&lt;/h2&gt;

&lt;p&gt;After testing, the contract is ready to be deployed on the Goerli test network. To accomplish this task, we need a provider instead of Ganache that will allow us to communicate and interact with the real blockchain. After an account is created on &lt;a href=&quot;https://www.infura.io/&quot;&gt;https://www.infura.io/&lt;/a&gt;, a new key can be generated.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/infura-1.png&quot; alt=&quot;Infura-1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, Goerli testnet can be selected and finally a url endpoint can be received for deployment.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/infura-2.png&quot; alt=&quot;Infura-2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The endpoint must be inserted in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.js&lt;/code&gt; file, as previously described:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HDWalletProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;birth hour hundred tuna confirm stove busy laugh initial spy sock start&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Wallet secret recovery phrase&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://goerli.infura.io/v3/ca6a6e33f51643fca72535c93625932a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Infura endpoints&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, the Foo smart contract can be deployed by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node deploy.js&lt;/code&gt;, displaying the contract address as in the following image:
&lt;img src=&quot;/assets/posts/hands-on-foo-contract/deploy.png&quot; alt=&quot;Deploy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once you have received the address of the smart contract, the process is complete and the contract is actually on the chain.&lt;/p&gt;

&lt;h2 id=&quot;contract-verification-with-etherscan&quot;&gt;Contract verification with Etherscan&lt;/h2&gt;

&lt;p&gt;The Foo Smart Contract is located in the Goerli test network and is visible to everyone via the blockchain explorer &lt;a href=&quot;https://goerli.etherscan.io&quot;&gt;https://goerli.etherscan.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/etherscan-1.png&quot; alt=&quot;Etherscan-1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The source code can be viewed by clicking on the “&lt;strong&gt;Contract&lt;/strong&gt;” section;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/etherscan-2.png&quot; alt=&quot;Etherscan-2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The “&lt;strong&gt;Read Contract&lt;/strong&gt;” section contains the message that was set in the deployment phase;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/etherscan-3.png&quot; alt=&quot;Etherscan-3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And the “&lt;strong&gt;Write Contract&lt;/strong&gt;” section allows (through connection with MetaMask) the use of the setMessage function.
&lt;img src=&quot;/assets/posts/hands-on-foo-contract/etherscan-4.png&quot; alt=&quot;Etherscan-4&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;deploy-details&quot;&gt;Deploy details&lt;/h2&gt;

&lt;p&gt;The deploy function also requires the bytecode (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evm.bytecode.object&lt;/code&gt;) of the smart contract generated by solc (the Solidity compiler) to be interpreted by the Ethereum Virtual Machine. Obviously the bytecode isn’t human readable, for clarity and better understanding of the compilation process a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log(module.exports);&lt;/code&gt; can be added to the end of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile.js&lt;/code&gt; file. After running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node compile&lt;/code&gt;, the ABI (which defines the methods and structures for interacting with the binary contract) and the bytecode can be viewed and look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/abi.png&quot; alt=&quot;ABI&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/hands-on-foo-contract/bytecode.png&quot; alt=&quot;bytecode&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy()&lt;/code&gt; function, there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send()&lt;/code&gt; function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;...
	.send({ from: accounts[0], gas: &quot;1000000&quot; });
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since each Ethereum transaction requires computational resources to be executed, there is a fee. Gas refers to the fee required to successfully complete a transaction on Ethereum and is expressed in Gwei. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gas&lt;/code&gt; parameter &lt;strong&gt;sets a limit of Gwei&lt;/strong&gt; that the sender allows to process the transaction.&lt;/p&gt;

&lt;p&gt;Wei is the smallest denomination of ether in Etheruem. One ether is one quintillion or 10^18 weis. The following table is a list of the named denominations and their value in wei:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Unit&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Wei Value&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Wei&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;wei&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1 wei&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Kwei (babbage)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10^3 wei&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1,000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Mwei (lovelace)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10^6 wei&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1,000,000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Gwei (shannon)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10^9 wei&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1,000,000,000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;microether (szabo)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10^12 wei&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1,000,000,000,000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;milliether (finney)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10^15 wei&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1,000,000,000,000,000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;ether&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;10^18 wei&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1,000,000,000,000,000,000&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.udemy.com/course/ethereum-and-solidity-the-complete-developers-guide/&quot;&gt;Ethereum and Solidity: The Complete Developer’s Guide&lt;/a&gt; - Created by Stephen Grider&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Blockchain introduction</title>
    <link href="https://davdifr.com/posts/blockchain-introduction/"/>
    <id>https://davdifr.com/posts/blockchain-introduction/</id>
    <published>2022-10-24T18:36:00+02:00</published>
    <updated>2024-09-25T12:34:02+02:00</updated>
    <category term="Tech Research"/>
    <category term="Blockchain"/>
    <summary>On October 31, 2008, Satoshi Nakamoto published a white paper entitled “Bitcoin: A peer-to-peer electronic cash system”, in which he described a system that would enable P2P payments without a financial intermediary.</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;On October 31, 2008, Satoshi Nakamoto published a white paper entitled “&lt;a href=&quot;https://bitcoin.org/bitcoin.pdf&quot;&gt;Bitcoin: A peer-to-peer electronic cash system&lt;/a&gt;”, in which he described a system that would enable P2P payments without a financial intermediary.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The blockchain is a &lt;strong&gt;P2P transaction model&lt;/strong&gt; that enables two parties to transact in a &lt;strong&gt;temper-resistant&lt;/strong&gt; and &lt;strong&gt;cryptographically proven&lt;/strong&gt; way. Essentially, it relies on three pillars: peer-to-peer networks, cryptography, and a consensus mechanism.&lt;/p&gt;

&lt;p&gt;Each computer participating in this P2P network is called a &lt;strong&gt;node&lt;/strong&gt;. Each node stores records of transactions in multiple &lt;strong&gt;consecutive blocks&lt;/strong&gt;. Once all nodes in the network have stored and verified a transaction, it is impossible to change the transaction without changing all subsequent and previous blocks. For this reason, blockchain transactions are &lt;strong&gt;irreversible&lt;/strong&gt;, as blockchain transactions and their data are only appended.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/blockchain-introduction/chain-of-blocks.svg&quot; alt=&quot;chain-of-blocks&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Blocks are connected by a link (also called a &lt;strong&gt;chain&lt;/strong&gt;). The link between two blocks &lt;em&gt;(Figure 1)&lt;/em&gt; is implemented by recording the previous block’s cryptographic hash so that it can be visited in reverse chronological order.&lt;/p&gt;

&lt;p&gt;The following table shows the data structure for a &lt;strong&gt;block header&lt;/strong&gt; (in Bitcoin):&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Field&lt;/th&gt;
      &lt;th&gt;Purpose&lt;/th&gt;
      &lt;th&gt;Updated when…&lt;/th&gt;
      &lt;th&gt;Size (Bytes)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Version&lt;/td&gt;
      &lt;td&gt;Block version number&lt;/td&gt;
      &lt;td&gt;You upgrade the software&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;hashPrevBlock&lt;/td&gt;
      &lt;td&gt;256-bit hash of the previous block header&lt;/td&gt;
      &lt;td&gt;A new block comes in&lt;/td&gt;
      &lt;td&gt;32&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;hashMerkleRoot&lt;/td&gt;
      &lt;td&gt;256-bit hash based on all of the transactions in the block&lt;/td&gt;
      &lt;td&gt;A transaction is accepted&lt;/td&gt;
      &lt;td&gt;32&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Time&lt;/td&gt;
      &lt;td&gt;Current timestamp as seconds&lt;/td&gt;
      &lt;td&gt;Every few seconds&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Bits&lt;/td&gt;
      &lt;td&gt;Current target in compact format&lt;/td&gt;
      &lt;td&gt;The difficulty is adjusted&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Nonce&lt;/td&gt;
      &lt;td&gt;32-bit number (starts at 0)&lt;/td&gt;
      &lt;td&gt;A hash is tried (increments)&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;In particular, hashPrevBlock refers to the 256-bit hash value of the previous block, and hashMerkleRoot is the hash Merkle root of all transactions in the block, including coinable transactions. And the nonce is the magic number that miners must find so that the SHA-256 hash value of the block header is smaller than or equal to the blockchain-defined specific target.&lt;/p&gt;

&lt;h2 id=&quot;transaction-process-overview&quot;&gt;Transaction process overview&lt;/h2&gt;

&lt;p&gt;Assuming user A wants to buy something from user B &lt;em&gt;(Figure 2)&lt;/em&gt; and agrees to pay B 10 Bitcoins (BTC), the transaction proceeds as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/blockchain-introduction/transaction-a-b.svg&quot; alt=&quot;transaction-a-b&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Create blockchain transactions:&lt;/strong&gt; A transaction is a transfer of value between two parties. When A sends 10 BTC to B, a transaction is created with one or more inputs and outputs, where the inputs reflect A’s account and the outputs reflect the accounts A wants to transfer. The transaction is digitally signed with A’s private key and broadcasted to the P2P network. The recipient uses the digital signature to verify ownership of A’s funds.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Validate the transactions and add them to the transaction pool:&lt;/strong&gt; Once the transaction is submitted to the blockchain network, the bookkeeper node (a node that receives the transactions) validates it according to the business and technical rules set by the blockchain network. If the transaction is valid, the bookkeeper adds it to the transaction pool and forwards the transaction to peers on the network.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Create the candidate blocks:&lt;/strong&gt; Transactions in the transaction pool are collected into a block at regular intervals. In a Bitcoin network, every 10 minutes a subset of network nodes called &lt;strong&gt;mining nodes&lt;/strong&gt; (or miners) collect all valid transactions from the transaction pool and create the candidate blocks.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mining the new block:&lt;/strong&gt; Once the block candidate is created, the race begins for the chance to add new blocks and win the rewards. The process of such a race is called &lt;strong&gt;mining&lt;/strong&gt;. The winner of the race is determined by the consensus mechanism (in this case the PoW mechanism, which will be described in the next part). The miners keep trying to find a random number, the nonce in the block header structure, until the hash meets certain demanding conditions. For example, one of these conditions is that &lt;em&gt;the resulting block hash is less than a target number&lt;/em&gt;, or in some cases, the &lt;em&gt;hash has a few leading zeros&lt;/em&gt;. In practice, any random number has an equal chance of winning the race, so you can practically just start a loop from 1 to 2^32 until you find such a nonce. It takes a tremendous CPU hashing effort to find such a nonce. The challenging condition, called difficulty, can be adjusted based on the target count or bits in the block header structure. The difficulty of winning the race grows exponentially with the smaller target number or fewer bits in the block header structure.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Add a new block to the blockchain:&lt;/strong&gt; The first winning node will announce the new block to the rest of the network for verification. Once the block is verified and approved by the majority of the network’s miners, it will be accepted and form the new top of the chain. Since all blocks are chained together by linking the hash value to the previous block, any change to the ledger becomes impossible as it requires PoW for all previous transitions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;consensus-mechanism&quot;&gt;Consensus mechanism&lt;/h2&gt;

&lt;p&gt;Consensus in a blockchain is the process by which a network of mutually distrustful nodes reaches an agreement on the global state of the blockchain. In a blockchain, transactions or data are shared and distributed across the network and each node has the same copy of the blockchain data. Consensus allows all network nodes to follow the same rules when validating transactions and adding new blocks to the chain, ensuring uniformity across all copies of a blockchain.
A consensus algorithm is a formal procedure or computer program for solving a consensus problem based on performing a series of specific actions. It is designed to be feasible on a network with multiple nodes. Consensus algorithms ensure that the next block in a blockchain is fully validated and secured. Currently, there are several types of consensus algorithms, each with different basic procedures. The two most popular algorithms are as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Proof of Work (PoW)&lt;/strong&gt;: This consensus algorithm was introduced by Satoshi and has been widely adopted by many other blockchain systems. The PoW is the mining process aimed at finding an answer to a cryptographic hashing problem. To do this, the miner must follow the block selection rules to find the previous block and use the hash of the previous block header along with the Merkle root of the current transactions in the new block to solve the hashing problem. This requires significant computation and hashing power. Any number between 0 and 2^32 has an equal chance of solving the puzzle. The loop solution to satisfy the criteria is shown in the diagram below:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/posts/blockchain-introduction/pow-flowchart.svg&quot; alt=&quot;pow-flowchart&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;After notification, the other nodes of the network automatically check if the results are valid. If the results are valid, they add the block to their copies of the blockchain, stop the ongoing mining, and proceed to the next block.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Proof of Stake (PoS)&lt;/strong&gt;: This consensus algorithm aims to select miners based on various combinations of random choices based on miners’ wealth or age (stake). Rather than miners competing with each other to solve energy-consuming cryptographic hash functions, the network will instead use a pool of validators. &lt;strong&gt;Validators&lt;/strong&gt; are nodes (which can run on a regular laptop) that are willing to stake their cryptocurrency on the transaction blocks they claim should be added to the public blockchain. Staking makes it easier for individuals to participate in securing the network and promotes decentralization.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;forks&quot;&gt;Forks&lt;/h2&gt;

&lt;p&gt;A fork in the blockchain occurs when there are two different ways to proceed, and can be intentional or accidental. An intentional fork occurs when the blockchain software or rules are to be updated/changed, and an accidental fork occurs when two or more miners find a block almost simultaneously. Each time a fork occurs, miners must “choose” which direction to take, meaning each miner votes on what is the right decision for the entire chain. A fork is resolved when more blocks are added and one of the chains becomes longer than the other(s) &lt;em&gt;(Figure 4)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/blockchain-introduction/blockchain-fork.svg&quot; alt=&quot;blockchain-fork&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The network abandons the blocks that are not in the longest chain (they are called orphan blocks) and continues. The blockchain works with a democratic policy, which means that it is always the majority that decides which way to go. The only way a breach can occur is if there is an attack, called a 51% attack, where the majority of nodes are compromised or choose to act maliciously.&lt;/p&gt;

&lt;h2 id=&quot;ethereum&quot;&gt;Ethereum&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Proposed by Vitalik Buterin in “&lt;a href=&quot;https://ethereum.org/669c9e2e2027310b6b3cdce6e1c52962/Ethereum_Whitepaper_-_Buterin_2014.pdf&quot;&gt;Ethereum: A Next-Generation Smart Contract and Decentralized Application Platform&lt;/a&gt;“.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ethereum is an implementation of the blockchain and is an open source, public, and decentralized computing platform. Public means that anyone can view the account balance and transaction history of any wallet at any time by simply accessing the public Ethereum blockchain through a block explorer. Ethereum became popular thanks to the implementation of &lt;strong&gt;smart contracts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Smart contracts are small programs (written in the Solidity language) in which developers can define the rules of the trust they intend to code. One of the most amazing features of smart contracts is their immutability.
Once implemented on the blockchain, their code cannot be changed. This immutable property makes it very difficult to program smart contracts and detect errors in advance, and that is the reason why &lt;strong&gt;testnets&lt;/strong&gt; exist.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testnets are the replica of the mainnet Ethereum blockchain where developers can deploy their contracts. If the contracts work properly on testnets then they will work perfectly on the mainnet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ethereum also introduced the concept of world state and account. The world state includes a mapping of all accounts and their public addresses. To facilitate both state transactions and decentralized computing, Ethereum introduces two types of accounts: &lt;strong&gt;Externally Owned Accounts (EOAs)&lt;/strong&gt;, which are controlled by private keys, and &lt;strong&gt;Contract Accounts (CA)&lt;/strong&gt;, which are controlled by their contract code. Without CAs, Ethereum would be limited to the mere transfer of value between parties, as with Bitcoin.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://bitcoin.org/bitcoin.pdf&quot;&gt;Bitcoin: A peer-to-peer electronic cash system&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.bitcoin.it/wiki/Block&quot;&gt;https://en.bitcoin.it/wiki/Block&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ethereum.org/669c9e2e2027310b6b3cdce6e1c52962/Ethereum_Whitepaper_-_Buterin_2014.pdf&quot;&gt;Ethereum Whitepaper&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Mastering-Blockchain-Programming-Solidity-production-ready/dp/1839218266&quot;&gt;Mastering Blockchain Programming with Solidity&lt;/a&gt; - Jitendra Chittoda&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Learn-Ethereum-decentralized-applications-contracts/dp/1789954118/ref=sr_1_1?crid=1R4FU0HKYPRVR&amp;amp;keywords=learn+ethereum&amp;amp;qid=1665334863&amp;amp;qu=eyJxc2MiOiIwLjYyIiwicXNhIjoiMC41NyIsInFzcCI6IjAuNzcifQ%3D%3D&amp;amp;s=books&amp;amp;sprefix=learn+ethereum%2Cstripbooks-intl-ship%2C263&amp;amp;sr=1-1&quot;&gt;Learn Ethereum&lt;/a&gt; - Xun Wu, Zhihong Zou and Dongying Song&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Non-Fungible Tokens explained</title>
    <link href="https://davdifr.com/posts/nfts-explained/"/>
    <id>https://davdifr.com/posts/nfts-explained/</id>
    <published>2022-10-10T18:01:00+02:00</published>
    <updated>2024-09-25T12:34:02+02:00</updated>
    <category term="Tech Research"/>
    <category term="Blockchain"/>
    <summary>A non-fungible token (NFT) refers to a class of blockchain-based tokens that are intended to be unique, as opposed to cryptocurrencies where all tokens are exchangeable. NFTs are typically used to prove ownership and can represent virtually any asset, whether physical or digital. However, the most common NFT assets are digital art, digital collectibles, content such as video or audio, and event tickets.</summary>
    <content type="html">&lt;p&gt;A &lt;strong&gt;non-fungible token&lt;/strong&gt; (NFT) refers to a class of blockchain-based tokens that are intended to be &lt;strong&gt;unique&lt;/strong&gt;, as opposed to cryptocurrencies where all tokens are exchangeable. NFTs are typically used to &lt;strong&gt;prove ownership&lt;/strong&gt; and can represent virtually any asset, whether physical or digital. However, the most common NFT assets are digital art, digital collectibles, content such as video or audio, and event tickets.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“NFT Art gives anyone a stake in something that they feel is significant and culturally relevant. Valuable Art is something the 1% has had a monopoly on. NFT art allows the 99% to become involved.” — Kevin Godfrey, Fabriik CTO&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nowadays the market for NFTs is growing rapidly especially in the collector sector with the trend of profile pictures (PFPs), which are attracting a lot of interest. Even major platforms like Instagram and Twitter are introducing them, which is undoubtedly remarkable. Mainstream interest in non-fungible tokens reached a fever pitch in late 2021, when the market grew 21,000% to $17.6 billion, according to &lt;a href=&quot;https://nonfungible.com&quot;&gt;nonfungible.com&lt;/a&gt; and &lt;a href=&quot;https://atelier.net/&quot;&gt;L’Atelier&lt;/a&gt;. The most widely used store for buying NFTs (&lt;a href=&quot;https://opensea.io/&quot;&gt;OpenSea&lt;/a&gt;) saw record sales of $2 billion in January 2022 alone. The huge USD volume traded in 2022 is shown in the following pie chart by interest category:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/nfts-explained/nfts-usd-volume.svg&quot; alt=&quot;nfts-usd-volume&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Some collections, such as the &lt;a href=&quot;https://opensea.io/collection/boredapeyachtclub&quot;&gt;Bored Ape Yacht Club&lt;/a&gt; (BAYC), have become nothing less than status symbols. Although they were originally intended as a joke, to this day they are no longer normal NFTs, and owning one of them is no less than owning a Ferrari. Steph Curry (a famous basketball player) bought the Bored Ape #7990 NFT in 2021 for $180,000. Other celebrities like Eminem, Snoop Dogg, Serena Williams, and Neymar own some of the most expensive PFPs out there, and they use them on their social networks.&lt;/p&gt;

&lt;p&gt;The following table provides some information on 5 of the most profitable NFTs sold in Q2 2022:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;NFT&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Project&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Days since purchase&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Purchase Price (USD)&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Resale Price (USD)&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Profit (USD)&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Profit (%)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;/assets/posts/nfts-explained/cryptopunk.png?fit=max&amp;amp;w=80&quot; alt=&quot;CryptoPunk #7756&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://opensea.io/collection/cryptopunks&quot;&gt;CryptoPunks&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;583&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$9,337&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$3,261,857&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3,252,519&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;34,833%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;/assets/posts/nfts-explained/otherside.png?fit=max&amp;amp;w=80&quot; alt=&quot;OtherSide #59906&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://opensea.io/collection/otherdeed&quot;&gt;Otherdeed for Otherside&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;7&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$5,905&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$1,647,788&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1,641,883&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;27,806%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;/assets/posts/nfts-explained/ape.png?fit=max&amp;amp;w=80&quot; alt=&quot;Ape #6388&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://opensea.io/collection/boredapeyachtclub&quot;&gt;Bored Ape Yacht Club&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;377&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$107,000&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$1,083,512&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$976,512&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;913%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;/assets/posts/nfts-explained/ape2.png?fit=max&amp;amp;w=80&quot; alt=&quot;Ape #7537&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://opensea.io/collection/boredapeyachtclub&quot;&gt;Bored Ape Yacht Club&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;85&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$298,001&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$1,222,922&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$924,921&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;310%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;/assets/posts/nfts-explained/moonbirds.png?fit=max&amp;amp;w=80&quot; alt=&quot;Moonbirds #3904&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://opensea.io/collection/proof-moonbirds&quot;&gt;Moonbirds&lt;/a&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;7&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$7,554&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$902,498&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;$894,944&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;11,847%&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;This kind of value enhancement is possible thanks to the great interest that NFTs experience on the Internet.
Every day, more and more companies are trying to incorporate NFTs into their marketing strategies, and this has also happened in the fashion industry. Luxury brands such as Dolce &amp;amp; Gabbana, Gucci, Louis Vuitton and Burberry have actively ventured into the digital space, looking for ways to incorporate NFTs into their product range and marketing efforts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Please note that this article isn’t intended as financial advice. The previous part was intended to show and appreciate the worldwide interest in this technology, and there’s no intention to suggest a financial investment.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;technical-details&quot;&gt;Technical details&lt;/h2&gt;

&lt;p&gt;For a better understanding of the following explanations, some key terms are defined here in a simplified way:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Smart contract&lt;/strong&gt; - A smart contract is an application that runs on the blockchain. Every smart contract has some functions, some state and an address.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ERCs&lt;/strong&gt; - ERCs (Ethereum Request for Comments) are technical documents used by smart contract developers at Ethereum. They define a set of rules required to implement tokens for the Ethereum ecosystem.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Wallet Address&lt;/strong&gt; - A wallet address is a string of letters and numbers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x04600C3E...ff49628&lt;/code&gt;) from which cryptocurrencies or NFTs can be sent to and from.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ethereum was the first blockchain to support NFTs with its inheritable standard &lt;strong&gt;ERC-721&lt;/strong&gt;. This means that developers can create new ERC-721-compliant contracts by copying a &lt;a href=&quot;https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol&quot;&gt;reference implementation&lt;/a&gt; that provides core methods for tracking the owner of a unique identifier and a way for the owner to transfer the asset to others.&lt;/p&gt;

&lt;p&gt;There are many standards in Ethereum; ERC20, for example, is the most popular token standard used to create fungible tokens like coins that have economic value.&lt;/p&gt;

&lt;p&gt;Here are some differences between the ERC20 and the ERC721 standard:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Property&lt;/th&gt;
      &lt;th&gt;ERC20 token standard&lt;/th&gt;
      &lt;th&gt;ERC721 NFT standard&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Fungibility&lt;/td&gt;
      &lt;td&gt;Tokens are fungible up to the decimal places specified in the contract.&lt;/td&gt;
      &lt;td&gt;Tokens are not fungible. Each token itself represents 1 asset that cannot be subdivided.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Ownership&lt;/td&gt;
      &lt;td&gt;Token ownership is not directly linked to an account, and only the token balances are tracked.&lt;/td&gt;
      &lt;td&gt;Ownership of each token is tied to an individual account address.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Uniqueness&lt;/td&gt;
      &lt;td&gt;There is no difference in each token.&lt;/td&gt;
      &lt;td&gt;Each token is different from every other token included in the same contract.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The main feature of ERC-721 is that each token is unique. When an ERC-721 token is created, there is only one copy. These tokens, as NFTs, have spread the idea and application of &lt;strong&gt;unique assets&lt;/strong&gt; on Ethereum.&lt;/p&gt;

&lt;p&gt;The following figure &lt;em&gt;(Figure 1)&lt;/em&gt; helps to better understand what it means that ERC20 maps addresses to amounts and ERC721 maps unique IDs to owners.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/nfts-explained/anatomy-erc20-erc721.svg&quot; alt=&quot;erc20-erc721&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The descriptive information of a particular ERC721 token is provided by its &lt;strong&gt;metadata&lt;/strong&gt; and might look something like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Token #1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://example.org/1.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;This is the token n.1&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are two options for representing metadata: On-chain and off-chain.
In the on-chain approach, metadata is stored permanently with the token and persists beyond the lifecycle of a particular application. Moreover, they can change according to the on-chain logic. Despite these benefits, most projects store their metadata off-chain &lt;em&gt;(Figure 2)&lt;/em&gt; simply due to the current storage limitations of the Ethereum blockchain.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/nfts-explained//off-chain-metadata.svg&quot; alt=&quot;off-chain-metadata&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The ERC721 standard includes (in an optional interface called ERC721Metadata) a function called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenURI&lt;/code&gt; that developers can implement to tell applications where to find the metadata for a given item.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function tokenURI(uint256 _tokenId) public view returns (string)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenURI&lt;/code&gt; returns the Uniform Resource Identifier (URI) as data type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt;. This in turn returns a JSON file that conforms to the ERC721 metadata schema.&lt;/p&gt;

&lt;h2 id=&quot;an-in-depth-insight-into-erc-721&quot;&gt;An in-depth insight into ERC-721&lt;/h2&gt;

&lt;p&gt;Each ERC721 token must implement nine mandatory functions and is defined as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;interface ERC721 {
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

    function balanceOf(address _owner) external view returns (uint256);
    function ownerOf(uint256 _tokenId) external view returns (address);
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function approve(address _approved, uint256 _tokenId) external payable;
    function setApprovalForAll(address _operator, bool _approved) external;
    function getApproved(uint256 _tokenId) external view returns (address);
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;balanceOf()&lt;/code&gt; function in the following code returns the total number of tokens for the specified address:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function balanceOf(address _owner) public view returns (uint256) {
	require(owner != address(0));
	return _ownedTokensCount[owner];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;Anyone is allowed to call this function, as it is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;view&lt;/code&gt; function, to read the value for off-chain calculation as well.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ownerOf()&lt;/code&gt; function finds the provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenId&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_tokenOwner&lt;/code&gt; map and returns the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address&lt;/code&gt; of its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;owner&lt;/code&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function ownerOf(uint256 tokenId) public view returns (address) {
	address owner = _tokenOwner[tokenId];
	require(owner != address(0));
	return owner;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;If the specified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenId&lt;/code&gt; does not exist in the mapping, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address(0)&lt;/code&gt; is assigned to the local variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;owner&lt;/code&gt; and the function call fails.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;approve()&lt;/code&gt; function approves permission from another entity to transfer a token on behalf of the owner. The function requires that the sender of the message is the owner of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenId&lt;/code&gt;. The approved token is stored in the mapping shop of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenApprovals&lt;/code&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function approve(address to, uint256 tokenId) public {
	address owner = ownerOf(tokenId);
	require(to != owner);
	require(msg.sender == owner || isApproveForAll(owner, msg.sender));

	_tokenApprovals[tokenId] = to;
	emit Approval(owner, to, tokenId);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;approve()&lt;/code&gt; function can also be called by the operator (who has rights to the owner’s tokens). The operator can also grant approvals to another account. There are two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; checks, the one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require(to != owner)&lt;/code&gt; ensures that the operator cannot grant any other approvals to the token &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;owner&lt;/code&gt;. The second &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; ensures that the sender is either the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;owner&lt;/code&gt; or has operator rights. After these checks are made, the token approval is issued to the address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to&lt;/code&gt; for the specified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenId&lt;/code&gt;. Finally, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Approval&lt;/code&gt; event is issued along with the approval data.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getApproved()&lt;/code&gt; function verifies and makes sure that the transaction senders are the owners of the token and that the token transfer gets approved:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function getApproved(uint256 tokenId) public view returns (address) {
	require(_exists(tokenId));
	return _tokenApprovals[tokenId];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;The function calls an internal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_exists()&lt;/code&gt; function to ensure that the given &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenId&lt;/code&gt; exists and that it has been assigned to a non-&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address(0)&lt;/code&gt; owner, otherwise, the function call fails.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setApprovalForAll&lt;/code&gt; function enables or disables the approval of a third party (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operator&lt;/code&gt;) to manage all of the assets for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg.sender&lt;/code&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function setApprovalForAll(address to, bool approved) public {
	require(to != msg.sender);
	_operatorApprovals[msg.sender][to] = approved;
	emit ApprovalForAll(msg.sender, to, approved);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;The argument &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;approved&lt;/code&gt; is a boolean value that specifies whether the approval should be granted or revoked.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isApprovedForAll()&lt;/code&gt; function checks that the given operator has operator rights on the given owner’s tokens:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function isApprovedForAll(address owner, address operator) public view returns (bool) {
	return _operatorApprovals[owner][operator];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;It fetches the read-only data from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_operatorApprovals&lt;/code&gt; mapping.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transferFrom()&lt;/code&gt; function transfers ownership of an NFT:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function transferFrom(address from, address to, uint256 tokenId) public {
	require(_isApprovedOrOwner(msg.sender, tokenId));
	_transferFrom(from, to, tokenId);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;The function first validates that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg.sender&lt;/code&gt; (function caller) has the necessary permissions to transfer the given &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokenId&lt;/code&gt;. Once it is verified, the internal call to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_transferFrom()&lt;/code&gt; function transfers the token from the owner’s account to the recipient’s account.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeTransferFrom()&lt;/code&gt; function is used to safely transfer the NFT from the owner’s account to the recipient’s account:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function safeTransferFroom(address from, address to, uint256 tokenId, bytes memory _data) public {
	transferFrom(from, to, tokenId);
	require(_checkOnERC721Received(from, to, tokenId, _data));
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;Safely transfer here means that if the recipient is a contract, you must ensure that the “recipient contract” has registered callbacks so that the “receiver contract” gets a notification when the ERC721 token transfer is successful.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There is another function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;safeTransferFrom()&lt;/code&gt; which is used when the recipient of the NFT is an &lt;strong&gt;Externally Owned Account (EOA)&lt;/strong&gt; and not a contract account:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function safeTransferFrom(address from, address to, uint256 tokenId) public {
	safeTransferFrom(from, to, tokenId, &quot;&quot;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The standard interface discussed is taken from the EIP standard document at &lt;a href=&quot;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md&quot;&gt;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Non-fungible_token&quot;&gt;Non-fungible token&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://eips.ethereum.org&quot;&gt;Ethereum Improvement Proposals&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://nonfungible.com&quot;&gt;nonfungible.com&lt;/a&gt; - 2022 NFT Market report Q2&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://atelier.net/news/report-17.6-billion-in-nft-trades-during-2021&quot;&gt;Report: $17.6 billion in NFT trades during 2021&lt;/a&gt; - L’Atelier&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://opensea.io/blog/guides/non-fungible-tokens/&quot;&gt;The Non-Fungible Token Bible: Everything you need to know about NFTs&lt;/a&gt; - Devin Finzer&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Mastering-Blockchain-Programming-Solidity-production-ready/dp/1839218266&quot;&gt;Mastering Blockchain Programming with Solidity&lt;/a&gt; - Jitendra Chittoda&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Learn-Ethereum-decentralized-applications-contracts/dp/1789954118/ref=sr_1_1?crid=1R4FU0HKYPRVR&amp;amp;keywords=learn+ethereum&amp;amp;qid=1665334863&amp;amp;qu=eyJxc2MiOiIwLjYyIiwicXNhIjoiMC41NyIsInFzcCI6IjAuNzcifQ%3D%3D&amp;amp;s=books&amp;amp;sprefix=learn+ethereum%2Cstripbooks-intl-ship%2C263&amp;amp;sr=1-1&quot;&gt;Learn Ethereum&lt;/a&gt; - Xun Wu, Zhihong Zou and Dongying Song&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>NFTs as credentials (?)</title>
    <link href="https://davdifr.com/posts/nfts-as-credentials/"/>
    <id>https://davdifr.com/posts/nfts-as-credentials/</id>
    <published>2022-10-07T19:00:00+02:00</published>
    <updated>2024-09-25T12:34:02+02:00</updated>
    <category term="Tech Research"/>
    <category term="Digital Credentials"/>
    <summary>As we saw in the previous article, there are different implementations and standards in the world of digital credentials. The idea of certifying one’s identity and competence with the digital signature of the issuer is undoubtedly very effective, especially when accompanied by a graphic aspect in the form of a recognition medal.</summary>
    <content type="html">&lt;p&gt;As we saw in the &lt;a href=&quot;https://davdifr.github.io/digitalcredentials/2022/09/22/exploring-digital-credentials.html&quot;&gt;previous article&lt;/a&gt;, there are different implementations and standards in the world of digital credentials. The idea of certifying one’s identity and competence with the digital signature of the issuer is undoubtedly very effective, especially when accompanied by a graphic aspect in the form of a recognition medal.&lt;/p&gt;

&lt;p&gt;However, the use of a verification tool (which cannot be universal given the different implementations) is essential and preservation also requires the use of third-party applications.&lt;/p&gt;

&lt;p&gt;So we might ask: &lt;strong&gt;What if we used NFTs as credentials?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Something belonging to an entity can be identified by either an NFT or a VC. The records of both are immutable (therefore secure), but there are significant differences. VCs use public-key infrastructure and digital signatures to prove a claim; they are not publicly viewable but are selectively shared with verifying parties as needed.&lt;/p&gt;

&lt;p&gt;In a post titled “&lt;a href=&quot;https://vitalik.ca/general/2022/06/12/nonfin.html&quot;&gt;Where to use a blockchain in non-financial applications&lt;/a&gt;” Vitalik Buterin (Ethereum co-founder) said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;With off-chain claims, you can do *positive* reputation, because it’s in the interest of the recipient of a claim to show it to appear more reputable (or make a ZK-proof about it), but you can’t do *negative* reputation, because someone can always choose to only show the claims that make them look good and leave out all the others.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some situations may benefit from this kind of transparency, and NFTs provide these specifics due to the fact that they are blockchain-based and time-stamped. The digital ownership and the origin of a token can be easily verified, and if you know the wallet address, you can see all the NFTs that someone owns and has ever owned.&lt;/p&gt;

&lt;p&gt;Currently, VCs are the most practical technology to digitize our credentials and allow people to establish their identity on the Internet. While privacy and the lack of financial speculation are two major benefits of using VCs for digital identity, both factors have limited the social reach and adoption of the concept.
As we can see, the search volume for NFTs is several orders of magnitude higher than for VCs.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Keywords&lt;/th&gt;
      &lt;th&gt;Monthly search volume&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;nft&lt;/td&gt;
      &lt;td&gt;1.830.000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;non fungible tokens&lt;/td&gt;
      &lt;td&gt;60.500&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;verifiable credentials&lt;/td&gt;
      &lt;td&gt;8.100&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;w3c verifiable credentials&lt;/td&gt;
      &lt;td&gt;90&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The great interest in this technology could prepare the ground for a real spread of digital credentials.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://vitalik.ca/general/2022/06/12/nonfin.html&quot;&gt;Where to use a blockchain in non-financial applications&lt;/a&gt; - Vitalik Buterin&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tools.wordstream.com/&quot;&gt;WordStream&lt;/a&gt; used for keywords results&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
</feed>
