<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Awab Abdoun]]></title><description><![CDATA[Awab Abdoun]]></description><link>https://blog.awabcodes.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 09 Apr 2026 11:17:52 GMT</lastBuildDate><atom:link href="https://blog.awabcodes.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building a Currency Converter in Go]]></title><description><![CDATA[Introduction
In this post, we'll create a practical currency converter Command-Line Interface app using Go. It enables you to swiftly convert between currencies without leaving your terminal.
Setting Up
Before diving into the code, make sure you have...]]></description><link>https://blog.awabcodes.com/building-a-currency-converter-in-go</link><guid isPermaLink="true">https://blog.awabcodes.com/building-a-currency-converter-in-go</guid><category><![CDATA[Go Language]]></category><category><![CDATA[currency]]></category><dc:creator><![CDATA[Awab Abdoun]]></dc:creator><pubDate>Mon, 11 Sep 2023 09:23:43 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In this post, we'll create a practical currency converter Command-Line Interface app using Go. It enables you to swiftly convert between currencies without leaving your terminal.</p>
<h2 id="heading-setting-up"><strong>Setting Up</strong></h2>
<p>Before diving into the code, make sure you have Go installed on your system. Additionally, we'll be using Cobra, a popular Go library for building CLI applications. You can install it using the following command:<br /><code>go get -u</code> <a target="_blank" href="http://github.com/spf13/cobra/cobra"><code>github.com/spf13/cobra/cobra</code></a>.</p>
<h2 id="heading-designing-the-currency-converter"><strong>Designing the Currency Converter</strong></h2>
<p>Our currency converter CLI will take three arguments: the amount to convert, the source currency, and the target currency. It will fetch exchange rates from an external API and perform the conversion.</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> rootCmd = &amp;cobra.Command{
        Use:   <span class="hljs-string">"[amount] [source currency code] [target currency code]"</span>,
        Short: <span class="hljs-string">"convert amount to any currency"</span>,
        Long:  <span class="hljs-string">"convert amount from any currency to any other currency"</span>,
        Args:  cobra.ExactArgs(<span class="hljs-number">3</span>),
        Run: <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(cmd *cobra.Command, args []<span class="hljs-keyword">string</span>)</span></span> {
            amount, err := validateAmount(args[<span class="hljs-number">0</span>])
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                log.Fatal(err)
            }

            sourceCurrency, targetCurrency, err := validateCurrencyCodes(args[<span class="hljs-number">1</span>], args[<span class="hljs-number">2</span>])
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                log.Fatal(err)
            }

            result, err := convertCurrency(amount, sourceCurrency, targetCurrency)
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                log.Fatal(err)
            }

            log.Printf(<span class="hljs-string">"%f %v is %f %v"</span>, amount, sourceCurrency, result, targetCurrency)
        },
    }
</code></pre>
<h2 id="heading-validating-user-input"><strong>Validating User Input</strong></h2>
<p>We've included input validation to ensure that the user provides the correct number format for the amount and valid three-character currency codes for source and target currencies.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">validateAmount</span><span class="hljs-params">(amountInput <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">float64</span>, error)</span></span> {
    amount, err := strconv.ParseFloat(amountInput, <span class="hljs-number">64</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, errors.New(<span class="hljs-string">"Invalid amount. Please provide a valid number."</span>)
    }

    <span class="hljs-keyword">return</span> amount, <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">validateCurrencyCodes</span><span class="hljs-params">(sourceCurrency <span class="hljs-keyword">string</span>, targetCurrency <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>, error)</span></span> {
    re := regexp.MustCompile(<span class="hljs-string">"^[a-zA-Z]{3}$"</span>)
    <span class="hljs-keyword">if</span> !re.Match([]<span class="hljs-keyword">byte</span>(sourceCurrency)) || !re.Match([]<span class="hljs-keyword">byte</span>(targetCurrency)) {
        <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>, <span class="hljs-string">""</span>, errors.New(<span class="hljs-string">"Invalid currency code(s). Currency codes must be 3 characters long (e.g., USD)."</span>)
    }

    <span class="hljs-keyword">return</span> strings.ToUpper(sourceCurrency), strings.ToUpper(targetCurrency), <span class="hljs-literal">nil</span>
}
</code></pre>
<h2 id="heading-fetching-exchange-rates"><strong>Fetching Exchange Rates</strong></h2>
<p>The <code>convertCurrency</code> function fetches exchange rates from an external API (<a target="_blank" href="https://www.exchangerate-api.com/"><strong>ExchangeRate-API</strong></a> in this example) based on the source currency.</p>
<h2 id="heading-performing-currency-conversion"><strong>Performing Currency Conversion</strong></h2>
<p>Once we have the exchange rates, we can easily convert the amount from the source currency to the target currency using a simple formula.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">convertCurrency</span><span class="hljs-params">(amount <span class="hljs-keyword">float64</span>, from <span class="hljs-keyword">string</span>, to <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">float64</span>, error)</span></span> {
    res, err := http.Get(<span class="hljs-string">"https://open.er-api.com/v6/latest/"</span> + from)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, errors.New(<span class="hljs-string">"Failed to retrieve exchange rates. Please try again later."</span>)
    }

    <span class="hljs-keyword">defer</span> res.Body.Close()

    body, err := io.ReadAll(res.Body)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, errors.New(<span class="hljs-string">"Failed to read response body"</span>)
    }

    <span class="hljs-keyword">var</span> exchangeRates ExchangeRates

    err = json.Unmarshal(body, &amp;exchangeRates)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, errors.New(<span class="hljs-string">"Failed to unmarshal json"</span>)
    }

    <span class="hljs-keyword">if</span> exchangeRates.Result != <span class="hljs-string">"success"</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, errors.New(<span class="hljs-string">"Exchange rate api failed to get the rates"</span>)
    }

    <span class="hljs-keyword">return</span> amount * exchangeRates.Rates[to], <span class="hljs-literal">nil</span>
}
</code></pre>
<h2 id="heading-usage"><strong>Usage</strong></h2>
<p>You can build and execute the script with the provided command, providing the amount, source currency and target currency. The converter will display the converted amount in the target currency.</p>
<p><code>./currency-switch 10 eur aed</code></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In conclusion, we've created a simple yet effective currency converter CLI app in Go, enabling you to handle currency conversions with ease right from your terminal. Feel free to customize it to meet your specific requirements and take control of your currency conversions. Happy coding!</p>
<p>You can find the source code in this <a target="_blank" href="https://github.com/awabcodes/currency-switch"><strong>GitHub Repository</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Dynamic Forms in Angular: Simple Yet Powerful]]></title><description><![CDATA[Introduction
Building dynamic forms can be complex. In this blog post, we'll cover a simple yet powerful way of creating dynamic forms in Angular. We'll walk through the process of creating a form schema, converting it to Angular's ReactiveForms cont...]]></description><link>https://blog.awabcodes.com/angular-dynamic-forms</link><guid isPermaLink="true">https://blog.awabcodes.com/angular-dynamic-forms</guid><category><![CDATA[Angular]]></category><category><![CDATA[forms]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[dynamic forms]]></category><dc:creator><![CDATA[Awab Abdoun]]></dc:creator><pubDate>Tue, 16 May 2023 17:45:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684101665151/579864b7-93f0-463e-9e17-f85f60a8c2c0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Building dynamic forms can be complex. In this blog post, we'll cover a simple yet powerful way of creating dynamic forms in Angular. We'll walk through the process of creating a form schema, converting it to Angular's ReactiveForms controls, and finally building and using the form in our Angular component.</p>
<h2 id="heading-creating-the-dynamic-form">Creating the Dynamic Form</h2>
<p>To begin, we need to create a schema object that defines the form controls, validators, and other metadata. We can model and save this schema to a backend of our choice and load it through an API call. Here's an example of a form schema:</p>
<pre><code class="lang-typescript">formSchema: FormSchemaItem[] = [
    {
      key: <span class="hljs-string">'name'</span>,
      name: <span class="hljs-string">'Full Name'</span>,
      value: <span class="hljs-string">''</span>,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">'text'</span>,
      validators: [
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.REQUIRED,
        },
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.MAX_LENGTH,
          argument: <span class="hljs-number">25</span>,
        },
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.MIN_LENGTH,
          argument: <span class="hljs-number">3</span>,
        },
      ],
    },
    {
      key: <span class="hljs-string">'age'</span>,
      name: <span class="hljs-string">'Age'</span>,
      value: <span class="hljs-string">''</span>,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">'number'</span>,
      validators: [
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.REQUIRED,
        },
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.MAX,
          argument: <span class="hljs-number">60</span>,
        },
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.MIN,
          argument: <span class="hljs-number">18</span>,
        },
      ],
    },
    {
      key: <span class="hljs-string">'email'</span>,
      name: <span class="hljs-string">'Email'</span>,
      value: <span class="hljs-string">''</span>,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">'email'</span>,
      validators: [
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.REQUIRED,
        },
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.EMAIL,
        },
      ],
    },
    {
      key: <span class="hljs-string">'phoneNumber'</span>,
      name: <span class="hljs-string">'Phone Number'</span>,
      value: <span class="hljs-string">''</span>,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">'number'</span>,
      validators: [
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.REQUIRED,
        },
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.PATTERN,
          argument: <span class="hljs-regexp">/\d/</span>,
        },
      ],
    },
    {
      key: <span class="hljs-string">'address'</span>,
      name: <span class="hljs-string">'Full Address'</span>,
      value: <span class="hljs-string">''</span>,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">'text'</span>,
      validators: [
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.PATTERN,
          argument: <span class="hljs-regexp">/[a-z]/</span>,
        },
        {
          <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes.MAX_LENGTH,
          argument: <span class="hljs-number">100</span>,
        },
      ],
    },
    {
      key: <span class="hljs-string">'date'</span>,
      name: <span class="hljs-string">'Date'</span>,
      value: <span class="hljs-string">''</span>,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">'date'</span>,
      validators: [],
    },
  ];
</code></pre>
<p>Next, we define the types used in the schema, including form item definitions and validators. These types help in maintaining a structured and consistent form schema.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { FormControl } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/forms'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> FormSchemaItemAndControl = {
  item: FormSchemaItem;
  control: FormControl;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> FormSchemaItem = {
  key: <span class="hljs-built_in">string</span>;
  name: <span class="hljs-built_in">string</span>;
  value: <span class="hljs-built_in">any</span>;
  <span class="hljs-keyword">type</span>: <span class="hljs-string">'text'</span> | <span class="hljs-string">'number'</span> | <span class="hljs-string">'tel'</span> | <span class="hljs-string">'email'</span> | <span class="hljs-string">'date'</span>;
  validators: FormSchemaValidator[];
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> FormSchemaValidator = {
  <span class="hljs-keyword">type</span>: FormSchemaValidatorTypes;
  argument?: <span class="hljs-built_in">any</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-built_in">enum</span> FormSchemaValidatorTypes {
  REQUIRED = <span class="hljs-string">'required'</span>,
  MAX = <span class="hljs-string">'max'</span>,
  MIN = <span class="hljs-string">'min'</span>,
  MAX_LENGTH = <span class="hljs-string">'maxLength'</span>,
  MIN_LENGTH = <span class="hljs-string">'minLength'</span>,
  EMAIL = <span class="hljs-string">'email'</span>,
  PATTERN = <span class="hljs-string">'pattern'</span>,
}
</code></pre>
<h2 id="heading-converting-schema-to-form-controls">Converting Schema to Form Controls</h2>
<p>We can now create a function that converts our custom schema to Angular's ReactiveForms controls. This function called <code>createFormControls</code> maps each item in the schema to a corresponding form control using Angular's FormBuilder. We also load the validators specified in the schema. Here's the code snippet:</p>
<pre><code class="lang-typescript">createFormControls(schema: FormSchemaItem[]): FormSchemaItemAndControl[] {
    <span class="hljs-keyword">const</span> formSchemaWithControls = schema.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> {
        item: item,
        control: <span class="hljs-built_in">this</span>.fb.control(
          item.value,
          <span class="hljs-built_in">this</span>.loadValidators(item.validators)
        ),
      };
    });

    <span class="hljs-keyword">return</span> formSchemaWithControls;
}
</code></pre>
<p>Additionally, we have a <code>loadValidators</code> function that maps the custom validators to Angular's built-in validators.</p>
<pre><code class="lang-typescript">loadValidators(validators: FormSchemaValidator[]): <span class="hljs-built_in">any</span> {
    <span class="hljs-keyword">const</span> validations = validators.map(<span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (element.argument) {
        <span class="hljs-keyword">return</span> Validators[element.type](element.argument);
      }

      <span class="hljs-keyword">return</span> Validators[element.type];
    });

    <span class="hljs-keyword">return</span> validations;
}
</code></pre>
<p>Finally, we define the <code>createFormGroup</code> function that creates a form group for all the controls. This function adds each control to the form group using the control's key from the schema.</p>
<pre><code class="lang-typescript">createFormGroup(
    formSchemaWithControls: FormSchemaItemAndControl[]
): UntypedFormGroup {
    <span class="hljs-keyword">const</span> form = <span class="hljs-built_in">this</span>.fb.group({});

    formSchemaWithControls.forEach(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
      form.addControl(item.item.key, item.control);
    });

    <span class="hljs-keyword">return</span> form;
}
</code></pre>
<h2 id="heading-using-the-form-service">Using the form service</h2>
<p>In our component.ts file, we can now build and use the dynamic form by injecting the form service and creating the form. Inside the <code>createForm</code> method, we call <code>createFormControls</code> to populate the <code>formSchemaWithControls</code> array with the converted form controls. Then, we use <code>createFormGroup</code> to create the form group for our dynamic form.</p>
<pre><code class="lang-typescript">formSchemaWithControls: FormSchemaItemAndControl[] = [];
formGroup!: UntypedFormGroup;

<span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> formService: FormService</span>) {}

ngOnInit(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.createForm();
}

createForm(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.formSchemaWithControls = <span class="hljs-built_in">this</span>.formService.createFormControls(
      <span class="hljs-built_in">this</span>.formService.formSchema
    );

    <span class="hljs-built_in">this</span>.formGroup = <span class="hljs-built_in">this</span>.formService.createFormGroup(
      <span class="hljs-built_in">this</span>.formSchemaWithControls
    );
}

submit() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.formGroup.value);
}
</code></pre>
<p>In the HTML template, we can dynamically generate the form by looping through the controls and binding them to the respective input fields. We also display any validation errors associated with each control.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"form"</span>
    *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"formSchemaWithControls"</span>
    (<span class="hljs-attr">ngSubmit</span>)=<span class="hljs-string">"submit()"</span>
    [<span class="hljs-attr">formGroup</span>]=<span class="hljs-string">"formGroup"</span>
  &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-item"</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let element of formSchemaWithControls"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        [<span class="hljs-attr">type</span>]=<span class="hljs-string">"element.item.type"</span>
        [<span class="hljs-attr">placeholder</span>]=<span class="hljs-string">"element.item.name"</span>
        [<span class="hljs-attr">formControl</span>]=<span class="hljs-string">"element.control"</span>
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"form-error"</span>
        *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"
          element.control.errors &amp;&amp;
          (element.control.dirty || element.control.touched)
        "</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let error of element.control.errors | keyvalue"</span>&gt;</span>
          {{ element.item.name + " " + error.key }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> [<span class="hljs-attr">disabled</span>]=<span class="hljs-string">"formGroup.invalid"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With the implementation of dynamic forms in Angular using the provided techniques, we have successfully created a form that adapts to changing requirements. The power of Angular's ReactiveForms, combined with a well-defined form schema, allows us to build robust and user-friendly dynamic forms. By following the steps outlined in this blog post, you can enhance the form-building experience in your Angular applications and create dynamic forms with ease.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684256014745/fccf78da-1547-4b3a-b873-3c721d9a1eb6.png" alt class="image--center mx-auto" /></p>
<p>And that's it! We now have a fully functional dynamic form based on the schema, complete with validations. Feel free to experiment with different schema configurations and expand upon this foundation to suit your specific needs.</p>
<p>You can find the source code in this <a target="_blank" href="https://github.com/awabcodes/angular-dynamic-forms">GitHub Repository</a>.</p>
]]></content:encoded></item></channel></rss>