<?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" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Bilkiss Dulloo on Medium]]></title>
        <description><![CDATA[Stories by Bilkiss Dulloo on Medium]]></description>
        <link>https://medium.com/@bilkiss.dulloo?source=rss-571616dbdfc9------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*5XTA-CFtmbkiacsAgm7l9Q.jpeg</url>
            <title>Stories by Bilkiss Dulloo on Medium</title>
            <link>https://medium.com/@bilkiss.dulloo?source=rss-571616dbdfc9------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 04:35:17 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@bilkiss.dulloo/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How to use our reactive storage service in Angular]]></title>
            <link>https://medium.com/@bilkiss.dulloo/how-to-use-our-reactive-storage-service-in-angular-8bb58989f49f?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/8bb58989f49f</guid>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Sat, 08 Jan 2022 06:15:22 GMT</pubDate>
            <atom:updated>2022-01-09T18:37:08.133Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gvVm9DJe2BTYFZdmUGMvBQ.gif" /><figcaption>Reactive storage service demo</figcaption></figure><p>This is a follow-up article to our previous one, where we explored how to create a service that would allow us to seamlessly use the browser’s localstorage, and provide a way to subscribe to changes reactively.</p><p>In this article, we shall build a simple app to explore how the reactive storage service can be used to create flexible data flows.</p><h4>Create project:</h4><p>Let’s begin by creating an Angular project:</p><pre>ng generate new reactive-storage-service-demo</pre><p>We should now have a basic project skeleton. Before we start writing code however, we will be installing Bootstrap and font-awesome to minimize the amount of work needed to make our demo look good :)</p><h4>Installation:</h4><p>Adding bootstrap:</p><pre>npm i bootstrap --save</pre><p>Adding fontawesome:</p><pre>npm i font-awesome --save</pre><p>Once the installation is complete, using bootstrap and font-awesome in angular is quite simple. We need to:</p><ol><li>Import bootstrap and fontawesome in the style.scss file</li><li>Nothing. We can now directly use it on our components’ templates.</li></ol><pre>@import &quot;~bootstrap/scss/bootstrap.scss&quot;;</pre><pre>@import &quot;~font-awesome/css/font-awesome.css&quot;;</pre><p>We have now installed the prerequisite libraries to deal with the UI aspect of things. We will now be creating the main part of this demo app, which is the storage service. As mentioned before, this article is a follow up to a previous one where we explain the process behind the creation of our storage service. <a href="https://medium.com/@kyushiro/building-a-reactive-storage-service-in-angular-bad412bcdce6">You can find it [HERE]</a>. Please follow along, and come back here once you have the service :)</p><p>After adding the reactive storage service, let’s see how we are going to implement it.</p><p>We will start by generating 4 components:</p><pre>ng g c components/home<br>ng g c components/form<br>ng g c components/list<br>ng g c components/total</pre><p>This will create the following files.</p><p><strong>home.component.ts</strong></p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;</pre><pre>@Component({<br> selector: &#39;app-home&#39;,<br> templateUrl: &#39;./home.component.html&#39;,<br> styleUrls: [&#39;./home.component.scss&#39;]<br>})</pre><pre>export class HomeComponent implements OnInit {<br><br>   constructor() {}<br><br>   ngOnInit(): void {}<br><br>}</pre><p><strong>form.component.ts</strong></p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;</pre><pre>@Component({<br> selector: &#39;app-form&#39;,<br> templateUrl: &#39;./form.component.html&#39;,<br> styleUrls: [&#39;./form.component.scss&#39;]<br>})</pre><pre>export class FormComponent implements OnInit {<br><br>   constructor() {}<br><br>   ngOnInit(): void {}<br><br>}</pre><p><strong>list.component.ts</strong></p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;</pre><pre>@Component({<br> selector: &#39;app-list&#39;,<br> templateUrl: &#39;./list.component.html&#39;,<br> styleUrls: [&#39;./list.component.scss&#39;]<br>})</pre><pre>export class ListComponent implements OnInit {<br><br>   constructor() {}<br><br>   ngOnInit(): void {}<br><br>}</pre><p><strong>total.component.ts</strong></p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;</pre><pre>@Component({<br> selector: &#39;app-total&#39;,<br> templateUrl: &#39;./total.component.html&#39;,<br> styleUrls: [&#39;./total.component.scss&#39;]<br>})</pre><pre>export class TotalComponent implements OnInit {<br><br>   constructor() {}<br><br>   ngOnInit(): void {}<br><br>}</pre><p>Now, we’ll call form and list components on our home.component.html :</p><p><strong>home.component.html</strong></p><pre>&lt;div class=&quot;container py-4&quot;&gt;<br>   &lt;app-form&gt;&lt;/app-form&gt;<br>   &lt;app-list&gt;&lt;/app-list&gt;<br>&lt;/div&gt;</pre><p>Now let’s look at the form component first. As its name may more or less imply, here we will be creating a small form to add a product. The form we will be creating is shown in the screenshot below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uEEIwz9Y1XyS5WUOkg9Xrw.png" /><figcaption>Figure 1</figcaption></figure><p>As you can see in Figure 1 above, the form is quite simple and straightforward. We have 2 inputs and a button to submit the data. We can however make the form a little more interesting by implementing a datalist for the product field. But first let’s add some code in our component’s ts.</p><p><strong>form.component.ts</strong></p><pre>private products: any[] = [];<br> public productNames:any = [];<br><br><br>getProducts(){<br>   this.products = [<br>     { &#39;Pizza&#39; : 200 },<br>     { &#39;Rice&#39; : 150 },<br>     { &#39;Bread&#39; : 70 }<br>   ];<br>   this.products.map( (key) =&gt; {<br>     this.productNames.push.apply(this.productNames, Object.keys(key));<br>   });<br> }</pre><p>We start by creating two properties, products and productNames, as well as a method named getProducts().</p><p>Traditionally, in order to implement the datalist feature mentioned earlier, we would have to make an API call somewhere to fetch the list of products. For our demo purposes however, we will hardcode the data in this method itself &amp; assign it to the products class property we have created above. The list will be an array of key/value pairs representing product names and prices.</p><p>Next, in order to generate the datalist for our html, we will need an array of strings containing only the product names. We achieve this by using the apply method to push one array into the other. We can then display the list of product names in our template, which will be our form.component.html</p><p>Let’s have a look at our html and see how are we going to display our productNames :</p><p><strong>form.component.html</strong></p><pre>&lt;div class=&quot;mb-3 row&quot;&gt;<br>   &lt;label for=&quot;productDataList&quot; class=&quot;col-sm-3 text-end col-form-label&quot;&gt; Product&lt;/label&gt;<br>   &lt;div class=&quot;col-sm-8&quot;&gt;<br>       &lt;input class=&quot;form-control&quot; list=&quot;productOptions&quot; id=&quot;productDataList&quot; placeholder=&quot;Type to search...&quot; required&gt;<br>       &lt;datalist id=&quot;productOptions&quot;&gt;<br>           &lt;option *ngFor=&quot;let opt of productNames&quot; value=&quot;{{opt}}&quot;&gt;&lt;/option&gt;<br>       &lt;/datalist&gt;<br>   &lt;/div&gt;<br>&lt;/div&gt;</pre><p>The interesting tags here are the input and datalist elements. A few interesting things to point out are that</p><ul><li>The &lt;input&gt; element has a list attribute that is set to “productOptions”</li><li>The &lt;datalist&gt; element has an id, which is also set to “productOptions”</li><li>The &lt;datalist&gt; element contains an &lt;option&gt; tag will be repeated for every element in our array of product names.</li></ul><p>By setting the list attribute to the same value as the id of our datalist, we are effectively binding those two elements. We will then be displaying our productNames inside of the &lt;datalist&gt; , so we use an *ngFor on the productNames in our &lt;option&gt; tag, and add each product name to the value attribute.</p><p>What we just achieved is that our &lt;input&gt; is now no longer a simple text box, as values from the datalist will be used to turn it into an autocomplete enabled textbox.</p><p><em>“But!”</em>, I hear you ask, <em>“Couldn’t we have just used a &lt;select&gt; here and list the options in there?”</em>, which is an excellent question. We indeed could have done that, but note that we have a different use case here. our input+datalist solution is more flexible, since now the user can enter their own value if what they want is not in the predefined list.</p><p>Alright! Next, upon selecting an existing product, we’ll want to populate its corresponding price as shown in figure 1.</p><p>In order to achieve this, we will need to rely on browser events. We will look at our html first, and then create the corresponding bindings in our component ts.</p><p>In our form.component.html , let’s add a “keyup” attribute to our product input, and calling the onChangeProduct() method, which we will be creating in our ts shortly. The method will take the event data $event as its only parameter. Basically the $event will contain the value of our product textbox.</p><p><strong>form.component.html</strong></p><pre>&lt;input class=&quot;form-control&quot; (keyup)=&quot;onChangeProduct($event)&quot; list=&quot;productOptions&quot; id=&quot;productDataList&quot; placeholder=&quot;Type to search...&quot; required&gt;<br>&lt;datalist id=&quot;productOptions&quot;&gt;<br>  &lt;option *ngFor=&quot;let opt of productNames&quot; value=&quot;{{opt}}&quot;&gt;&lt;/option&gt;<br>&lt;/datalist&gt;</pre><p>Next, let’s take a look at our ts. We first add a new public property to our class called “currentProduct”, which will contain the details that we want the form to submit. We then add the onChangeProduct() method.</p><p><strong>form.component.ts</strong></p><pre>public currentProduct: any = {<br>   name: &#39;&#39;,<br>   price: 0<br> };<br> <br><br>onChangeProduct(event: any): void{<br><br>   const value = event.target.value;<br>   this.products.map( prod =&gt; {<br>     if (Object.keys(prod)[0].includes(value)){<br>       this.currentProduct.price = Object.values(prod)[0];<br>     };<br>   });<br><br> }</pre><p>Within the method, we create a new variable called “value”, and assign it to our product textbox’s value through the “event” parameter using “event.target.value”.</p><p>Now, since as mentioned earlier we are not using a &lt;select&gt; element for the product name, and the user thus has the option to enter their own value, we cannot guarantee that the value entered in the textbox has a corresponding price. As such, we’ll need to check if the name of the product entered exists in our list, and therefore has a corresponding price. If it does, we’ll assign it to this.currentProduct.price</p><p>After updating this.currentProduct.price we now need to populate our price input in our html with its value.</p><p>Angular provides us with a few ways to change a form input’s value programmatically from our component ts file. The one we will use here is the [(ngModel)] directive.</p><p>ngModel is a directive provided by angular’s form module, and it allows us to set up either one or two way binding between our form input and a property of our component class. In order to use the directive however, we need to first import the required module in our app.module.ts file</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ec514701a153dee138bee8610a4bbf2a/href">https://medium.com/media/ec514701a153dee138bee8610a4bbf2a/href</a></iframe><p>Please note that since you have modified the app.module.ts file, you will need to serve your application once again for changes to our module file to take effect.</p><p>Once this is done, we can go back to our html. We will be using bootstrap classes to make the UI more interesting. Here we will be using an input group to be able to add a $ sign in front of the price input.</p><p>In order to populate the updated price in the input, we are binding it to our class property currentProduct.price using the [(ngModel)] directive on our input tag, so that each time we are changing the product, it will update to the corresponding price.</p><p><strong>form.component.html</strong></p><pre>&lt;div class=&quot;mb-3 row&quot;&gt;<br>   &lt;label for=&quot;inputPrice&quot; class=&quot;col-sm-3 text-end col-form-label&quot;&gt;Price&lt;/label&gt;<br>   &lt;div class=&quot;col-sm-8&quot;&gt;<br>       &lt;div class=&quot;input-group mb-3&quot;&gt;<br>           &lt;span class=&quot;input-group-text&quot; id=&quot;basic-price&quot;&gt;&lt;i class=&quot;fa fa-dollar&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt;&lt;/span&gt;<br>           &lt;input type=&quot;text&quot; [(ngModel)]=&quot;currentProduct.price&quot; class=&quot;form-control&quot; id=&quot;inputPrice&quot; placeholder=&quot;Price&quot; aria-label=&quot;Price&quot; aria-describedby=&quot;basic-price&quot;&gt;<br>       &lt;/div&gt;<br>   &lt;/div&gt;<br>&lt;/div&gt;</pre><p>Now we need to do the same for our product input, binding it to currentProduct.name so that the product name is also synced with our currentProduct property.</p><pre>&lt;div class=&quot;mb-3 row&quot;&gt;<br>    &lt;label for=&quot;productDataList&quot; class=&quot;col-sm-3 text-end col-form-label&quot;&gt;Product&lt;/label&gt;<br>    &lt;div class=&quot;col-sm-8&quot;&gt;<br>        &lt;input class=&quot;form-control&quot; (keyup)=&quot;onChangeProduct($event)&quot; [(ngModel)]=&quot;currentProduct.name&quot; list=&quot;productOptions&quot; id=&quot;productDataList&quot; placeholder=&quot;Type to search...&quot; required&gt;<br>        &lt;datalist id=&quot;productOptions&quot;&gt;<br>            &lt;option *ngFor=&quot;let opt of productNames&quot; value=&quot;{{opt}}&quot;&gt;&lt;/option&gt;<br>        &lt;/datalist&gt;<br>    &lt;/div&gt;<br>&lt;/div&gt;</pre><p>We’re almost done with the form. Last but not least, we now need to save the form data to the storage.</p><p>First, let’s add a click event to our button in our html. We will bind the click event to an addProduct() method, that we will create shortly on our form.component.ts.</p><p><strong>form.component.html</strong></p><pre>&lt;button type=&quot;button&quot; class=&quot;btn btn-success btn-sm&quot; (click)=&quot;addProduct()&quot;&gt;<br>    &lt;i class=&quot;fa fa-paper-plane me-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt;<br>      Save<br>&lt;/button&gt;</pre><p>We will now create our addProduct() method in our ts file, which is going to add the product to our storage.</p><p>We begin by creating a new variable called storageProductList. This will be an array that we will use as a proxy to the data that is in our storage.</p><p>After that, we’ll get all the products from storage and assign it them our storageProductList. If there is no value in the storage we’ll just set it to an empty array.</p><p>We can then push our current product (that has been synced into this.currentProduct with the two ngModel directives in our html) into the storageProductList and then set it back to our storage with this.storage.set(‘products’, this.storageProductList);</p><p><strong>form.component.ts</strong></p><pre>public storageProductList: any = []; <br><br>addProduct(): void{<br>     this.storageProductList = this.storage.get(&#39;products&#39;);<br>     if (!this.storageProductList) {<br>       this.storageProductList = [];<br>     }<br>     this.storageProductList.push({...this.currentProduct});<br>     this.storage.set(&#39;products&#39;, this.storageProductList);<br>   }<br><br> }</pre><p><strong>form.components.html</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6321448f73eb0c0b7a5c5be2123d9299/href">https://medium.com/media/6321448f73eb0c0b7a5c5be2123d9299/href</a></iframe><p><strong>form.components.ts</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c3974ad0c47faf7c04fd834057e2d710/href">https://medium.com/media/c3974ad0c47faf7c04fd834057e2d710/href</a></iframe><p>Now that we are done with the form, we will be looking at the list. First, let’s check the list UI. We want to build something like the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*piS9Ier7A7jqSu4iIQeB5w.png" /><figcaption>Figure 2</figcaption></figure><p>As you can see in Figure 2 above, it is a list of all the products from the localstorage. In the table we have 3 columns: the product name, the product price (in dollars) &amp; a column for the delete button for each product. Let’s add some code in our component’s ts file;</p><p>We’ll first declare the productList$ &amp; inject the storage service</p><p><strong>list.component.ts</strong></p><pre>productList$ = this.storage.watch(&#39;products&#39;);<br><br> constructor(<br>   public storage: StorageService<br> ) { }</pre><p>It is worth noting that since we know the watch method of our storage service will be returning an observable, we can create a stream directly simply by assigning it to our productList$ property. This will enable us to access the data directly in our template by using an async pipe.</p><p>Next, we’ll display the product in a table by using *ngFor on the productList$ | async and displaying the name &amp; price. As mentioned above, the async pipe is used to resolve the observable stream. In order to format the price in a suitable format we’ll add a currency pipe when rendering the price ( item.price | currency )</p><p><strong>list.component.html</strong></p><pre>&lt;table class=&quot;table table-striped table-hover&quot;&gt;<br>   &lt;thead&gt;<br>     &lt;tr&gt;<br>       &lt;th scope=&quot;col&quot;&gt;Name&lt;/th&gt;<br>       &lt;th scope=&quot;col&quot; class=&quot;col-2 text-center&quot;&gt;Price (&lt;i class=&quot;fa fa-dollar&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt;)&lt;/th&gt;<br>       &lt;th scope=&quot;col&quot; class=&quot;text-end pe-5 col-2&quot;&gt;Action&lt;/th&gt;<br>     &lt;/tr&gt;<br>   &lt;/thead&gt;<br>   &lt;tbody&gt;<br>     &lt;tr *ngFor=&quot;let item of productList$ | async&quot;&gt;<br>       &lt;td&gt;{{item?.name}}&lt;/td&gt;<br>       &lt;td class=&quot;text-center&quot;&gt;{{item?.price | currency}}&lt;/td&gt;<br>       &lt;td class=&quot;text-end pe-5&quot;&gt;<br>           &lt;button class=&quot;btn btn-danger btn-sm&quot; (click)=&quot;removeStoreProduct(item.name)&quot;&gt;<br>               &lt;i class=&quot;fa fa-trash&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt;<br>           &lt;/button&gt;<br>       &lt;/td&gt;<br>     &lt;/tr&gt;<br>   &lt;/tbody&gt;<br> &lt;/table&gt;</pre><p>Then let’s check on how we’ll remove a product from the list. Notice that in the markup above, we have a click event in our button, binding to a removeStoreProduct() method, passing the item name as an argument.</p><p>We will therefore create our removeStoreProduct() method in our ts file, in which we are going to remove the product to our storage. By passing the product name as a parameter, we’ll be able to filter on our list directly. But first, similarly to when we were adding a product, let’s get the products from our storage with this.storage.get(‘products’) , and assign it to a list variable.</p><p>Next we’ll filter on the list and remove the product with the same name as the one that we have passed as parameter</p><p>list = list.filter( (x:any) =&gt; x.name != name );</p><p>and then set the list back to our storage</p><p>this.storage.set(‘products’, list);</p><p>and tada… it’s done :)</p><p><strong>list.component.ts</strong></p><pre>removeStoreProduct(name: string): void{<br>   let list = this.storage.get(&#39;products&#39;);<br>   if (!list) {<br>     list = [];<br>   }<br>   list = list.filter( (x: any) =&gt; x.name != name);<br>   this.storage.set(&#39;products&#39;, list);<br> }</pre><p>And we are functionally done with the list :) but before moving on, let’s add the &lt;app-total&gt; selector at the bottom of our list in order to call the total component here.</p><p><strong>list.component.html</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a89c68c2ddfb71edb67d98c198c27c80/href">https://medium.com/media/a89c68c2ddfb71edb67d98c198c27c80/href</a></iframe><p><strong>list.component.ts</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a3b1657ac2fb4140354253da1a8bc28a/href">https://medium.com/media/a3b1657ac2fb4140354253da1a8bc28a/href</a></iframe><p>Alright. At this point our form and list are done. You can test that adding a product in the form indeed populates the list, and removing a product also works, without us having to manually communicate updates between the components.</p><p>Now let’s look at the total component. Ultimately we want to have something like the following UI:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/1*RSAZyaLDoFzQbWs3aAK9Og.png" /><figcaption>Figure 3</figcaption></figure><p>As you can see in Figure 2 above, we are adding a total and also calculating a discount of 5% and adding a 15% of VAT to the subtotal. Let’s add some code in our total component’s ts.</p><p>We’ll first of all declare variable displayProductData as an object, which will contain all the information we want to display (i.e our subtotal, discount, vat and the total), and setting all their initial values to 0.</p><p><strong>total.component.ts</strong></p><pre>displayProductData: any = {<br>   subtotal: 0,<br>   discount: 0,<br>   vat: 0,<br>   total: 0<br> };</pre><p>Next, once again, we’ll inject storage service in the constructor.</p><p><strong>total.component.ts</strong></p><pre>constructor(<br>   public storage: StorageService<br> ) { }</pre><p>We will be doing all the calculations in the ngOnInit() method, we could also create a method for the calculation and call it on our ngOnInit().</p><p>Let’s start by subscribing to the watch() method for our products on our storageService. This will again provide us with an observable pipeline that will allow us to subscribe to updates in the product list in our localstorage. Initially however, since there will be nothing in our storage the first time we run the application, we need to check if our res is not null before proceeding.</p><p>We can then create a prices array from the product list by aggregating the results in our subscribe, as we will only need the prices here.</p><p>We will begin by using the map method to transform our array of objects into an array of prices, that we will use to calculate our subtotal.</p><p>So basically if there’s only 1 item in our prices array, we will just set the subtotal to the first element in the prices ( thus prices[0] ). Otherwise, we will use the reduce function (i.e prices.reduce()) to obtain the sum of all prices in the array.</p><p>Next for the 5% discount, we’ll just multiply 0.05 by the subtotal.</p><p>0.05 * this.displayProductData.subtotal</p><p>And assign it to this.displayProductData.discount</p><p>Regarding the VAT (15%), same principle, we’ll be multiplying 0.15 * this.displayProductData.subtotal and assign it to this.displayProductData.vat</p><p>Finally, for the total, we’ll do subtotal minus discount plus VAT, so</p><p>this.displayProductData.total <strong>= </strong>this.displayProductData.subtotal <strong>— </strong>this.displayProductData.discount <strong>+</strong> this.displayProductData.vat;</p><p><strong>total.component.ts</strong></p><pre>ngOnInit(): void {<br>   this.storage.watch(&#39;products&#39;)?.subscribe( res =&gt; {     if (!res) return;<br>     const prices = res.map( (x: any) =&gt; x.price);<br>     this.displayProductData.subtotal = (prices.length &gt; 1) ?<br>     prices.reduce( (a:number, b:number) =&gt; a+b, 0 ): prices[0];<br><br>     this.displayProductData.discount = 0.05 * this.displayProductData.subtotal;<br>     this.displayProductData.vat = 0.15 * this.displayProductData.subtotal;<br>     this.displayProductData.total = this.displayProductData.subtotal -           this.displayProductData.discount + this.displayProductData.vat;<br><br>   });<br> }</pre><p>All good! So now everytime we get an update from the storage service, our component will recalculate all the values. We can now go ahead and use it in our html :)</p><p>Speaking of our html, we’ll be displaying the subtotal, discount, VAT and total in dl, dt &amp; dd. We’ve added dt on subtotal and total to make it bold and also increased the size for the total by adding an fs-5 class. And also add a pipe currency on each item.</p><p><strong>total.component.html</strong></p><pre>&lt;dl class=&quot;text-end pe-5&quot;&gt;<br>   &lt;dt&gt;{{displayProductData.subtotal | currency}}&lt;/dt&gt;<br>   &lt;dd&gt;{{displayProductData.discount | currency}}&lt;/dd&gt;<br>   &lt;dd&gt;{{displayProductData.vat | currency}}&lt;/dd&gt;<br>   &lt;dt class=&quot;fs-5&quot;&gt;{{displayProductData.total | currency}}&lt;/dt&gt;<br>&lt;/dl&gt;</pre><p><strong>total.component.html</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9170e87572d0bc3d09f3a7a7b480a382/href">https://medium.com/media/9170e87572d0bc3d09f3a7a7b480a382/href</a></iframe><p><strong>total.component.ts</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0fae477a6816ee1a10477ef295a93356/href">https://medium.com/media/0fae477a6816ee1a10477ef295a93356/href</a></iframe><p>And we’re done! Now we can add products using the form, they’ll automatically update the list and total component. Removing a product from the list will also update the total as well. All this works across the 3 components with our localstorage acting as a source of truth. What is even better is that since we are using localstorage, this state is also persisted across page loads.</p><p>This concludes our short showcase of how to use the reactive storage service. Of course this is just a simple use case of what can be done using this pattern, but we are already excited about all the possibilities this approach enables.</p><p>Any thoughts, questions or improvement ideas? We would be delighted to hear from you :)</p><p>You can find a live demo: <a href="https://reactive-storage-service-demo.herokuapp.com/">https://reactive-storage-service-demo.herokuapp.com/</a></p><p>And the code on Github: <a href="https://github.com/Bilkiss/reactive-storage-service-demo">https://github.com/Bilkiss/reactive-storage-service-demo</a></p><p>Keep safe and keep learning :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8bb58989f49f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building custom typescript decorators for angular]]></title>
            <link>https://levelup.gitconnected.com/building-custom-typescript-decorators-for-angular-4595816e7b87?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/4595816e7b87</guid>
            <category><![CDATA[custom]]></category>
            <category><![CDATA[confirmable]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[decorators]]></category>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Tue, 30 Mar 2021 11:17:44 GMT</pubDate>
            <atom:updated>2021-03-31T11:59:46.619Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IFOv2QMFpVheai4ImmJFGA.gif" /></figure><p>As frontend developers we love beautiful UI. In the same vein, we really should strive to have clean reusable code. Modern tools and techniques provide us with many ways to achieve that. In this article, we will look at typescript decorators, and how they can help us add abstraction and reusability to our code.</p><p>We will do that by creating a custom decorator to launch a <a href="https://sweetalert.js.org/guides/">Sweetalert</a>.</p><p>But first of all let us look at what decorators are.</p><p>When I was first introduced to decorators, I wondered why we needed them at all. I mean sure, Angular uses that @Whatever symbols everywhere but how did they actually work? Ultimately they looked like black boxes. And surely, one can build apps in TS / Angular without understanding them. But once we dig a little deeper we can understand what they are, as well as the benefits of using them.</p><h4>What are decorators?</h4><p>At its core, a decorator is just a JavaScript function. Ok i know this sounds like a joke but really! A decorator is just a function that allows us to “extend” our code to do more. Yes it’s very abstract for now but we’ll get to clarify that soon.</p><p>Let’s look at the different types of decorators available in typescript.</p><p>There are four main types:</p><ul><li>Class decorators, which are used to add functionality to a class e.g. <strong>@Component</strong> and <strong>@NgModule</strong></li><li>Property decorators for adding functionality to properties inside classes, e.g. <strong>@Input</strong> and <strong>@Output</strong></li><li>Method decorators for methods inside classes, e.g. <strong>@HostListener</strong></li><li>Parameter decorators for parameters inside class constructors, e.g. <strong>@Inject</strong></li></ul><p>Each decorator has a unique role. For examples of the different decorator types and their application in angular, please check <a href="https://medium.com/@bilkiss.dulloo/decorators-in-angular-16e20efcd17c">Decorators used in Angular</a>.</p><p>Those are the basics you should know before we can jump into the fun part, actual code :) As mentioned earlier, we will be creating a method decorator that will show a sweetalert confirmation box before a method is executed.</p><h4>OK let’s start!</h4><p>As mentioned earlier, decorators are actually just functions, it’s as simple as that, and are called with whatever they are decorating. A method decorator will be called before the method it’s decorating, and a class decorator will be called before the class to be decorated.</p><p>I am assuming you already have an angular project, but if not you can create one with</p><pre>ng new</pre><p>Let’s quickly make a decorator that we can use in a class to demonstrate this a little further. The decorator we’ll be building is a confirmable decorator, which will ask for confirmation before executing a method. We will be using <a href="https://sweetalert2.github.io/">SweetAlert 2</a> as our popup plugin.</p><h4><strong>Installation</strong>:</h4><p>To install sweetalert we need to run the following command in the terminal</p><pre>npm install --save sweetalert2</pre><p>Once the installation is complete, using sweetalert in angular is quite simple. We need to:</p><ol><li>Import the library in our component</li><li>Call Swal.fire(); to show the popup.</li></ol><p>For example consider the code sample below:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/65e6bd139c7b6d83f874738dd3295604/href">https://medium.com/media/65e6bd139c7b6d83f874738dd3295604/href</a></iframe><p>(This code sample is just for illustrative purposes, you will not need this component in the project).</p><p>In the above example, when the component is initiated, an alert box will appear</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yhTyHuPa-EDKACJb4Dkrpw.png" /></figure><p>Now that we have looked at the basic usage of sweetalert, let’s write some code. First, we will create a component, which will be our starting point for this adventure. As usual we will use the cli.</p><pre>ng g c item</pre><p>This will create the following file.</p><p><strong>item.component.ts</strong></p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;</pre><pre>@Component({<br>  selector: &#39;app-item&#39;,<br>  templateUrl: ‘./item.component.html&#39;,<br>  styleUrls: [&#39;./item.component.scss&#39;]<br>})</pre><pre>export class ItemComponent implements OnInit {</pre><pre>constructor() {}</pre><pre>ngOnInit(): void {}</pre><pre>}</pre><p>Nothing too fancy for now. We will be adding a delete method to this component class, which will simply log a message to the browser console.</p><p><strong>item.component.ts</strong></p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;</pre><pre>@Component({<br>  selector: &#39;app-item&#39;,<br>  templateUrl: ‘./item.component.html&#39;,<br>  styleUrls: [&#39;./item.component.scss&#39;]<br>})</pre><pre>export class ItemComponent implements OnInit {</pre><pre> constructor() {}</pre><pre> ngOnInit(): void {}</pre><pre> deleteItem(): void {<br>  console.log(“An item was deleted”);<br> }</pre><pre>}</pre><p>And in the component’s markup, we will add a button to trigger the newly created method.</p><p><strong>item.component.html</strong></p><pre>&lt;button (click)=”deleteItem()”&gt;Delete item&lt;/button&gt;</pre><p>If we load the component and click the button, the console will indeed log the message. So far so good, but what if we wanted to ask the user to confirm this action rather than directly running the method?</p><p>One option would be to call sweetalert within the deleteItem method itself, and this would work ok, but what if we wanted this to be a reusable logic, so that it wouldn’t need to be copy/pasted every time we have a functionality requiring a user confirmation? I know you were waiting for it, this is where our decorator will come in!</p><p>So for the next step, we will create a folder named “decorators” in our app directory, and within it add a new blank typescript file named <em>confirmable.decorator.ts</em>.</p><p>The first thing we will do in that file is to import sweetalert.</p><p><strong>confirmable.decorator.ts</strong></p><pre>import Swal from &#39;sweetalert2&#39;;</pre><p>Next, remember how we were saying that decorators were simple TS functions? Those functions’ signatures look like the following for method decorators:</p><pre>function confirmable(target: Object, propertyKey: string, descriptor: PropertyDescriptor)</pre><p>Where “target” represents the class containing the method we’re decorating, “propertyKey” represents the method name, and “descriptor” will contain the method implementation. Within the decorator function we are able to do things before / after the method executes, or skip execution altogether based on arbitrary conditions. For example</p><pre>function decorator(target: Object, propertyKey: string, descriptor: PropertyDescriptor){</pre><pre> // we first cache the original method implementation<br> const originalMethod = descriptor.value;</pre><pre> // then we overwrite it with a new implementation,<br> // ...args represent the original arguments</pre><pre> descriptor.value = function (...args) {</pre><pre>  // do custom logic before executing the original method<br>  // execute original method with the original arguments<br>  const result = originalMethod.apply(this, args);</pre><pre>   // execute custom logic after executing the original method<br>   return result;<br>  }</pre><pre> };</pre><pre> return descriptor;</pre><pre>};</pre><p>As we can see in the method above, using decorators we can inject logic to our decorated method. This decorator would then be used by importing the function in our component.ts, and prepending it to our method definition as follows</p><pre>@decorator<br>myDecoratedMethod(){.....}</pre><p>Makes sense? Now let’s try it for real on our confirmable decorator :)</p><p><strong>confirmable.decorator.ts</strong></p><pre>import Swal, {SweetAlertOptions} from &#39;sweetalert2&#39;;</pre><pre>export function Confirmable (target: Object, propertyKey: string, descriptor: PropertyDescriptor) {</pre><pre> // Again, cache the original method for later use<br> const originalMethod = descriptor.value;</pre><pre> // the configuration object for sweetalert<br> const config: SweetAlertOptions = {<br>  title: &#39;Are you sure?&#39;,<br>  html: &#39;Do you want to perform this action?&#39;,<br>  showDenyButton: true,<br>  confirmButtonText: &#39;Yes&#39;,<br>  denyButtonText: &#39;No&#39;,<br>  icon: &#39;question&#39;<br> };</pre><pre> // we write a new implementation for the method<br> descriptor.value = async function (...args) {</pre><pre>   const res = await Swal.fire(config);  <br>   // fire sweetalert with the config object</pre><pre>   if (res.isConfirmed){ // if user clicked yes,</pre><pre>   // we run the original method with the original arguments<br>   const result = originalMethod.apply(this, args);<br>  <br>   // and return the result<br>   return result;<br>  }<br> };</pre><pre> return descriptor;<br> };</pre><pre>}</pre><p>So now, any method decorated with our decorator will ask for a confirmation, and will only be executed if the user clicks “Yes”. we will now implement it in our item component.</p><p><strong>item.component.ts</strong></p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;<br>import { Confirmable } from &#39;../decorators/confirmable.decorator&#39;;</pre><pre>@Component({<br> selector: &#39;app-item&#39;,<br> templateUrl: ‘./item.component.html&#39;,<br> styleUrls: [&#39;./item.component.scss&#39;]<br>})</pre><pre>export class ItemComponent implements OnInit {</pre><pre> constructor() {}</pre><pre> ngOnInit(): void {}</pre><pre> @Confirmable<br> deleteItem(): void {<br>   //Code to delete your item<br> }</pre><pre>}</pre><p><strong>item.component.html</strong></p><pre>&lt;button (click)=”deleteItem()”&gt;Delete item&lt;/button&gt;</pre><p>And here we go. Now when clicking the button, our decorator shall trigger asking for a confirmation, and only if the user clicks “yes” will our <strong>deleteItem</strong> method executed.</p><h4><strong>Passing data to the decorator</strong></h4><p>Our previous solution definitely works, but there is in my opinion a small flaw in our implementation which makes it a bit inflexible: Using this decorator, the confirmation title and message are hardcoded in the decorator logic, and as such we will have the same message for every confirmation box throughout our application. While this may be acceptable in some use cases, this is definitely not always the case!</p><p>The solution to this is to use decorator factories. Instead of having our decorator ts file export our decorator function directly, we will export a callable function, which will return our decorator function. The subtle difference here is that our callable factory function will be able to accept parameters, which can be used to further customize our decorator’s behavior.</p><p>This sounds a little abstract, so again let’s look at code :)</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5905122835b5dadf16c1785d688b0aa0/href">https://medium.com/media/5905122835b5dadf16c1785d688b0aa0/href</a></iframe><p>To use this new version of our decorator, we must now update our component code to reflect the fact that “Confirmable” is now a callable function returning our decorator, rather than the decorator itself.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b67b4db47c2cc75e09536f47bb815fe8/href">https://medium.com/media/b67b4db47c2cc75e09536f47bb815fe8/href</a></iframe><p>Now we can pass the different keys from the @Confirmable() call itself. A few things to note here are that:</p><ul><li>The options parameter is optional. As such @Confirmable() would work just as well.</li><li>Since we set the type of options to “SweetAlertOptions”, typescript and your editor will kick in and you should get autocompletion for the option object’s available properties :)</li></ul><p>Again, running the code and clicking the delete button will show our sweetalert confirmation box :)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eeqNWAO8zk5xfSzzEOlbmg.png" /></figure><p>Now, anytime we’ll need to get user confirmation for an action, we can just import our confirmable decorator, and apply it on the methods we need the confirmation on.</p><p>This was just an example of what can be achieved using decorators. The goal is to factor out reusable functionalities that can then just be imported to be used.</p><p>Keep safe and keep learning :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4595816e7b87" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/building-custom-typescript-decorators-for-angular-4595816e7b87">Building custom typescript decorators for angular</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Decorators in Angular]]></title>
            <link>https://medium.com/@bilkiss.dulloo/decorators-in-angular-16e20efcd17c?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/16e20efcd17c</guid>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Tue, 30 Mar 2021 10:20:28 GMT</pubDate>
            <atom:updated>2021-03-30T10:20:28.007Z</atom:updated>
            <content:encoded><![CDATA[<h4><strong>Class Decorators</strong></h4><p>Angular offers us a few class decorators. These are the top-level decorators that we use to express <em>intent</em> for classes. They allow us to tell Angular that a particular class is a component, or module, for example. And the decorator allows us to define this intent without having to actually put any code inside the class.</p><h4>A <strong>@Component:</strong></h4><p>Are decorators that mark a class as an Angular component and provide configuration metadata that determines how the component should be processed, instantiated, and used at runtime.</p><h4>and <strong>@NgModule</strong>:</h4><p>Are decorator that mark a class as an NgModule and supplies configuration metadata.</p><p>Here are the decorators example with classes:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ef347fa0ec9069be8aa06bc5bf7d87c3/href">https://medium.com/media/ef347fa0ec9069be8aa06bc5bf7d87c3/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2955e695e32b747f7ef6d7c6620766b8/href">https://medium.com/media/2955e695e32b747f7ef6d7c6620766b8/href</a></iframe><p>Notice how both classes by themselves are effectively the same. No code is needed within the class to tell Angular that it is a component or a module. All we need to do is decorate it, and Angular will do the rest.</p><h4>Property Decorators</h4><p>These are probably the second most common decorators that you’ll come across. They allow us to decorate specific properties within our classes — an extremely powerful mechanism.</p><p>Let’s take a look at <strong>@Input()</strong>:</p><p><em>Are decorators that mark a class field as an input property and supplies configuration metadata. The input property is bound to a DOM property in the template. During change detection, Angular automatically updates the data property with the DOM property’s value.</em></p><p>Imagine that we have a property within our class that we want to be an input binding.</p><p>Without decorators, we’d have to define this property in our class anyway for TypeScript to know about it, and then somewhere else tell Angular that we’ve got a property that we want to be an input.</p><p>With decorators, we can simply put the<strong> @Input()</strong>:</p><p><em>Are decorators that mark a class field as an output property and supplies configuration metadata. The DOM property bound to the output property is automatically updated during change detection.</em></p><p>They are decorators that are above the property — which Angular’s compiler will automatically create an input binding from the property name and link them.</p><p>We’d then pass the input binding via a component property binding:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/33dadbc9088d82d54bd8a21026e7962e/href">https://medium.com/media/33dadbc9088d82d54bd8a21026e7962e/href</a></iframe><p>The property decorator and “magic” happens <em>within</em> the ExampleComponent definition. Here, with the <em>&lt;example-component&gt;</em> tag there is a single property exampleProperty which is decorated, which is easy to change, maintain and track as our code base grows. You can call your <em>&lt;example-component&gt;</em> tag on any component and can use it as a template.</p><h4>Method Decorators</h4><p><strong>@HostListener</strong>:</p><p><em>Are decorator that declares a DOM event to listen for, and provides a handler method to run when that event occurs.</em></p><p>Method decorators are very similar to property decorators but are used for methods instead. This let’s us decorate specific methods within our class with functionality. A good example of this is <strong>@HostListener</strong>. This allows us to tell Angular that when an event on our host happens, we want the decorated method to be called with the event.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cd545f2564cdbbeae4136dc5246ed6c1/href">https://medium.com/media/cd545f2564cdbbeae4136dc5246ed6c1/href</a></iframe><h4><strong>Parameter Decorators</strong></h4><p>Parameter decorators are quite interesting. You may have come across these when injecting primitives into a constructor, where you need to manually tell Angular to inject a particular provider.</p><p>Parameter decorators allow us to decorate parameters in our class constructors.</p><p>Due to the metadata that TypeScript exposes for us we don’t actually have to do this for our providers:</p><pre>constructor(@Inject(MyService) myService) {<br>   console.log(myService); // MyService<br>}</pre><p>We can just allow TypeScript and Angular to do the hard work for us by specifying the provider to be injected as the parameter <em>type</em>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/aab806acc0ac228c246ada001e14b5b5/href">https://medium.com/media/aab806acc0ac228c246ada001e14b5b5/href</a></iframe><p>Now that we’ve covered the types of decorators we can use, let’s dig into what they actually are doing — and why we need them.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=16e20efcd17c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Angular custom directives]]></title>
            <link>https://medium.com/swlh/angular-custom-directives-d70b2e305ab6?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/d70b2e305ab6</guid>
            <category><![CDATA[directives]]></category>
            <category><![CDATA[user-roles]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Thu, 31 Dec 2020 11:28:45 GMT</pubDate>
            <atom:updated>2020-12-31T11:28:45.708Z</atom:updated>
            <content:encoded><![CDATA[<h3>Part 2: Structural directives</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gLSk54aThNB4w48CTuhhjw.png" /></figure><p>In this 2-part series, we are looking at how to implement custom directives in Angular. As a reminder, in the first part, we looked at how to create a custom attribute directive to implement a <a href="https://medium.com/swlh/creating-a-drag-and-drop-file-upload-component-using-angular-directives-91596ecb65bf">drag &amp; drop file upload</a> functionality.</p><p>In this second part, we are going to look at structural directives, and how to use them to dynamically change our DOM structure.</p><h4><strong>What are directives?</strong></h4><p>As we have discussed before, there are three kinds of directives in Angular:</p><ol><li><strong>Components </strong>— directives with a template.</li><li><strong>Attribute directives</strong> — change the appearance or behavior of an element, component, or another directive, and</li><li><strong>Structural directives</strong> — change the DOM layout by adding and removing DOM elements.</li></ol><p><em>Components</em> are the most common of the three directives and are one of the core building blocks in the Angular framework to build applications. They are basically the same as an attribute directive except that their selector is actually a tag, and they have an associated template markup.</p><p>On the other hand, attribute directive, such as our previously visited FileUploadDirective, changes the appearance and/or behavior of the host DOM element according to the logic implemented.</p><p><em>Finally, structural directives, which we’ll be looking at today,</em> can change our DOM <em>structure</em>, usually by adding, removing, or manipulating elements. As with other directives, structural directives are usually applied to a <em>host element</em>. The directive then does whatever it’s supposed to do with that host element and its descendants.</p><p>Structural directives are easy to recognize in html markup: the directive’s attribute name is always preceded by an asterisk (*).</p><pre>&lt;span *ngIf=”user” class=”name”&gt;Welcome {{user.name}} !&lt;/span&gt;</pre><p>In the above example, the span is either present or absent from the dom, depending on whether the “user” property of our component class is set or not.</p><p>Structural directives are important as they let us control the DOM and how it reacts to changes in our underlying data. Now let’s see how to build our own.</p><h4>How to create our structural directive</h4><p>The process to create a structural directive is not very different from the one to create an attribute directive. Again, we can simply use the CLI to generate our class. For example:</p><pre>ng g directive directives/myStructuralDirective</pre><p>This will generate a new typescript class decorated with the @Directive decorator, which will contain our directive’s implementation logic.</p><h4>So, what are we building today?</h4><p>The structural directive we are building will allow us to conditionally attach or remove an element in our dom, depending on whether a logged in user has a specific role and as such the permission to see the element our directive will be attached to. Sounds hard? No worries, as usual we’re going to take it slow :)</p><h4>Step 1. Generating the class file</h4><p>Similarly to an attribute directive, a minimal structural directive would consist of a class annotated with the @Directive decorator, which specifies the selector that identifies our directive. This class will then implement the desired directive behavior.</p><p>So we begin by generating our directive class using the CLI</p><pre>ng generate directive directives/enableForRole</pre><p>This command will do three things:</p><ol><li>Generate our class file at ‘src/app/directives/enable-for-role.directive.ts’,</li><li>Generate a corresponding test file at ‘src/app/directives/enable-for-role.directive.spec.ts’, and</li><li><em>Declare</em> the directive class in our root AppModule.</li></ol><p>The generated main directive class enable-for-role.directive.ts will look as follows:</p><pre>import { Directive} from ‘@angular/core’;</pre><pre>@Directive({<br>  selector: ‘[appEnableForRole]’<br>})</pre><pre>export class EnableForRoleDirective {</pre><pre>  constructor() {}</pre><pre>}</pre><p>Here we are importing the @Directive decorator, and using it to configure our directive class. The directive’s selector is defined by default as ‘[appEnableForRole]’, but let’s change that to ‘[enableForRole]’ for convenience and readability.</p><p>Again, similarly to attribute directives’ selectors, It’s the brackets ([]) that make it an attribute selector. Angular will locate each element in the template that has an attribute named appEnableForRole and apply the logic of this directive to that element.</p><p>As opposed to attribute directives though, when using our structural directives in our markup, we need to prefix its selector with an asterisk (*). This is how Angular can tell that this is a structural directive rather than just a regular old attribute directive. Below is an example of how we would use this particular structural directive in our markup:</p><pre>&lt;p *enableForRole=”admin”&gt;This tag is only displayed for admin users!&lt;/p&gt;</pre><p>But let’s not get ahead of ourselves just yet. We still need to build the logic of our directive!</p><h4>Step 2. Adding the necessary imports</h4><p>After the @Directive decorator comes the directive’s class, called EnableForRoleDirective, which contains the (currently empty) logic for the directive. Exporting EnableForRoleDirective makes the directive accessible.</p><p>We will now edit the generated src/app/directives/enable-for-role.directive.ts file. First, we will import TemplateRef and ViewContainerRef from ‘@angular/core’, and inject them in our constructor. The resulting file shall look as follows:</p><pre>import { Directive, TemplateRef, ViewContainerRef } from ‘@angular/core’;</pre><pre>@Directive({<br> selector: ‘[enableForRole]’<br>})</pre><pre>export class EnableForRoleDirective {</pre><pre>constructor(<br> private templateRef: TemplateRef&lt;any&gt;,<br> private viewContainerRef: ViewContainerRef<br> ) {}</pre><pre>}</pre><p>We have added two new imports to our directive class. What do they do?</p><h4>Well let’s begin with TemplateRef.</h4><p>TemplateRef represents the contents of an embedded &lt;ng-template&gt; that can be used to instantiate embedded views. In short, it will basically contain the innerHTML of our host element. In our case, this would be the content we want to add/remove depending on the user role.</p><p>Next is the ViewContainerRef. We will be using this class to either instantiate a new embedded view based on the contents our TemplateRef described above, or clear the content if the user doesn’t have the necessary role.</p><p>So, in a very simplified summary, our TemplateRef will contain the innerHTML structure of our directive’s host element, and our ViewContainerRef will enable us to either render this content or clear it.</p><h4>Sidequest 1: More about &lt;ng-template&gt;</h4><p>In the last step, we have seen that TemplateRef will reference the contents of an &lt;ng-template&gt; element. But what does that mean?</p><p>Ng-template is a virtual element in angular. What thi means is that tags within a pair of &lt;ng-template&gt; tags will not be rendered by default. This is useful if we need to control when to include / exclude specific blocks of markup from the rendered DOM.</p><p>But wait, we aren’t using any ng-template tags in our markup, so how will this work? Well, it is all thanks to the structural directive :) Remember how we said that we would use our new directive like the following?</p><pre>&lt;p *enableForRole=”admin”&gt;This tag is only displayed for admin users!&lt;/p&gt;</pre><p>Well, because of that asterisk, this code will be transformed by angular into the following:</p><pre>&lt;ng-template [enableForRole]=”`admin`”&gt;<br>  &lt;p&gt;This tag is only displayed for admin users!&lt;/p&gt;<br>&lt;/ng-template&gt;</pre><p>And our TemplateRef will therefore contain our &lt;p&gt; tag.</p><h4>Step 3. Implementing the actual logic</h4><p>We will now (finally) be writing the logic of our directive. So in short what we will be doing here is firstly, create a virtual property with the same name as our selector, to which we will be assigning our desired role from the html. We do this by creating a setter, which will run anytime we try to assign a value to the property, and decorating it with the @input decorator, so that it will have access to the role we are assigning from the html.</p><p>We will then get the user data from storage (presumably we will have saved it there after a sign in) and check whether the user has the role specified above. If they do, we will render the contents of the TemplateRef inside our ViewContainerRef. Else we will clear the ViewContainerRef. Here is what the completed code looks like:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b0e13448745e6a6da0e3b68795203982/href">https://medium.com/media/b0e13448745e6a6da0e3b68795203982/href</a></iframe><h4>Sidequest 2: Mocking our user data</h4><p>In our directive, we are fetching the user object from the browser’s localStorage. Usually we will have saved it there when a user successfully logs in. For the sake of brevity in this demo however we will be directly mocking the data inside our storage.</p><p>In our browser’s developer tools console, we can inject data into the storage by using the following commands.</p><pre>// Mocking an admin</pre><pre>localStorage.setItem(“user”, JSON.stringify({<br> first_name: “Test”,<br> last_name: “Lastname”,<br> role: “admin”,<br> email: “admin@test.io”<br> }) );</pre><p>And to overwrite the mocked data with a non admin user, we can run</p><pre>// Mocking a normal user</pre><pre>localStorage.setItem(“user”, JSON.stringify({<br> first_name: “Test”,<br> last_name: “Lastname”,<br> role: “user”,<br> email: “user@test.io”<br> } ));</pre><p>And we now have our mock user data inside our storage.</p><h4>Step 4. Apply the attribute directive</h4><p>To use the new EnableForRoleDirective, We will add a paragraph (&lt;p&gt;) element to the template of our AppComponent and apply the directive as an attribute.</p><pre>&lt;p *enableForRole=”`admin`”&gt;I am an Admin!&lt;/p&gt;</pre><p>Now we can run the application to see the EnableForRoleDirective in action.</p><pre>ng serve</pre><p>You will notice that depending on what user role is stored in our storage, The directive will insert or remove our &lt;p&gt; tag accordingly.</p><p>To summarize, Angular found the EnableForRole attribute on the <strong>host</strong> &lt;p&gt; element. It created an instance of the EnableForRoleDirective class and injected a reference to the &lt;p&gt; element into the directive’s constructor which will show or hide the &lt;p&gt; element depending on the user role.</p><p>So, in conclusion, a structural directive is not that different from an attribute directive. The main thing that differentiates the two variants is that the structural directives allow us to easily modify the dom structure by allowing us to access and manipulate the dom structure of our host elements’ DOM structure.</p><p>Also, by digging around, you may notice that the directive does not yet react to changes to the login status. We will look at how to use rxjs to make it a bit more reactive in a future article.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d70b2e305ab6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/angular-custom-directives-d70b2e305ab6">Angular custom directives</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Deep dive into Angular Forms]]></title>
            <link>https://medium.com/@bilkiss.dulloo/deep-dive-into-angular-forms-8b4783572ab7?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/8b4783572ab7</guid>
            <category><![CDATA[forms]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[reactive-forms]]></category>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Thu, 17 Dec 2020 12:11:33 GMT</pubDate>
            <atom:updated>2020-12-17T12:11:33.141Z</atom:updated>
            <content:encoded><![CDATA[<p>Part 1 — The basics of Reactive forms</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8nm0IFMPNvSjcGp-f2VjtA.png" /></figure><p>Forms are a very important part of any real, non trivial application requiring user input. From simple static forms to dynamic event driven reactive forms, Angular provides us with tools and modules to build powerful forms. In this short series of articles, we are going to explore the tools that the framework provides us to build, handle and maintain forms throughout your application. In this first part we shall explore Angular’s Reactive Forms module.</p><p>Reactive forms? what’s that again?</p><p>Before we take a deep dive into the code, we need to understand what the tool is, and what we are going to build with it. so, what in the heavens is a reactive form?</p><p>In Angular, the reactive forms module provides us with an explicit and immutable approach to managing the state of a form at a given point in time.</p><p>In practical terms, it means that our components’ typescript code will hold a model representing our form, the fields within it, the value of said fields as well as the validation rules and validity status of our form.</p><p>Each change to the form state will return a new state, which maintains the integrity of the model between changes. Reactive forms are built around observable streams, where form inputs and values are provided as streams of input values, which can be accessed synchronously.</p><p>Reactive forms differ from template-driven forms in a few distinct ways. For instance, Reactive forms provide more predictability with synchronous access to the data model, immutability with observable operators, and change tracking through observable streams.</p><p>Ok now with that out of the way, let’s take a look at how we will build a reactive form.</p><h4><strong>Step 1.</strong> Generating angular-forms project</h4><p>So as usual, we will begin by generating a new project for our little exploration of reactive forms.</p><pre>ng new angular-forms</pre><p>We will enable routing and choose scss as our style language as this is what we’ll be using throughout this series, but you may do otherwise depending on your needs).</p><h4>Step 2. (Optional) Installing bootstrap and font-awesome</h4><p>We will be using bootstrap as well as font awesome in order to make our form’s UI look more aesthetically pleasing. This can be done by running the following command.</p><pre>npm install --save bootstrap font-awesome</pre><p>After the installation is done, we can import the two libraries by adding the following lines in our styles.scss file (located in the src directory of your app)</p><pre>@import &quot;~bootstrap/scss/bootstrap&quot;;<br>@import &quot;~font-awesome/css/font-awesome.min.css&quot;;</pre><h4>Step 3. Import ‘ReactiveFormsModule’</h4><p>We will now import `ReactiveFormsModule` inside our application’s file (typically app.module.ts). The module can be imported from @angular/forms as follows:</p><pre>import { ReactiveFormsModule } from &#39;@angular/forms&#39;;</pre><p>After that, we’ll need to add the module in our imports array for it to be available to our components. Our app.module.ts file should look like below.</p><pre>import { BrowserModule } from &#39;@angular/platform-browser&#39;;<br>import { NgModule } from &#39;@angular/core&#39;;</pre><pre>import { AppRoutingModule } from &#39;./app-routing.module&#39;;<br>import { AppComponent } from &#39;./app.component&#39;;<br>import { ReactiveFormsModule } from &#39;@angular/forms&#39;;</pre><pre>@NgModule({</pre><pre>  declarations: [<br>    AppComponent<br>  ],</pre><pre>  imports: [<br>   BrowserModule, <br>   AppRoutingModule, <br>   ReactiveFormsModule<br>  ],</pre><pre>  providers: [],</pre><pre>  bootstrap: [AppComponent]</pre><pre>})</pre><pre>export class AppModule { }</pre><p>We now have access to Angular’s ReactiveFormsModule from our application’s components.</p><p>Now before we continue, there are a few key concepts that we need to be familiar with, namely</p><ul><li>Form Controls,</li><li>Form Groups, and</li><li>Form Builders.</li></ul><p>The FormControl object will represent your form inputs. each input will need to have a corresponding FormControl object in your compnent’s ts file. These objects will keep track of the input’s default value, updated value, validation rules and status.</p><p>A FormGroup will represent a group of FormControl objects. It will have similar properties and keep track of the different controls within it.</p><p>Finally, the FormBuilder class is a helper class that will help us to easily build our form’s group/control structure as well as assigning default values and validation rules.</p><p>Sounds a bit vague? No problem, let’s jump into some code :)</p><h4>Step 4. Component</h4><p>For this demo, we will be using a cv component, that will present us a form to input our CV’s details. So let’s create our cv component with the following command</p><pre>ng g component components/cv</pre><p>We should now have a new component :)</p><p>We will now add it in our app-routing.module.ts</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/401a0a51614b47fc92ce5c07298fcd0e/href">https://medium.com/media/401a0a51614b47fc92ce5c07298fcd0e/href</a></iframe><h4>Step 5. Form Logical Structure</h4><p>In our newly created cv.component.ts we will begin by importing FormBuilder, Validators, and FormGroup from @angular/forms.</p><pre>import { FormBuilder, FormGroup, Validators} from &quot;@angular/forms&quot;;</pre><p>As described above, FormBuilder is a helper class that will aid us in setting up our form model. Validators contains a set of inbuilt validators that we can use in our form, and FormGroup will help us organize our form’s structure.</p><p>Next we’ll add a property of type FormGroup to our class. this form group will represent our example form.</p><pre>cvForm: FormGroup;</pre><p>We can now inject the FormBuilder service class in our component’s constructor as follows</p><pre>constructor(private fBuilder: FormBuilder) { }</pre><p>We can now use the FormBuilder service in our cv component.</p><p>The FormBuilder service has three methods: control(), group(), and array(). These are factory methods for generating instances in your component classes including form controls, form groups, and form arrays.</p><p>Inside our component’s ngOnInit method, we will be using the group method to create our controls.</p><pre>ngOnInit(): void {</pre><pre>  this.cvForm = this.fBuilder.group({<br>    email: [‘’],<br>    password: [‘’],<br>    confirm_password: [‘’],<br>    rating: [0],<br>    skill_name: [‘’]<br>  })</pre><pre>}</pre><p>In the example above, we are using the FormBuilder’s group() method with an object to define the properties of our form. The value for each control name is an array containing the initial value as the first item in the array (here an empty string for every field except rating, which we are setting to “0”).</p><p>Our form will therefore have 5 inputs, namely for the email, password, password confirmation, a skill name and its rating.</p><p>We don’t have any validation rules applied yet though. Let’s fix this.</p><h4>Step 6. Validation</h4><p><em>Form validation</em> is used to ensure that user input is complete and correct. To summarize, the steps to add validation to a form control are as follows:</p><ol><li>e need to Import a validator function (custom or inbuilt) in our component.</li><li>We will then add the validator to the form control.</li><li>And finally add logic to handle the validation status.</li></ol><p>One of the most common validation use cases is making a field required. Let’s try doing exactly that:</p><p>If you look at the code we’ve written so far, you’ll notice that, at the very beginning of our component code, we are importing Validators from “@angular/forms”. What does this do? Well, reactive forms include a set of validator functions for common use cases. These functions receive a control to validate against and return an error object or a null value based on the validation check.</p><p>In the form initialization code, we will add the `Validators.required` static method as the second element in the array for the different form controls.</p><pre>this.cvForm = this.fBuilder.group({<br>  email: [&#39;&#39;, <strong>Validators.</strong><strong><em>required</em></strong>],<br>  password: [&#39;&#39;, <strong>Validators.</strong><strong><em>required</em></strong>],<br>  confirm_password: [&#39;&#39;],<br>  rating: [0, <strong>Validators.</strong><strong><em>required</em></strong>],<br>  skill_name: [&#39;&#39;, <strong>Validators.</strong><strong><em>required</em></strong>]<br>})</pre><p>You will notice right away that we’re not applying the validator to the confirm_password field here. For that we shall add a custom validator to compare the passwords entered.</p><p>For simplicity’s sake, we will write the custom valdation function directly after our ngOnInit method. please note that usually in most cases you would want to externalize custom validator functions so that they can be reused.</p><p>Let’s call our validation function `checkPasswords`.</p><pre>checkPasswords(group: FormGroup){</pre><pre>  let pass = group.get(‘password’).value;<br>  let confirmPass = group.get(‘confirm_password’).value;<br>  return pass === confirmPass ? null : { notSame : true }</pre><pre>}</pre><p>The method will take a FormGroup instance as a parameter, perform your custom checks on the group’s controls, and then return either null if the form group is valid, or else an object setting your custom error to true. In our case above, if the `password` control’s value is different from the `confirm_password` control’s value, a ‘notSame’ (arbitrary name, you could make up your own) error will be trigerred on the form.</p><p>We will then update our form’s initialization code to use our new validator :)</p><pre>this.cvForm = this.fBuilder.group({</pre><pre>  email: [‘’, Validators.<em>required</em>],<br>  password: [‘’, Validators.<em>required</em>],<br>  confirm_password: [‘’],<br>  rating: [0, Validators.<em>required</em>],<br>  skill_name: [‘’, Validators.<em>required</em>]</pre><pre>}, { validators: this.checkPasswords })</pre><p>But, something’s different here. We are not setting the validator directly on the form control but after the definition. Why would that be?</p><p>Well to put it simply, our checkPasswords validator cannot be bound to a single form control because we are using values from 2 different controls inside its logic. It therefore needs to be applied at the FormGroup level.</p><p>We will also add a “createCV” method that we will trigger on form submission. for now it will just log the whole form value to the console.</p><p>Here is what our final cv.component.ts will look like:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bef7b282db449f42695f065befe5af6c/href">https://medium.com/media/bef7b282db449f42695f065befe5af6c/href</a></iframe><p>Almost done! now let’s look at the markup.</p><h4>Step 7. HTML</h4><p>Inside our component’s template file (cv.component.html), we will now need to write the markup for our form. The page structure and styling aside, here are the important parts we will need to include in our markup:</p><pre>&lt;form [formGroup]=”cvForm”&gt;<br>   …<br>&lt;/form&gt;</pre><p>Firstly the form tag. as shown above, we can bind it to the formgroup created in our component ts file using the [formGroup] directive.</p><p>Next, let’s look at how to add our form controls. we will take the email field as en example:</p><pre>&lt;input type=&quot;text&quot; formControlName=&quot;email&quot; class=&quot;form-control&quot; placeholder=&quot;Please enter your Email&quot; /&gt;</pre><p>By usingthe formControlName directive and binding it to our form control name defined in our ts file, we have now bound this html input tag to our form control object. We can even change its attributes depending on the formcontrol’s status:</p><pre>&lt;input type=”text” formControlName=”<strong>email</strong>” class=”form-control” placeholder=”Please enter your Email” [ngClass]=”{‘<strong>is-invalid</strong>’: cvForm.controls.<strong>email</strong>.dirty &amp;&amp; cvForm.controls.<strong>email</strong>.invalid}” /&gt;</pre><p>Now our input will have a class of “is-invalid” whenever the formControl’s validator(s) fail. You will notice that, in addition to checking for validity, we are checking a property of our control called “dirty”.</p><pre>cvForm.controls.email.dirty</pre><p>What this property does is, returns true if and only if the form control’s value has been changed by the user since the form was loaded. This will prevent us from getting errors caused by the initially empty required fields.</p><p>What if we needed to display an error message to the user in case the form was invalid? Well we already know the condition to use and can just use an *ngIf to handle it :)</p><pre>&lt;div class=&quot;is-invalid text-danger mt-1&quot; <strong>*ngIf</strong>=&quot;cvForm.controls.email.dirty &amp;&amp; cvForm.controls.email.invalid&quot;&gt;Email is required!&lt;/div&gt;</pre><p>And it is done!</p><p>We can now repeat this logic for all our form fields, so that all controls have a corresponding input.</p><h4>Step 8. The submit button</h4><p>The last part we will look at now is the form’s submit button. let’s take a look at the button tag below:</p><pre>&lt;button class=&quot;btn btn-sm btn-outline-dark mr-2&quot; (click)=&quot;createCv()&quot;&gt;<br>  &lt;i class=&quot;fa fa-envelope mr-2&quot;&gt;&lt;/i&gt; Save CV<br>&lt;/button&gt;</pre><p>On click of this button, we are going to call our createCv method. But what if we wanted the button to be disabled when our form was in an invalid state?</p><pre>&lt;button class=&quot;btn btn-sm btn-outline-dark&quot;  [disabled]=&quot;cvForm.invalid&quot; (click)=&quot;createCv()&quot;&gt;<br>   &lt;i class=&quot;fa fa-envelope mr-2&quot;&gt;&lt;/i&gt; Save CV<br>&lt;/button&gt;</pre><p>The <strong>Submit</strong> button will now be disabled whenever cvForm is in an invalid state.</p><p>Our final cv.component.html file, with added markup for style and formatting, will be as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/edea0bc21351b47f3e4cf5343ab077b1/href">https://medium.com/media/edea0bc21351b47f3e4cf5343ab077b1/href</a></iframe><p>We now have a basic form with validation. The next part we will be looking at how to implement custom form controls.</p><p>Neat! now we can submit the form, or store the values in our localStorage, or whatever our requirements dictate :)</p><p>In the next part of this series we will be looking at how to create custom form controls outside of those provided natively by our browser.</p><p>Until then, Stay safe and keep learning ^^</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8b4783572ab7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Angular: Créer un composant d’upload en glisser/déposer en utilisant une directive]]></title>
            <link>https://medium.com/@bilkiss.dulloo/angular-cr%C3%A9er-un-composant-dupload-en-glisser-d%C3%A9poser-en-utilisant-une-directive-a32ae33a6eb6?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/a32ae33a6eb6</guid>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[upload]]></category>
            <category><![CDATA[directives]]></category>
            <category><![CDATA[drag-and-drop]]></category>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Sun, 16 Aug 2020 10:50:40 GMT</pubDate>
            <atom:updated>2020-08-16T10:50:40.867Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zpjhfRzEZ97uF79D9bP5vQ.gif" /></figure><p>Note: Ceci est une traduction d’un de mes articles en Anglais <a href="https://medium.com/swlh/creating-a-drag-and-drop-file-upload-component-using-angular-directives-91596ecb65bf">ici</a></p><p>Il y a quelques semaines lors d’une de mes sessions de formation, l’une de mes sessions de formation, un de mes élèves travaillant sur un projet Angular devait implémenter un composant d’upload de fichiers en glisser/déposer.</p><p>Comme probablement tout développeur, son premier réflexe était de chercher un plugin existant sur npm, mais en l’aidant à externaliser et personnaliser l’aspect visuel du plugin je me suis dit que c’était en fait une belle opportunité de démystifier l’implémentation d’une fonctionnalité de cette envergure, en l’aidant à créer son propre composant :) Cet article est le résumé du résultat de cette session de travail.</p><p>Dans notre cas, nous avions déjà un projet Angular sur lequel travailler. Cependant, afin que cet article puisse être suivi indépendamment, nous allons commencer par créer un squelette d’application générique.</p><p>Comme dans mon dernier article je pars du principe que vous avez déjà l’outil CLI du framework Angular d’installé sur votre machine. Si tel n’est pas le cas vous pouvez jeter un œil sur la doc :)</p><p>( <a href="https://angular.io/guide/setup-local">https://angular.io/guide/setup-local</a> )</p><h3>Step 1: Création du projet</h3><p>Dans un invite de commande, entrez la commande suivante:</p><pre>ng new angular-file-upload --style=scss</pre><h3>Step 2: Générer une nouvelle directive qui contiendra notre logique pour le glisser/déposer.</h3><p>Les directives en Angular sont des fonctions qui améliorent les capacités des éléments HTML en y rattachant de la logique via des balises et/ou attributs personnalisables. Voyons ce que cela donne concrètement.</p><p>Nous allons tout d’abord changer de dossier pour aller a la racine de notre projet</p><pre>cd angular-file-upload</pre><p>Nous pouvons ensuite générer notre directive avec le CLI Angular</p><pre>ng g directive directives/upload</pre><p>Cette commande va créer le fichier upload.directive.ts comme tel:</p><pre>import { Directive } from ‘@angular/core’;</pre><pre>@Directive({<br>  selector: ‘[appUpload]’<br>})</pre><pre>export class UploadDirective {<br>  constructor() { }<br>}</pre><p>Cette classe sera notre directive. Nous pouvons déjà noter ici la ligne “selector: [‘appUpload’]”. Cette ligne signifie en gros que, tout élément (ou tag) dans le DOM auquel nous attacherons l’attribut “appUpload” va hériter de la logique que nous allons définir dans cette classe. Nous pouvons aussi changer le nom du sélecteur mais pour cette démo on va la laisser tranquille :)</p><h3>Step 3: Import des composants de notre directive</h3><p>Angular étant un framework très complet à la base, nous avons déjà tout ce dont nous avons besoin pour implémenter notre fonctionnalité, et n’aurons besoin d’aucune dépendance externe. Nous aurons juste à importer quelques décorateurs depuis @angular/core</p><p>Nous allons maintenant changer la ligne d’import de notre directive comme suit:</p><pre>import { Directive, Output, EventEmitter, HostBinding, HostListener, HostBindingDecorator } from ‘@angular/core’;</pre><p>Jetons un œil sur les nouvelles additions. Nous avons donc:</p><ul><li>Output et EventEmitter seront utilisés afin d’exposer un évènement auquel notre composant pourra réagir. En effet, notre composant devra pouvoir réagir au drop d’un fichier.</li><li>HostBinding permet d’interagir avec les propriétés de l’élément DOM auquel notre directive sera rattachée (le Host) Dans notre cas nous allons uniquement interagir avec l’attribut “style”</li><li>et HostListener permet d’écouter et réagir aux évènements DOM de notre élément Host.</li></ul><h3>Step 4: Définir les propriétés de notre classe directive.</h3><p>Dans la définition de notre Classe, nous allons tout d’abord rajouter trois propriétés en utilisant nos décorateurs Output et HostBinding définis plus haut:</p><pre>@Output() onFileDropped = new EventEmitter&lt;any&gt;();<br>@HostBinding(‘style.background-color’) public background = ‘#fff’;<br>@HostBinding(‘style.opacity’) public opacity = ‘1’;</pre><p>Ces trois propriétés vont nous permettre de contrôler notre directive.</p><ul><li>OnFileDropped sera l’événement que notre directive exposera a notre component, d’ou le decorateur Output. Nous lancerons l’événement OnFileDropped quand un fichier sera déposé sur notre élément Host.</li><li>background et opacity sont de simple variables que nous rattachons ici à la propriété “style” de notre élément Host. Notez que nous définissons aussi par défaut une couleur (blanc) et une opacité complète.</li></ul><p>Si nous rattachons maintenant notre directive à un élément DOM dans notre component, rien ne va se passer, à part le fait que la couleur et l’opacité seront aux valeurs définies plus haut.</p><p>Nous pouvons maintenant rajouter un peu de logique à notre directive :)</p><h3>Step 5: Les évènements DOM</h3><p>Nous allons commencer par ajouter deux méthodes à notre Classe, qui réagiront aux évènements DOM dragOver et dragLeave. Dans ces méthodes, nous allons simplement changer la couleur et l’opacité de notre élément, et en empêcher la propagation :)</p><pre>//Dragover, l&#39;utilisateur glisse quelque chose sur notre élément<br>Host element<br>@HostListener(‘dragover’, [‘$event’]) onDragOver(evt) {<br>  evt.preventDefault();<br>  evt.stopPropagation();<br>  this.background = ‘#9ecbec’;<br>  this.opacity = ‘0.8’<br>}</pre><pre>//Dragleave, l&#39;utilisateur glisse quelque chose hors de notre élément Host<br>@HostListener(&#39;dragleave&#39;, [&#39;$event&#39;]) public onDragLeave(evt) {<br>  evt.preventDefault();<br>  evt.stopPropagation();<br>  this.background = &#39;#fff&#39;<br>  this.opacity = &#39;1&#39;<br>}</pre><h3>Step 6: L’évènement drop</h3><p>On y est presque! nous devons maintenant ajouter notre dernière méthode, qui réagira quand l’utilisateur dépose un fichier sur notre élément.</p><pre>@HostListener(&#39;drop&#39;, [&#39;$event&#39;]) public ondrop(evt) {<br>  evt.preventDefault();<br>  evt.stopPropagation();<br>  this.background = &#39;#f5fcff&#39;<br>  this.opacity = &#39;1&#39;<br>  let files = evt.dataTransfer.files;<br>  if (files.length &gt; 0) {<br>    this.onFileDropped.emit(files)<br>  }<br>}</pre><p>Cette méthode est quelque peu différente, Outre les deux premières lignes pour empêcher la propagation, et le changement de style, ici nous vérifions si ce qui a été déposé sur notre Host est effectivement un fichier, et si tel est le cas nous lancerons notre évènement onFileDropped, auquel notre component pourra réagir è son tour.</p><p>Et nous avons fini notre directive! ;) voici le code complet:</p><pre>import { <em>Directive</em>, <em>Output</em>, <em>EventEmitter</em>, <em>HostBinding</em>, <em>HostListener</em>, <em>HostBindingDecorator</em> } from &#39;@angular/core&#39;;</pre><pre>@Directive({<br>  selector: &#39;[appUpload]&#39;<br>})</pre><pre>export class UploadDirective {</pre><pre>@Output() onFileDropped = new EventEmitter&lt;any&gt;();<br>@HostBinding(&#39;style.background-color&#39;) public background = &#39;#fff&#39;;<br>@HostBinding(&#39;style.opacity&#39;) public opacity = &#39;1&#39;;<br>  <br>  //Dragover, l&#39;utilisateur glisse quelque chose sur notre élément<br>Host element<br>  @HostListener(&#39;dragover&#39;, [&#39;$event&#39;]) onDragOver(evt) {<br>    evt.preventDefault();<br>    evt.stopPropagation();<br>    this.background = &#39;#9ecbec&#39;;<br>    this.opacity = &#39;0.8&#39;<br>  };</pre><pre>//Dragleave, l&#39;utilisateur glisse quelque chose hors de notre élément Host<br>  @HostListener(&#39;dragleave&#39;, [&#39;$event&#39;]) public onDragLeave(evt) {<br>    evt.preventDefault();<br>    evt.stopPropagation();<br>    this.background = &#39;#fff&#39;<br>    this.opacity = &#39;1&#39;<br>  }</pre><pre>  @HostListener(&#39;drop&#39;, [&#39;$event&#39;]) public ondrop(evt) {<br>    evt.preventDefault();<br>    evt.stopPropagation();<br>    this.background = &#39;#f5fcff&#39;<br>    this.opacity = &#39;1&#39;<br>    let files = evt.dataTransfer.files;<br>    if (files.length &gt; 0) {<br>      this.onFileDropped.emit(files)<br>    }<br>  }</pre><pre>  constructor() { }</pre><pre>}</pre><h3>Step 7: Utilisation de notre nouvelle directive</h3><p>Une fois notre directive implémentée, nous pouvons l’inclure dans notre component. Dans notre cas nous utilisons le app Component pour faire simple, mais nous pouvons faire la même chose dans n’importe quel component de notre application.</p><p>Dans notre app.component.html, nous allons rajouter l’élément suivant:</p><pre>&lt;div appUpload (onFileDropped)=&quot;uploadFile(<strong><em>$event</em></strong>)&quot; &gt;Déposer un fichier ici&lt;/div&gt;</pre><p>Notre étape finale sera de réagir a notre onFileDropped depuis notre app.component.ts en y ajoutant la méthode uploadFile</p><pre>uploadFile(evt){<br>// evt est un tableau des fichier(s) déposés sur notre div. Ici nous supposerons qu&#39;il y a un seul fichier uploadé<br>  <br>  let payload = new <strong><em>FormData</em></strong>();<br>  payload.append(&#39;data&#39;, evt[0]);<br>  <em>// </em>Nous pouvons maintenant uploader le fichier en lancant une requete POST avec la variable payload comme corps de requete :)<br>}</pre><p>Nous sommes maintenant libres de personnaliser notre interface utilisateur à volonté avec du CSS :)</p><p>Lors de mes séances de formation, j’essaie beaucoup de démystifier l’implémentation d’éléments UI communs. J’ai pu remarquer au fil des sessions que les nouveaux développeurs ont tendance à traiter les “UI packs” ou composants JavaScript tout prêts comme des boites noires, et leur montrer qu’avec leurs aptitudes actuelles ils peuvent coder une telle fonctionnalité les aide a prendre confiance en eux et démontrer leur créativité :)</p><p>J’ai également ajouté du CSS pour rendre la démo un peu plus “user friendly”. Vous pourrez trouver le code de cette démo <a href="https://github.com/Bilkiss/angular-file-upload">ici</a>.</p><p>Une live démo peut aussi être trouvée <a href="https://angular-upload-file.herokuapp.com/">ici</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a32ae33a6eb6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Creating a Drag and Drop File Upload Component Using Angular Directives]]></title>
            <link>https://medium.com/swlh/creating-a-drag-and-drop-file-upload-component-using-angular-directives-91596ecb65bf?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/91596ecb65bf</guid>
            <category><![CDATA[drag-and-drop]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[directives]]></category>
            <category><![CDATA[upload]]></category>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Sun, 09 Aug 2020 10:35:53 GMT</pubDate>
            <atom:updated>2020-12-31T11:38:28.645Z</atom:updated>
            <content:encoded><![CDATA[<h3>Part 1: Attribute directives</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zpjhfRzEZ97uF79D9bP5vQ.gif" /></figure><p>In this 2-part series, we are looking at how to implement directives in Angular. In this first part we will be looking at attribute directives. And in part 2 we will be looking at <a href="https://medium.com/@bilkiss.dulloo/angular-custom-directives-d70b2e305ab6"><strong>structural directives</strong></a>.</p><p>Recently, during one of my training sessions, one of my trainees working on an Angular project needed to implement a drag and drop file upload component.</p><p>So as is often the first reflex, they looked for an existing npm package that does the task, but ran into issues with making the new packages feel coherent with the rest of the application’s UI.</p><p>After helping them dig around for a way to customize the CSS however, I had a thought. What if I used this situation as an opportunity to build their understanding of custom directives, and by the same occasion demystify the implementation of such a functionality by showing them they could easily build it themselves? This blog post as basically what we ended up with.</p><p>So we already had an existing Angular project initialized, but for the sake of this blog post being its own independent thing if you are following through, we will here create a generic app skeleton to demo this.</p><p>As in my previous blog post I am assuming that you already have the Angular cli installed here. (If not, please check out this guide to install the tooling: Angular — Setting up the local environment and workspace <a href="https://angular.io/guide/setup-local">https://angular.io/guide/setup-local</a> )</p><h4><strong>Step 1: </strong>Creating our standalone project</h4><p>Run the following command in your terminal</p><pre>ng new angular-file-upload --style=scss</pre><h4><strong>Step 2: </strong>Generating a new directive that will contain our logic for the drag and drop file upload.</h4><p>Angular directives are functions that enhance the capability of HTML elements by attaching custom behavior to the DOM via custom tags and attributes. What does this mean concretely? Let’s have a look.</p><p>First we need to change directory to our project folder</p><pre>cd angular-file-upload</pre><p>Then we can generate our brand new directive using the angular CLI</p><pre>ng g directive directives/upload</pre><p>This shall create the following upload.directive.ts file:</p><pre>import { Directive } from ‘@angular/core’;</pre><pre>@Directive({<br>  selector: ‘[appUpload]’<br>})</pre><pre>export class UploadDirective {</pre><pre>constructor() { }</pre><pre>}</pre><p>So basically this class will be our directive. Worthy of note already in that skeleton is the selector in the directive declaration. In a nutshell, this means that any DOM element we attach the “appUpload” attribute to will have additional behaviour that we will defined in this class. We can also change the selector if we wish, but for the purpose of this demo we shall leave it be :)</p><h4><strong>Step 3: </strong>Importing the pieces we need</h4><p>Part of the beauty of Angular is that the framework comes with many parts already included, so we won’t have any external dependency for this functionality and only use what is provided to us in @angular/core.</p><p>Update the import line in our directive to read as follows:</p><pre>import { Directive, Output, EventEmitter, HostBindingDecorator, HostListener } from ‘@angular/core’;</pre><p>So if we go over the new additions, we now have:</p><ul><li>Output and EventEmitter will be used to provide a hook event our component will be able to subscribe to. This is important since we need the component to be able define what happens when a file is dropped.</li><li>HostBindingDecorator will allow us to interact with the properties of the DOM element our directive will be attached to. In our case we will interact with the style of the host element</li><li>and HostListener will allow us to listen to DOM events from the host element and define how our directive will react to them.</li></ul><h4><strong>Step 4: </strong>Define our Class properties</h4><p>Within our Class definition, we will first add three properties using our Output and HostBindingDecorator as follows:</p><pre>@Output() onFileDropped = new EventEmitter&lt;any&gt;();<br>@HostBinding(‘style.background-color’) public background = ‘#fff’;<br>@HostBinding(‘style.opacity’) public opacity = ‘1’;</pre><p>Here we have the properties that will help us control the directive.</p><ul><li>OnFileDropped will be the custom event that we will expose to our component, thus the output decorator. This will be triggered when a file is dropped on our host DOM element later.</li><li>background and opacity on the other hand are simple properties that we are binding to the host DOM element’s style property. We are also setting the default “idle” values to a white background and a full opacity.</li></ul><p>As of now, if we try to attach our directive to a DOM element, nothing much will happen, only the element’s background color and opacity will be affected. So now would be the perfect time to add some more behaviour to our directive :)</p><h4><strong>Step 5: </strong>Adding the drag events</h4><p>We will now add two methods to our class, which will be event listeners for our dragOver and dragLeave events. In these methods, we will simply change the background and opacity defined above, and prevent those events from bubbling up to our host component.</p><pre>//Dragover listener, when something is dragged over our host element</pre><pre>@HostListener(‘dragover’, [‘$event’]) onDragOver(evt) {<br>  evt.preventDefault();<br>  evt.stopPropagation();<br>  this.background = ‘#9ecbec’;<br>  this.opacity = ‘0.8’<br>}</pre><pre>//Dragleave listener, when something is dragged away from our host element</pre><pre>@HostListener(&#39;dragleave&#39;, [&#39;$event&#39;]) public onDragLeave(evt) {<br>  evt.preventDefault();<br>  evt.stopPropagation();<br>  this.background = &#39;#fff&#39;<br>  this.opacity = &#39;1&#39;<br>}</pre><h4><strong>Step 6: </strong>Our drop event</h4><p>Almost done with the directive! all that’s left is to add our last event listener, for when a file is actually dropped over our host DOM element. Let’s add the following method:</p><pre>@HostListener(&#39;drop&#39;, [&#39;$event&#39;]) public ondrop(evt) {<br>  evt.preventDefault();<br>  evt.stopPropagation();<br>  this.background = &#39;#f5fcff&#39;<br>  this.opacity = &#39;1&#39;<br>  let files = evt.dataTransfer.files;<br>  if (files.length &gt; 0) {<br>    this.onFileDropped.emit(files)<br>  }<br>}</pre><p>This one is a bit different. Apart from the similar bubbling prevention and style alterations, here we are checking if there are actually files that were dropped on our host DOM element, and if such is the case we emit our custom onFileDropped event that can be subscribed to from our component.</p><p>We have now completed our directive. here is the complete Class definition:</p><pre>import { <em>Directive</em>,<em>Output</em>, <em>EventEmitter</em>, <em>HostBinding</em>, <em>HostListener</em>, <em>HostBindingDecorator</em> } from &#39;@angular/core&#39;;<br><br>@Directive({<br>  selector: &#39;[appUpload]&#39;<br>})</pre><pre>export class UploadDirective {<br><br>  @Output() onFileDropped = new EventEmitter&lt;any&gt;();<br>  @HostBinding(&#39;style.background-color&#39;) public background = &#39;#fff&#39;;<br>  @HostBinding(&#39;style.opacity&#39;) public opacity = &#39;1&#39;;<br>  <br>  //Dragover listener, when something is dragged over our host element<br>  @HostListener(&#39;dragover&#39;, [&#39;$event&#39;]) onDragOver(evt) {<br>    evt.preventDefault();<br>    evt.stopPropagation();<br>    this.background = &#39;#9ecbec&#39;;<br>    this.opacity = &#39;0.8&#39;<br>  };<br><br>  //Dragleave listener, when something is dragged away from our host element<br>  @HostListener(&#39;dragleave&#39;, [&#39;$event&#39;]) public onDragLeave(evt) {<br>    evt.preventDefault();<br>    evt.stopPropagation();<br>    this.background = &#39;#fff&#39;<br>    this.opacity = &#39;1&#39;<br>  }<br><br>  @HostListener(&#39;drop&#39;, [&#39;$event&#39;]) public ondrop(evt) {<br>    evt.preventDefault();<br>    evt.stopPropagation();<br>    this.background = &#39;#f5fcff&#39;<br>    this.opacity = &#39;1&#39;<br>    let files = evt.dataTransfer.files;<br>    if (files.length &gt; 0) {<br>      this.onFileDropped.emit(files)<br>    }<br>  }<br><br>  constructor() { }<br><br>}</pre><h4><strong>Step 7: </strong>Using the directive</h4><p>Now that our directive has been implemented, we can include it in our component. It can be any component in your app, but for the purpose of this demo we will be using the main app component.</p><p>In our app.component.html file let’s add the following element:</p><pre>&lt;div appUpload (onFileDropped)=&quot;uploadFile(<strong><em>$event</em></strong>)&quot; &gt;Drop a file here&lt;/div&gt;</pre><p>Our final step will be to handle the onFileDropped event within our app.component.ts by defining the uploadFile method.</p><pre>uploadFile(evt){<br>  <em>// evt is an array of the file(s) dropped on our div. Here we&#39;re assuming only one file has been uploaded</em><br>  <br>  let payload = new <strong><em>FormData</em></strong>();<br>  payload.append(&#39;data&#39;, evt[0]);<br>  <em>// File can now be uploaded by doing an http post with the payload</em><br>}</pre><p>From there we can proceed with tweaking the UI as desired to fit our requirements :)</p><p>During my training sessions, one of my main objectives is to help demystify the implementation of common UI components to my trainees. It has been my observation that Junior devs tend to treat ready-made UI components as black boxes and demonstrating how they themselves could implement such a component from scratch helps them realize the realm of possibilities at their fingertips :)</p><p>I have also added some CSS to make the demo a bit more user friendly. As usual all the code for this demo can be found at: <a href="https://github.com/Bilkiss/angular-file-upload">Angular file upload</a>.</p><p>The UI for this demo can be found at <a href="https://angular-upload-file.herokuapp.com/">Angular upload file</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=91596ecb65bf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/creating-a-drag-and-drop-file-upload-component-using-angular-directives-91596ecb65bf">Creating a Drag and Drop File Upload Component Using Angular Directives</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Integrating Tailwind CSS with Angular]]></title>
            <link>https://medium.com/@bilkiss.dulloo/integrating-tailwind-css-with-angular-451273918133?source=rss-571616dbdfc9------2</link>
            <guid isPermaLink="false">https://medium.com/p/451273918133</guid>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[tailwind-css]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Bilkiss Dulloo]]></dc:creator>
            <pubDate>Sun, 05 Jul 2020 17:16:16 GMT</pubDate>
            <atom:updated>2020-09-04T13:18:24.905Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*1D5VCWWT27KZb29B6FNIXA.jpeg" /><figcaption>Integrating Tailwind CSS with Angular</figcaption></figure><p>I’ve recently heard some noise online about a new toy called Tailwind CSS. Well after playing around with Bootstrap, discovering Sass and overall messing around with preprocessors / CSS frameworks, how could I miss the chance to try a shiny new toy? :)</p><p>Meanwhile, I have been developing production web (and mobile) apps using Angular, so I told myself, the best way to try if Tailwind would fit in my existing workflow would be to try integrating it directly in there right? So that’s exactly what I did.</p><p>Let’s take a quick look at the main actors in our little experiment first.</p><h4>What is Tailwind CSS?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_6ooq0R60ba3UT5c-QVemA.png" /></figure><p>Well, given that I’m just getting started with Tailwind, you’d probably learn more about Tailwind on the official website (See <a href="https://tailwindcss.com/#what-is-tailwind">What is Tailwind</a> ), but if you want my quick shot at a description, Tailwind CSS is a minimalist utility first, highly customizable, low-level CSS framework. What does that mean? In short, Tailwind allows you to create beautiful custom UI elements without making any design choices for you.</p><p>Since this article is about integrating Tailwind with Angular, a more in depth description would be out of place here, but feel free to check the <a href="https://tailwindcss.com/">Official website</a> :)</p><h4>What is Angular:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6XnvCgNztBLHWk1R8ufkow.png" /></figure><p><strong>Angular</strong> is a platform and framework for building single-page client applications. <em>Angular</em> is written in TypeScript and… Wait, you actually don’t know Angular? Please check the official website: <a href="https://angular.io/">Angular framework</a></p><p>I’ve started working with the Angular framework since 2016, and haven’t looked back. Try it! You may come to love it too! 😜</p><p>Now let setup our first demo project. I am assuming that you already have the Angular cli installed here. (If not, please check out this guide to install the tooling: <a href="https://angular.io/guide/setup-local">Angular — Setting up the local environment and workspace</a> )</p><h4>Set up Angular project:</h4><p><strong>Step 1</strong>: Create Angular project</p><p>First we’ll begin by creating our skeleton project in which we’ll try to integrate Tailwind. We’ll call the project “angular-tailwind-demo”, because what’s more beautiful than a completely explicit name? :)</p><p>Run the following command in your console:</p><pre>ng new angular-tailwind-demo --style=scss</pre><p><strong>Step 2</strong>: Add Tailwind to the project</p><p>Next, once we have our generated project boilerplate, we’ll add the Tailwind package using npm.</p><pre>cd angular-tailwind-demo</pre><pre>npm install tailwindcss --save</pre><p><strong>Step 3</strong>: Initiate a Tailwind config</p><p>Ok, now we have everything we need to start our little experiment ^^. We’ll begin by initializing Tailwind.</p><pre>npx tailwindcss init</pre><p>The default <em>init</em> will create a minimal <em>tailwind.config.js</em> file and place it at the root folder of your project. This file will look something like the following:</p><pre>// tailwind.config.js</pre><pre>module.exports = {<br>  theme: {},<br>  variants: {},<br>  plugins: [],<br>}</pre><p>Our next step here will be to customize the generated config file to fit our needs.</p><p>Below is an example of a customized <em>tailwind.config.js</em></p><pre>// Example `tailwind.config.js` file</pre><pre>module.exports = {<br> important: true,<br> theme: {<br>  fontFamily: {<br>    display: [&#39;Gilroy&#39;, &#39;sans-serif&#39;],<br>    body: [&#39;Graphik&#39;, &#39;sans-serif&#39;],<br>  },<br>  extend: {<br>    colors: {<br>      cyan: &#39;#9cdbff&#39;,<br>    },<br>    margin: {<br>     &#39;96&#39;: &#39;24rem&#39;,<br>     &#39;128&#39;: &#39;32rem&#39;,<br>    },<br>   }<br> },<br> variants: {<br>  opacity: [&#39;responsive&#39;, &#39;hover&#39;]<br> }<br>}</pre><p>Every section of the config file is optional and only needs to specify what needs to change. For example the <em>tailwind.config.js</em> file above defined the font-family in the theme section, as well as the colors, margin and padding in the extend section. Any missing part will fallback to <a href="https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js">default configuration</a>.</p><p><strong>Step 4</strong>: Create a <em>tailwind-build.css</em> inside your src project folder and configure it as shown below:</p><pre>@tailwind preflight;<br>//Your custom components go here...</pre><pre>@tailwind utilities;<br>// Your custom utilities go here...</pre><p>According to the Tailwind official documentation, Preflight is a set of base styles for Tailwind projects that are designed to smooth over cross-browser inconsistencies and make it easier for you to work within the constraints of your design system.</p><p>Tailwind also provides a pretty comprehensive set of utility classes out of the box.</p><p><strong>Step 5</strong>: Add this script to your <em>package.json</em> file, inside the script block as follows:</p><pre>&quot;scripts&quot;: {<br>...<br>&quot;tailwind&quot;: &quot;./node_modules/.bin/tailwind build ./src/tailwind-build.css -c ./tailwind.config.js -o ./src/styles.css&quot;,<br>&quot;prestart&quot;: &quot;npm run tailwind&quot;,<br>}</pre><p>Next: in your angular.json file, in “architect”, “options”, “styles” add “src/styles.css”</p><pre>&quot;prefix&quot;: &quot;app&quot;,<br>&quot;architect&quot;: {<br>  &quot;build&quot;: {<br>    &quot;builder&quot;: &quot;@angular-devkit/build-angular:browser&quot;,<br>    &quot;options&quot;: {<br>      &quot;outputPath&quot;: &quot;dist/angular-tailwind-demo&quot;,<br>      &quot;index&quot;: &quot;src/index.html&quot;,<br>      &quot;main&quot;: &quot;src/main.ts&quot;,<br>      &quot;polyfills&quot;: &quot;src/polyfills.ts&quot;,<br>      &quot;tsConfig&quot;: &quot;tsconfig.app.json&quot;,<br>      &quot;aot&quot;: true,<br>      &quot;assets&quot;: [<br>        &quot;src/favicon.ico&quot;,<br>        &quot;src/assets&quot;<br>      ],<br>      &quot;styles&quot;: [<br>        &quot;src/styles.scss&quot;,<br>        &quot;src/styles.css&quot;<br>      ],<br>      &quot;scripts&quot;: []<br>    },<br>    ...<br>   }<br>  }</pre><p><strong>Step 6</strong>: Let’s create a card component by running the following in our terminal</p><pre>ng generate component card</pre><p>This command should generate a few files for our components. Of interest to us here is mostly the template <em>card.component.html</em> file.</p><p>Next let’s add our UI markup in the generated <em>card.component.html</em>.</p><pre>&lt;div class=&quot;flex flex-wrap mt-4 mb-4&quot;&gt;<br>  &lt;div class=&quot;w-full md:w-1/2 lg:w-1/3 pr-3&quot; <em>*ngFor</em>=&quot;let <strong><em>car </em></strong>of carFilterList&quot;&gt;<br>    &lt;div class=&quot;card&quot;&gt;<br>      &lt;img class=&quot;object-cover h-56 w-full&quot; [src]=&quot;<strong><em>car</em></strong>.car_image&quot; alt=&quot;{{<strong><em>car</em></strong>.name}}&quot;&gt;<br>      &lt;div class=&quot;px-6 py-4&quot;&gt;<br>       &lt;div class=&quot;font-bold text-gray-700 text-xl mb-2&quot;&gt;{{<strong><em>car</em></strong>.name}}&lt;/div&gt;<br>       &lt;p class=&quot;text-gray-700 text-base&quot;&gt;<br>        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus quia, nulla!<br>       &lt;/p&gt;<br>     &lt;/div&gt;<br>     &lt;div class=&quot;px-4 py-4 flex&quot;&gt;<br>      &lt;span class=&quot;inline-block cursor-pointer bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2&quot; [routerLink]=&quot;[<strong><em>car</em></strong>.car_url]&quot;&gt;<br>      &lt;i class=&quot;fa fa-angle-double-right&quot;&gt;&lt;/i&gt;<br>      View list<br>     &lt;/span&gt;<br>   &lt;/div&gt;<br>  &lt;/div&gt;<br> &lt;/div&gt;<br>&lt;/div&gt;</pre><p>We are using a few classes provided by Tailwind here. A few examples are:<br> — “w-full” class will make the element take a width of 100%.<br> — “md:w-1/2” to an element would set the element width of 50% at medium screen sizes and above.<br> — “text-gray-700” Control the text color of an element using the .text-{color} utilities.</p><p>These are Tailwind utility classes and will be processed by Tailwind to generate our CSS.</p><p>After creating the card component, let’s add some styling. In our <em>tailwind-build.css</em> let’s add some style under <em>@tailwind components;</em></p><p>For components like card and form elements, creating a template partial or JavaScript component can often feel too heavy compared to a simple CSS class.</p><p>In these situations, you can use Tailwind <em>@apply</em> directive to easily extract common utility patterns to CSS component classes.</p><p>Here’s what a .card class might look like using <em>@apply</em> to compose it from existing utilities:</p><pre>@tailwind components;</pre><pre>.card {<br>  @apply max-w-sm rounded overflow-hidden shadow mt-4<br>}</pre><pre>.card:hover {<br>  @apply shadow-lg<br>}</pre><p>Now just using the card class will apply all these utility classes to our element, thanks to <em>@apply</em></p><p><strong>Step 7</strong>: Let’s import our card component in our app.component.html by including this tag</p><pre>&lt;app-card&gt;&lt;/app-card&gt;</pre><p><strong>Step 8</strong>:<strong> </strong>We can now run the following code in the terminal to check if everything is working as expected</p><pre>ng serve --open</pre><p>If all goes well, this should open a browser window pointing to <a href="http://localhost:4200/">http://localhost:4200</a> which should display our card component.</p><figure><img alt="Card component" src="https://cdn-images-1.medium.com/max/745/1*qL1wLLd7Dnbp9ZKwRvdd5w.png" /></figure><p>Now we can use the card component anywhere in our application.</p><h4>Summary, or What have we learned so far?</h4><ul><li>We created a new Angular project and installed the Tailwind CSS package</li><li>We looked at the config files required for Tailwind to work</li><li>We created a card component with minimal lines of actual CSS.</li></ul><p>Playing around with Tailwind is pretty straightforward and the rapidly growing community around the framework looks friendly and ready to help in case of issues.</p><p>I will definitely look into it more, and maybe eventually use it in production :)</p><p>Do you have experience using Tailwind CSS in conjunction with a JavaScript framework? Let me know in the comment! :)</p><p>For a more in depth preview of what is possible with Tailwind, here’s a demo app extending the concept component explored in this article: <a href="https://github.com/Bilkiss/ng-tailwind-demo">Angular Tailwind demo</a>.</p><p>The UI for this demo can be found at <a href="https://marketplace-front-test.herokuapp.com/">Market place</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=451273918133" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>