<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shahar Kazaz</title>
    <description>The latest articles on DEV Community by Shahar Kazaz (@shaharkazaz).</description>
    <link>https://dev.to/shaharkazaz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F169508%2F4baf350c-928e-4a12-9839-a7050e556929.jpeg</url>
      <title>DEV Community: Shahar Kazaz</title>
      <link>https://dev.to/shaharkazaz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shaharkazaz"/>
    <language>en</language>
    <item>
      <title>Remove Redundant Subscriptions in Angular with @jsverse/letify</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Wed, 30 Oct 2024 15:58:49 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/remove-redundant-subscriptions-in-angular-with-jsverseletify-2pni</link>
      <guid>https://dev.to/shaharkazaz/remove-redundant-subscriptions-in-angular-with-jsverseletify-2pni</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60tn22yohsrs0el0kzcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60tn22yohsrs0el0kzcf.png" alt="Letify logo" width="800" height="551"&gt;&lt;/a&gt;&lt;br&gt;
In modern web applications, performance and maintainability are key.&lt;br&gt;
✨ Letify is here to help you remove redundant subscriptions in your Angular templates by automatically identifying these duplications and replacing them with &lt;code&gt;@let&lt;/code&gt; variable declarations.  &lt;/p&gt;
&lt;h3&gt;
  
  
  A Quick Reminder: The Async Pipe and Its Pitfall
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; pipe is a widely used feature in Angular for handling observables and promises in templates. However, it has a drawback: it creates a new subscription each time it's used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ (data$ | async).name }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ (data$ | async).description }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;data$ | async&lt;/code&gt; is used twice, leading to multiple subscriptions to the same observable. This can degrade performance, especially in large applications.&lt;/p&gt;

&lt;p&gt;Before Angular v18.1, solutions to this problem included capturing the value in an &lt;code&gt;ngIf&lt;/code&gt; statement or using third-party libraries like &lt;a href="https://github.com/rx-angular/rx-angular" rel="noopener noreferrer"&gt;@rx-angular/template&lt;/a&gt; with its &lt;code&gt;rxLet&lt;/code&gt; directive. &lt;/p&gt;

&lt;p&gt;With the &lt;a href="https://medium.com/r?url=https%3A%2F%2Fblog.angular.dev%2Fintroducing-let-in-angular-686f9f383f0f" rel="noopener noreferrer"&gt;introduction of &lt;code&gt;@let&lt;/code&gt;&lt;/a&gt; in Angular v18.1, you can now manage async data more efficiently by creating a single subscription and reusing it throughout your template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@let data = data$ | async;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ data.name }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ data.description }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, there's still the challenge of refactoring your existing codebase and keeping those redundant subscriptions away in the future. That's where &lt;code&gt;letify&lt;/code&gt; comes in!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;@jsverse/letify&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/jsverse/letify" rel="noopener noreferrer"&gt;&lt;code&gt;@jsverse/letify&lt;/code&gt;&lt;/a&gt; CLI tool helps developers automatically detect and optimize redundant &lt;code&gt;async&lt;/code&gt; pipe subscriptions in their templates. It scans your HTML files, identifies duplicate subscriptions, and replaces them with the &lt;code&gt;@let&lt;/code&gt; directive to enhance performance.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;letify&lt;/code&gt; is straightforward. Once installed, you can run it against your project files to generate a report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @jsverse/letify
npx letify &lt;span class="o"&gt;[&lt;/span&gt;analyze|fix] &lt;span class="s1"&gt;'src/app/**/*.html'&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analyze&lt;/strong&gt;: Scans your templates and highlights opportunities for refactoring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Automatically replaces occurrences where possible.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can even integrate &lt;code&gt;letify&lt;/code&gt; into your CI pipeline or Git hooks to catch these issues before code is committed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3oezmq7557n0kef4gq8b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3oezmq7557n0kef4gq8b.gif" alt="Letify in action" width="600" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Angular's new features continuously enhance app performance and readability. Because of asyncpopularity, duplicated subscriptions are common. letify is your Swiss army knife to easily tackle this issue and optimize your templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Join the ️@jsverse Community
&lt;/h3&gt;

&lt;p&gt;I'm excited to see how &lt;code&gt;letify&lt;/code&gt; can enhance your Angular apps! Be sure to check out the &lt;a href="https://github.com/jsverse/letify" rel="noopener noreferrer"&gt;&lt;code&gt;@jsverse/letify&lt;/code&gt;&lt;/a&gt; repository, give it a star, and follow the &lt;a href="https://github.com/jsverse" rel="noopener noreferrer"&gt;&lt;code&gt;jsverse organization&lt;/code&gt;&lt;/a&gt; for more updates and tools that will help you build better apps.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>performance</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Remove Redundant Subscriptions in Angular with @jsverse/letify</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Wed, 30 Oct 2024 15:58:49 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/remove-redundant-subscriptions-in-angular-with-jsverseletify-24c3</link>
      <guid>https://dev.to/shaharkazaz/remove-redundant-subscriptions-in-angular-with-jsverseletify-24c3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60tn22yohsrs0el0kzcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60tn22yohsrs0el0kzcf.png" alt="Letify logo" width="800" height="551"&gt;&lt;/a&gt;&lt;br&gt;
In modern web applications, performance and maintainability are key.&lt;br&gt;
✨ Letify is here to help you remove redundant subscriptions in your Angular templates by automatically identifying these duplications and replacing them with &lt;code&gt;@let&lt;/code&gt; variable declarations.  &lt;/p&gt;
&lt;h3&gt;
  
  
  A Quick Reminder: The Async Pipe and Its Pitfall
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; pipe is a widely used feature in Angular for handling observables and promises in templates. However, it has a drawback: it creates a new subscription each time it's used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ (data$ | async).name }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ (data$ | async).description }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;data$ | async&lt;/code&gt; is used twice, leading to multiple subscriptions to the same observable. This can degrade performance, especially in large applications.&lt;/p&gt;

&lt;p&gt;Before Angular v18.1, solutions to this problem included capturing the value in an &lt;code&gt;ngIf&lt;/code&gt; statement or using third-party libraries like &lt;a href="https://github.com/rx-angular/rx-angular" rel="noopener noreferrer"&gt;@rx-angular/template&lt;/a&gt; with its &lt;code&gt;rxLet&lt;/code&gt; directive. &lt;/p&gt;

&lt;p&gt;With the &lt;a href="https://medium.com/r?url=https%3A%2F%2Fblog.angular.dev%2Fintroducing-let-in-angular-686f9f383f0f" rel="noopener noreferrer"&gt;introduction of &lt;code&gt;@let&lt;/code&gt;&lt;/a&gt; in Angular v18.1, you can now manage async data more efficiently by creating a single subscription and reusing it throughout your template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@let data = data$ | async;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ data.name }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ data.description }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, there's still the challenge of refactoring your existing codebase and keeping those redundant subscriptions away in the future. That's where &lt;code&gt;letify&lt;/code&gt; comes in!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;@jsverse/letify&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/jsverse/letify" rel="noopener noreferrer"&gt;&lt;code&gt;@jsverse/letify&lt;/code&gt;&lt;/a&gt; CLI tool helps developers automatically detect and optimize redundant &lt;code&gt;async&lt;/code&gt; pipe subscriptions in their templates. It scans your HTML files, identifies duplicate subscriptions, and replaces them with the &lt;code&gt;@let&lt;/code&gt; directive to enhance performance.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;letify&lt;/code&gt; is straightforward. Once installed, you can run it against your project files to generate a report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @jsverse/letify
npx letify &lt;span class="o"&gt;[&lt;/span&gt;analyze|fix] &lt;span class="s1"&gt;'src/app/**/*.html'&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analyze&lt;/strong&gt;: Scans your templates and highlights opportunities for refactoring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Automatically replaces occurrences where possible.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can even integrate &lt;code&gt;letify&lt;/code&gt; into your CI pipeline or Git hooks to catch these issues before code is committed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3oezmq7557n0kef4gq8b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3oezmq7557n0kef4gq8b.gif" alt="Letify in action" width="600" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Angular's new features continuously enhance app performance and readability. Because of asyncpopularity, duplicated subscriptions are common. letify is your Swiss army knife to easily tackle this issue and optimize your templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Join the ️@jsverse Community
&lt;/h3&gt;

&lt;p&gt;I'm excited to see how &lt;code&gt;letify&lt;/code&gt; can enhance your Angular apps! Be sure to check out the &lt;a href="https://github.com/jsverse/letify" rel="noopener noreferrer"&gt;&lt;code&gt;@jsverse/letify&lt;/code&gt;&lt;/a&gt; repository, give it a star, and follow the &lt;a href="https://github.com/jsverse" rel="noopener noreferrer"&gt;&lt;code&gt;jsverse organization&lt;/code&gt;&lt;/a&gt; for more updates and tools that will help you build better apps.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>performance</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Thank you Faker. Now it’s Time to Move On.</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Mon, 24 Jan 2022 21:36:37 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/thank-you-faker-now-its-time-to-move-on-5cfi</link>
      <guid>https://dev.to/shaharkazaz/thank-you-faker-now-its-time-to-move-on-5cfi</guid>
      <description>&lt;p&gt;TL;DR — &lt;a href="https://github.com/ngneat/falso"&gt;Falso&lt;/a&gt; is a modern, tree-shakeable, well-documented replacement for Faker.js&lt;/p&gt;

&lt;p&gt;You probably know &lt;a href="https://www.theverge.com/2022/1/9/22874949/developer-corrupts-open-source-libraries-projects-affected"&gt;what happened&lt;/a&gt; to Faker.js around two weeks ago.&lt;/p&gt;

&lt;p&gt;In collaboration with &lt;a href="https://twitter.com/NetanelBasal"&gt;Netanel Basal&lt;/a&gt;, I created a new mock data generator lib to provide a quick, suitable replacement for those relying on Faker (including us).&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet Falso 🎩
&lt;/h2&gt;

&lt;p&gt;✅ 160+ Functions ( at the time of writing)&lt;br&gt;
✅ Tree Shakable&lt;br&gt;
✅ Fully Typed&lt;br&gt;
✅ Entity Functions&lt;br&gt;
✅ Well documented with live previews&lt;br&gt;
✅ Single and Array Results&lt;/p&gt;

&lt;p&gt;There was a lot of community effort put into building this library. In just two weeks, we accomplished:&lt;/p&gt;

&lt;p&gt;✨ A whopping 1.6k Github Stars&lt;br&gt;
💪 59 Merged pull requests&lt;br&gt;
🎁 58 New Features&lt;/p&gt;

&lt;p&gt;I want to thank everyone who took part in this, you rock!&lt;/p&gt;

&lt;p&gt;Give Falso a try and let me know what you think 🌟&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ngneat"&gt;
        ngneat
      &lt;/a&gt; / &lt;a href="https://github.com/ngneat/falso"&gt;
        falso
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      All the Fake Data for All Your Real Needs 🙂
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
 &lt;a rel="noopener noreferrer" href="https://github.com/ngneat/falsologo.png"&gt;&lt;img width="20%" height="20%" src="https://res.cloudinary.com/practicaldev/image/fetch/s--GzvRlYqa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/ngneat/falsologo.png"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All the Fake Data for All Your Real Needs 🙂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create massive amounts of fake data in the browser and NodeJS. Tree Shakeable &amp;amp; Fully Typed.&lt;/p&gt;






&lt;p&gt;&lt;a href="https://github.com/ngneat/falso/actions/workflows/ci.yml"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oahaWFMR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/ngneat/falso/actions/workflows/ci.yml/badge.svg" alt="@ngneat/falso"&gt;&lt;/a&gt;
&lt;a href="https://github.com/ngneat/falso"&gt;&lt;img src="https://camo.githubusercontent.com/f30b8934c0ea587a97cade3e40fca021c63224940aeb2fd85bf4bbf3830481fa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6d6d6974697a656e2d667269656e646c792d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265" alt="commitizen"&gt;&lt;/a&gt;
&lt;a href="https://github.com/ngneat/falso"&gt;&lt;img src="https://camo.githubusercontent.com/0ff11ed110cfa69f703ef0dcca3cee6141c0a8ef465e8237221ae245de3deb3d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265" alt="PRs"&gt;&lt;/a&gt;
&lt;a href="https://github.com/ngneat/falso"&gt;&lt;img src="https://camo.githubusercontent.com/3101ce90ebae5b8a8d598ba308c065515bccccf2574119cbf1ed41c0b110c745/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64656f662d636f6e647563742d6666363962342e7376673f7374796c653d666c61742d737175617265" alt="coc-badge"&gt;&lt;/a&gt;
&lt;a href="https://github.com/semantic-release/semantic-release"&gt;&lt;img src="https://camo.githubusercontent.com/fc8926ab5e0230b451396bf44d5583b0efe708645dad6d6bd39e240e77822dc6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2532302532302546302539462539332541362546302539462539412538302d73656d616e7469632d2d72656c656173652d65353037392e7376673f7374796c653d666c61742d737175617265" alt="semantic-release"&gt;&lt;/a&gt;
&lt;a href="https://github.com/prettier/prettier"&gt;&lt;img src="https://camo.githubusercontent.com/7d409ef1314ca87ee7ff07a9d0de0bd9e86677726c34b03dca757f7ce6277dbc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374796c65645f776974682d70726574746965722d6666363962342e7376673f7374796c653d666c61742d737175617265" alt="styled with prettier"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✅  164 Functions&lt;br&gt;
✅  Tree Shakable&lt;br&gt;
✅  Fully Typed&lt;br&gt;
✅  Entity Functions&lt;br&gt;
✅  Single and Array Result&lt;/p&gt;
&lt;p&gt;🤓 Learn about it on the &lt;a href="https://ngneat.github.io/falso/" rel="nofollow"&gt;docs site&lt;/a&gt; &lt;br&gt;
🔥 Run it on &lt;a href="https://stackblitz.com/edit/typescript-pjao1u?file=index.ts" rel="nofollow"&gt;Stackblitz&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;div class="snippet-clipboard-content position-relative overflow-auto"&gt;&lt;pre&gt;&lt;code&gt;npm i @ngneat/falso
yarn add @ngneat/falso
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
Usage&lt;/h3&gt;
&lt;div class="highlight highlight-source-ts position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;randEmail&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;randFullName&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'@ngneat/falso'&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;user&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;email&lt;/span&gt;: &lt;span class="pl-en"&gt;randEmail&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;name&lt;/span&gt;: &lt;span class="pl-en"&gt;randFullName&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;emails&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;randEmail&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;length&lt;/span&gt;: &lt;span class="pl-c1"&gt;10&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
Setting a Randomness Seed&lt;/h3&gt;
&lt;p&gt;You can set your own seed if you want consistent results:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;rand&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;seed&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'@ngneat/falso'&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-en"&gt;seed&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'some-constant-seed'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// Always returns 2&lt;/span&gt;
&lt;span class="pl-en"&gt;rand&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-c1"&gt;1&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;2&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;3&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;4&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;5&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ngneat/falso"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;See the &lt;a href="https://ngneat.github.io/falso/"&gt;docs&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8bCk4dgM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxvkom80pn9k2ovfj7ej.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8bCk4dgM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxvkom80pn9k2ovfj7ej.gif" alt="The [Falso docs](https://ngneat.github.io/falso/) and live preview" width="880" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’re just getting started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;🌐 Locale support&lt;br&gt;
💪 More Generators&lt;br&gt;
🎯 Improve data accuracy&lt;/p&gt;

&lt;p&gt;You are welcome to &lt;a href="https://github.com/ngneat/falso/blob/main/CONTRIBUTING.md"&gt;contribute&lt;/a&gt;! Let us build the next generation of mock data together!&lt;/p&gt;

&lt;p&gt;For those looking to contribute for the first time to an open-source, Falso is an excellent choice!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>angular</category>
      <category>react</category>
      <category>vue</category>
    </item>
    <item>
      <title>Introducing Variabless - JS &amp; CSS A Match Made in Heaven</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Sun, 01 Aug 2021 11:36:28 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/introducing-variabless-js-css-a-match-made-in-heaven-3n1g</link>
      <guid>https://dev.to/shaharkazaz/introducing-variabless-js-css-a-match-made-in-heaven-3n1g</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frp9m4f662tvuur47704w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frp9m4f662tvuur47704w.png" alt="Variabless logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;center&gt;Thanks goes to &lt;a href="https://www.rubideri.com/" rel="noopener noreferrer"&gt;Rubi Deri&lt;/a&gt; for this awesome logo 🎉&lt;/center&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We have all been there. We start a new project, create our theme using CSS variabless, and then the worst; We add third-party libraries that expose a JS API to alter their style. What do we do now? How do we share our lovely theme with those libraries?&lt;/p&gt;

&lt;p&gt;No worries. We got you covered! Let's see the magic of Variabless:&lt;/p&gt;

&lt;h1&gt;
  
  
  One Single Source of Truth
&lt;/h1&gt;

&lt;p&gt;Instead of managing two sets of theme definitions, one in CSS and one in JS, Variabless will convert your Variabless definitions file to CSS variables or properties, allowing you to use those values in JS and CSS files:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1500%2F1%2AJXhMe8jzxQmPWtHA4-UF2g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1500%2F1%2AJXhMe8jzxQmPWtHA4-UF2g.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;center&gt;You can try it live in the &lt;a href="https://ngneat.github.io/variabless/" rel="noopener noreferrer"&gt;Variabless playground&lt;/a&gt;
&lt;/center&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we can pass our theme to our 3rd party lib and use it anywhere in our JS code:&lt;/p&gt;


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


&lt;p&gt;Or use it in our CSS files just like any other variable:&lt;/p&gt;


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


&lt;h1&gt;
  
  
  Styles Generator
&lt;/h1&gt;

&lt;p&gt;Variabless allows you to easily create utility classes or any selector you wish referencing the variable’s value. For example, let’s add font-size classes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2000%2F1%2AURagIn_Em4Zsld8NnL7t-A.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2000%2F1%2AURagIn_Em4Zsld8NnL7t-A.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As easy as it gets 🔥&lt;/p&gt;

&lt;h1&gt;
  
  
  Use the Power of JS
&lt;/h1&gt;

&lt;p&gt;Variabless uses a JS config file. It means you can leverage JavaScript to prevent repetitions and keep your config clean 🧼&lt;/p&gt;

&lt;p&gt;Let’s take a look at the following configuration. We want to define several font sizes:&lt;/p&gt;


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


&lt;p&gt;Using JS we can easily replace that with a cleaner more scalable option:&lt;/p&gt;


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





&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;: since Variabless uses JS and CSS files you get your IDE’s autocompletion 🎉&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Install the Variabless package via yarn or npm by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @ngneat/variabless
yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; @ngneat/variabless
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;There are two ways you can use Variabless via CLI or Webpack plugin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The recommended approach is with the Webpack plugin&lt;/strong&gt; since it provides you with the ability to add/remove variables during development, while you’re working on the project and see the results as you make the changes.&lt;/p&gt;

&lt;p&gt;All you have to do is add the &lt;code&gt;VariablessWebpackPlugin&lt;/code&gt; to your plugins list:&lt;/p&gt;


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



&lt;p&gt;You can find information on using it via CLI &lt;a href="https://github.com/ngneat/variabless#cli" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Include the generated file by Variabless in your styles:&lt;/p&gt;


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


&lt;p&gt;Add the generated file to your &lt;code&gt;.gitignore&lt;/code&gt; file, there is no need to track it.&lt;/p&gt;




&lt;p&gt;For more information visit the variabless repo, docs and playground:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jsverse" rel="noopener noreferrer"&gt;
        jsverse
      &lt;/a&gt; / &lt;a href="https://github.com/jsverse/variabless" rel="noopener noreferrer"&gt;
        variabless
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      JS &amp;amp; CSS - A Match Made in Heaven 💎
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;br&gt;
&lt;p&gt;
 &lt;a rel="noopener noreferrer" href="https://github.com/jsverse/variabless./logo.svg"&gt;&lt;img width="70%" height="50%" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fjsverse%2Fvariabless.%2Flogo.svg"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;
    &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b44890358b62ed506ee63de3ac148c8bd0e52f67d932864455d67ada837638c4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6d6d6974697a656e2d667269656e646c792d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/b44890358b62ed506ee63de3ac148c8bd0e52f67d932864455d67ada837638c4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6d6d6974697a656e2d667269656e646c792d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265"&gt;&lt;/a&gt;
    &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/88482ebfc5e3e4f2d667148ab6a3eb55948789f1dba71dfa0eb2e05afe02958c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/88482ebfc5e3e4f2d667148ab6a3eb55948789f1dba71dfa0eb2e05afe02958c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265"&gt;&lt;/a&gt;
    &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/bffa4a9dcb27638820fdf23890dce0ffcebff3fe984e9fb481ba5c699c8370bc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64656f662d636f6e647563742d6666363962342e7376673f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/bffa4a9dcb27638820fdf23890dce0ffcebff3fe984e9fb481ba5c699c8370bc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64656f662d636f6e647563742d6666363962342e7376673f7374796c653d666c61742d737175617265"&gt;&lt;/a&gt;
    &lt;a href="https://github.com/semantic-release/semantic-release" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/85458d55a3d3dc7d9a3840c71ce699cb31e39fa2cb4345be6d3934421b021285/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2532302532302546302539462539332541362546302539462539412538302d73656d616e7469632d2d72656c656173652d65353037392e7376673f7374796c653d666c61742d737175617265"&gt;&lt;/a&gt;
    &lt;a href="https://github.com/prettier/prettier" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d648f53a465339837ee2170355a3f89faef0835dab36c3e5e364f7dd9be02360/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374796c65645f776974682d70726574746965722d6666363962342e7376673f7374796c653d666c61742d737175617265"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Variabless allows you to manage application-wide CSS styles and variables in a single source of truth manner
Variabless will convert a JS definitions file to CSS variables or classes, allowing you to use those values in JS and CSS files.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Variabless?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Since introducing CSS variables, supporting themes in your app, and customizing styles became much more convenient
While developing several apps, we noticed a reoccurring need. We need to refer to the theme and variables in our TS files for various reasons. For example, we are passing colors and fonts to libraries such as highcharts and grid.&lt;/p&gt;
&lt;p&gt;At that point, it was either managing two sets of theme definitions, one in CSS and one in TS, or found a solution to centralize our theme and make it accessible for both; thus, Variabless was born.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;✅  Convert JS to CSS variables&lt;br&gt;
✅  Single Source of Styling Across the App…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jsverse/variabless" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This library was created by myself and &lt;a class="mentioned-user" href="https://dev.to/netanelbasal"&gt;@netanelbasal&lt;/a&gt; with ❤️&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Writing Custom Git Hooks With NodeJS</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Fri, 17 Jan 2020 13:54:39 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/writing-custom-git-hooks-with-nodejs-3f8b</link>
      <guid>https://dev.to/shaharkazaz/writing-custom-git-hooks-with-nodejs-3f8b</guid>
      <description>&lt;p&gt;Git hooks are a useful tool, especially when working in large teams.&lt;br&gt;
They can help us apply code style and linting standards to our staged files.  &lt;/p&gt;

&lt;p&gt;In the article, we'll write a few powerful Javascript git hooks that will help us manage our codebase and have a smoother developing experience.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Running The Script 
&lt;/h3&gt;

&lt;p&gt;We are going to run our hooks with the help of Husky 🐶.&lt;br&gt;
After we &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fgithub.com%2Ftypicode%2Fhusky%23install"&gt;installed Husky&lt;/a&gt; the next thing we need to do is run our node script.&lt;br&gt;
Let's add our script to the package.json scripts section, and use husky to call it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks:pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ./hooks/pre-commit.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks:pre-push"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ./hooks/pre-push.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run hooks:pre-commit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pre-push"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run hooks:pre-push"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That's pretty much it, now let's see some useful implementations of &lt;br&gt;
&lt;code&gt;pre-commit&lt;/code&gt; and &lt;code&gt;pre-push&lt;/code&gt; hooks.  &lt;/p&gt;
&lt;h4&gt;
  
  
  Exec.js 
&lt;/h4&gt;

&lt;p&gt;I created an &lt;code&gt;exec.js&lt;/code&gt; helper function for my hooks scripts, that wraps &lt;code&gt;shelljs&lt;/code&gt;'s &lt;code&gt;exec&lt;/code&gt; function. &lt;br&gt;
The &lt;code&gt;exec&lt;/code&gt; function spawns a shell then executes a given command within that shell:&lt;/p&gt;


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



&lt;h3&gt;
  
  
  Pre-Commit 📦
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Branch Names Convention 
&lt;/h4&gt;

&lt;p&gt;Allow to create only branches that have one of the following prefixes: &lt;code&gt;feature|fix|hotfix|chore|tests|automation&lt;/code&gt;&lt;/p&gt;


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


&lt;h4&gt;
  
  
  2. Forbidden Tokens ✋
&lt;/h4&gt;

&lt;p&gt;Who hasn't forgotten to remove a &lt;code&gt;debugger&lt;/code&gt;? or an &lt;code&gt;fdescribe&lt;/code&gt; in a test? no more!&lt;/p&gt;


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


&lt;h3&gt;
  
  
  Pre-Push 🚀
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Auto Sync Master
&lt;/h4&gt;

&lt;p&gt;We noticed that developers often forget to update their branches regularly from the remote.  &lt;/p&gt;

&lt;p&gt;This is a simple but important hook that updates your local branch from the remote &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;


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


&lt;h4&gt;
  
  
  2. Forbidden Branches ✋
&lt;/h4&gt;

&lt;p&gt;There are brunches that we don't want their commits ending up in master&lt;br&gt;
such as a &lt;code&gt;staging&lt;/code&gt; branch.  &lt;/p&gt;

&lt;p&gt;We'll make a commit in these branches that will act as a "flag" 🚩.&lt;br&gt;
Before pushing to the remote we will verify that this commit isn't part of the  branch being pushed (we will obviously remove this code in the &lt;code&gt;staging&lt;/code&gt; branch).&lt;/p&gt;


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


&lt;h3&gt;
  
  
  Takeaways 
&lt;/h3&gt;

&lt;p&gt;We saw some useful examples for using git hooks, and how easy you can use Husky and NodeJS to apply policies and prevent bad commits.  &lt;/p&gt;

&lt;p&gt;Now you can customize these hooks in the best way that suits your project 🥳&lt;/p&gt;




&lt;h3&gt;
  
  
  Have You Tried Transloco Yet? 🌐
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ng-neat&lt;/code&gt; introduces &lt;strong&gt;Transloco&lt;/strong&gt;, the internationalization (i18n) library for Angular. It allows you to define translations for your content in different languages and switch between them easily in runtime.  &lt;/p&gt;

&lt;p&gt;It exposes a rich API to manage translations efficiently and cleanly. It provides multiple plugins that will improve your development experience.&lt;br&gt;
We/I highly recommend you read more about it and &lt;a href="https://github.com/ngneat/transloco"&gt;check it out&lt;/a&gt;!&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing Transloco: Angular Internationalization Done Right
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/introducing-transloco-angular-internationalization-done-right-54710337630c"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TzQYv_pn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0byy9oicu3el19il9bx2.png" alt="🚀 Introducing Transloco: Angular Internationalization Done Right"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Translation Files Validation in Angular with Transloco And Husky
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/shaharkazaz/translation-files-validation-in-angular-with-transloco-and-husky-4oc5"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UzKo6Q9s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fijkr5zgi3dx7u0rldry.png" alt="Translation Files Validation in Angular with Transloco And Husky"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy Load Translation Files In Angular Using Transloco
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/@shahar.kazaz/lazy-load-translation-files-in-angular-using-transloco-2d3afed116ce"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SwexzsDu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qrbtvmni72l4jx39rymo.jpg" alt="Lazy Load Translation Files In Angular Using Transloco"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>git</category>
      <category>node</category>
    </item>
    <item>
      <title>Translation Files Validation in Angular with Transloco And Husky</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Tue, 15 Oct 2019 05:39:48 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/translation-files-validation-in-angular-with-transloco-and-husky-4oc5</link>
      <guid>https://dev.to/shaharkazaz/translation-files-validation-in-angular-with-transloco-and-husky-4oc5</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://medium.com/@shahar.kazaz/translation-files-validation-in-angular-with-transloco-e6ba02467f33"&gt;shahar.kazaz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When working on an enterprise application and with multiple teams, it’s often the case where we have merge conflicts with one of the translation files.&lt;/p&gt;

&lt;p&gt;In this case, we can accidentally break the file by forgetting an extra comma, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "key": "",
  "keyTwo": "", &amp;lt;====
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which leads to an invalid JSON. In most cases, the developer doesn’t notice this change and pushes the code to production or staging environments, and brokes that app.&lt;/p&gt;

&lt;p&gt;Here in Transloco, we take such things seriously, and to prevent this, we created a linter that will verify the translation files before they pushed.&lt;/p&gt;

&lt;p&gt;In addition to that, it will also check that it does not contain duplicate keys.&lt;br&gt;
Let’s see how we use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up husky and &lt;a href="https://github.com/okonet/lint-staged#examples"&gt;lint-staged&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm i @ngneat/transloco-validator --save-dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Update your &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lint-staged"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"src/assets/i18n/*.json"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"transloco-validator"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will make sure no one accidentally pushes an invalid translation file.&lt;/p&gt;

&lt;p&gt;If you liked this post, please 👏🏻 and share it!&lt;/p&gt;




&lt;p&gt;Here is some more great content about Transloco:&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Transloco: Angular Internationalization Done Right
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/introducing-transloco-angular-internationalization-done-right-54710337630c"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TzQYv_pn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0byy9oicu3el19il9bx2.png" alt="🚀 Introducing Transloco: Angular Internationalization Done Right"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy Load Translation Files In Angular Using Transloco
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/@shahar.kazaz/lazy-load-translation-files-in-angular-using-transloco-2d3afed116ce"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SwexzsDu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qrbtvmni72l4jx39rymo.jpg" alt="Lazy Load Translation Files In Angular Using Transloco"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Help the Translator by Using Transloco: The internationalization (i18n) library for Angular
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/@shahar.kazaz/help-the-translator-by-using-transloco-the-internationalization-i18n-library-for-angular-831c3c513ee4"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PDpooOB8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bor4py6tbht5que5lj5q.jpeg" alt="Help the Translator by Using Transloco: The internationalization (i18n) library for Angular"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>translation</category>
      <category>husky</category>
      <category>validation</category>
    </item>
    <item>
      <title>Lazy Load Translation Files In Angular Using Transloco</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Fri, 11 Oct 2019 07:08:34 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/lazy-load-translation-files-in-angular-using-transloco-41je</link>
      <guid>https://dev.to/shaharkazaz/lazy-load-translation-files-in-angular-using-transloco-41je</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://medium.com/@shahar.kazaz/lazy-load-translation-files-in-angular-using-transloco-2d3afed116ce"&gt;shahar.kazaz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will learn how we can use the internationalization library for Angular Transloco to lazy load translation files in our Angular application. There are two advantages to this approach. First, we make our initial bundle smaller, which will improve the application load time. Second, we are less exposed to merge conflicts.&lt;/p&gt;

&lt;p&gt;Let's see how easy it is to do it with Transloco 💪&lt;/p&gt;

&lt;p&gt;Let's say we have a user profile page. We want to create separate translation files for this page and load them only when the user navigates there. &lt;/p&gt;

&lt;p&gt;First, we need to create a user-profile folder (or whatever name you choose); In it, we create a translation file for each language we want to support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├─ i18n/
   ├─ en.json
   ├─ es.json
   ├─ profile-page/
      ├─ en.json
      ├─ es.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In each file will add only the relevant translations for this page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User Profile"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's continue and create the UserProfile module and routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserProfileComponent&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UserProfileComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TRANSLOCO_SCOPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouterModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;TranslocoModule&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;UserProfileModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Adding the &lt;code&gt;TRANSLOCO_SCOPE&lt;/code&gt; to the providers instruct Transloco load the corresponding scope based on the active language and merge it under the scope namespace into the active language translation object.&lt;/p&gt;

&lt;p&gt;For example, if the active language is en, it will load the &lt;code&gt;user-profile/en.json&lt;/code&gt; file, and will set the translation to be the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  header: '',
  login: '',
  userProfile: {
    title: 'User Profile'
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can access each one of the user profile keys by using the &lt;code&gt;userProfile&lt;/code&gt; namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*transloco=&lt;/span&gt;&lt;span class="s"&gt;"let t"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   {{ t('userProfile.title') }}
   {{ t('title') }}
&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By default, the namespace will be the scope name (camel-cased), but we can override it in two ways:&lt;/p&gt;

&lt;p&gt;By using the &lt;code&gt;config.scopeMapping&lt;/code&gt; config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  provide: TRANSLOCO_CONFIG,
   useValue: {
    defaultLang: 'en',
    scopeMapping: {
      'user-profile': 'profile'
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By providing a custom alias name in the module/component scope provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  provide: TRANSLOCO_SCOPE,
  useValue: { scope: 'user-profile', alias: 'profile' }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can access it through a custom name we provided instead of the original scope name (profile in our case):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*transloco=&lt;/span&gt;&lt;span class="s"&gt;"let t"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   {{ t('profile.title') }}
   {{ t('title') }}
&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;Here is some more great content about Transloco:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/introducing-transloco-angular-internationalization-done-right-54710337630c"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TzQYv_pn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0byy9oicu3el19il9bx2.png" alt="🚀 Introducing Transloco: Angular Internationalization Done Right"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/good-things-come-to-those-who-wait-whats-new-in-transloco-5dadf886b485"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lgZ2n2xw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0o19r97lw5jlti15nryp.png" alt="🎉 Good Things Come to Those Who Wait: What’s new in Transloco"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@shahar.kazaz/creating-search-engine-friendly-internationalized-apps-with-angular-universal-and-transloco-ab9583cfb5ac"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xdsg31lO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/cv1393qstlvo16qgk81x.jpg" alt="Creating Search Engine-Friendly Internationalized Apps with Angular Universal and Transloco 🌐"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>internationalization</category>
      <category>translate</category>
      <category>optimization</category>
    </item>
    <item>
      <title>Help the Translator by Using Transloco: The internationalization (i18n) library for Angular</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Sun, 15 Sep 2019 10:48:29 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/help-the-translator-by-using-transloco-the-internationalization-i18n-library-for-angular-562j</link>
      <guid>https://dev.to/shaharkazaz/help-the-translator-by-using-transloco-the-internationalization-i18n-library-for-angular-562j</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://medium.com/@shahar.kazaz/help-the-translator-by-using-transloco-the-internationalization-i18n-library-for-angular-831c3c513ee4" rel="noopener noreferrer"&gt;shahar.kazaz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are times where we need to help the translator with a description and meaning. To translate a text message accurately, the translator may need additional information or context.&lt;/p&gt;

&lt;p&gt;Let's take for example the following translation key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"book"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Book"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is this a "book" or to "book" something? We need to communicate to our translators the translation context.&lt;/p&gt;

&lt;p&gt;Let's learn how we can use Transloco the internationalization (i18n) library for Angular in order to provide the translators with these type of comments.&lt;/p&gt;

&lt;p&gt;For each translation key that requires a description, we can add a companion key post-fixed with &lt;code&gt;.comment&lt;/code&gt;, as shown in the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"book"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Book"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"book.comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"we mean a reading book"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, We don't want these keys to get into our final bundle, so we can remove them using an official transloco library when building the production environment.&lt;/p&gt;

&lt;p&gt;First, we need to install the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @ngneat/transloco-remove-comments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we need to add to the &lt;code&gt;package.json&lt;/code&gt; the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"remove-comments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"transloco-remove-comments dist/appName/assets/i18n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build:prod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ng build --prod &amp;amp;&amp;amp; npm run remove-comments"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we build the production environment, the library will take care of removing these keys from the translation files specified in the path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Once again, Transloco has made our life more comfortable.&lt;/strong&gt; Cheers! 🍻&lt;/p&gt;




&lt;p&gt;Here is some more great content about Transloco:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/introducing-transloco-angular-internationalization-done-right-54710337630c" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0byy9oicu3el19il9bx2.png" alt="🚀 Introducing Transloco: Angular Internationalization Done Right"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/good-things-come-to-those-who-wait-whats-new-in-transloco-5dadf886b485" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0o19r97lw5jlti15nryp.png" alt="🎉 Good Things Come to Those Who Wait: What’s new in Transloco"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@shahar.kazaz/creating-search-engine-friendly-internationalized-apps-with-angular-universal-and-transloco-ab9583cfb5ac" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcv1393qstlvo16qgk81x.jpg" alt="Creating Search Engine-Friendly Internationalized Apps with Angular Universal and Transloco 🌐"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>internationalization</category>
      <category>translate</category>
      <category>translators</category>
    </item>
    <item>
      <title>Creating Search Engine-friendly Internationalized Apps with Angular Universal and Transloco 🌐</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Fri, 13 Sep 2019 09:08:06 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/creating-search-engine-friendly-internationalized-apps-with-angular-universal-and-transloco-m02</link>
      <guid>https://dev.to/shaharkazaz/creating-search-engine-friendly-internationalized-apps-with-angular-universal-and-transloco-m02</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://medium.com/@shahar.kazaz/creating-search-engine-friendly-internationalized-apps-with-angular-universal-and-transloco-ab9583cfb5ac" rel="noopener noreferrer"&gt;shahar.kazaz&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In this article, I will show you how easily we can add internalization (i18n) support to Angular SSR using the next generation Angular internalization library Transloco. Let's get started.&lt;/p&gt;

&lt;p&gt;First, let's create a brand new Angular CLI project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @angular/cli new transloco-ssr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, add SSR support by using &lt;code&gt;@nguniversal/express-engine&lt;/code&gt; schematics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @nguniversal/express-engine &lt;span class="nt"&gt;--clientProject&lt;/span&gt; &amp;lt;PROJECT-NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add Transloco to your project by using schematics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @ngneat/transloco
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose your supported languages, and answer &lt;code&gt;Yes&lt;/code&gt; for the SSR question. Now you can see that it created the translation files, the loader, and added everyhing it needs to the &lt;code&gt;AppModule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When using Angular SSR, we need to change our loader base path to be absolute instead of relative, for it to work. This is already done for you.&lt;/p&gt;

&lt;p&gt;The only thing you need to do is modify the new &lt;code&gt;baseUrl&lt;/code&gt; property in each one of the &lt;code&gt;environment&lt;/code&gt; files based on your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;====&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// environment.prod.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;====&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's add a new key to our translation files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Angular SSR with Transloco english"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let's use it in our template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;transloco&lt;/span&gt; &lt;span class="na"&gt;let-t&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ t.title }}
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's build our application for production using the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build:ssr
npm run serve:ssr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser and navigate to &lt;code&gt;http://localhost:4000&lt;/code&gt; and Viola! We did it!&lt;/p&gt;

&lt;p&gt;Let's see the source HTML file:&lt;br&gt;
image&lt;/p&gt;

&lt;p&gt;We have got a working application with SSR and internalization (i18n) support in 5 minutes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;We can use the &lt;code&gt;accept-language&lt;/code&gt; header to set the preferred user language automatically. The Accept-Language request HTTP header advertises which languages the client can understand, and which locale variant is preferred.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Optional&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;REQUEST&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nguniversal/express-engine/tokens&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TranslocoService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ngneat/transloco&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;REQUEST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TranslocoService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setActiveLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accept-language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;accept-language&lt;/code&gt; headers return the following string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  'accept-language': 'en-US,en;q=0.9,he;q=0.8,ru;q=0.7,fr;q=0.6,pt;q=0.5',
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to extract the language and set it as active.&lt;/p&gt;




&lt;p&gt;Here is some more great content about Transloco:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/introducing-transloco-angular-internationalization-done-right-54710337630c" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0byy9oicu3el19il9bx2.png" alt="🚀 Introducing Transloco: Angular Internationalization Done Right"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netbasal.com/good-things-come-to-those-who-wait-whats-new-in-transloco-5dadf886b485" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0o19r97lw5jlti15nryp.png" alt="🎉 Good Things Come to Those Who Wait: What’s new in Transloco"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>internationalization</category>
      <category>translate</category>
      <category>ssr</category>
    </item>
    <item>
      <title>Server Side Pagination Made Easy with Akita and Angular</title>
      <dc:creator>Shahar Kazaz</dc:creator>
      <pubDate>Mon, 20 May 2019 08:55:34 +0000</pubDate>
      <link>https://dev.to/shaharkazaz/server-side-pagination-made-easy-with-akita-and-angular-26b</link>
      <guid>https://dev.to/shaharkazaz/server-side-pagination-made-easy-with-akita-and-angular-26b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When developing applications, we often need to deal with large data-sets. Imagine a scenario where we have one million records in the database, and we require to show it on a web page.&lt;/p&gt;

&lt;p&gt;We generally want to avoid sending all the data at once. The reasons for that are 1) We want a faster initial page load. 2) We don’t want to bloat the user’s machine memory.&lt;/p&gt;

&lt;p&gt;Instead, server-side paging is used, where the server sends just a single page at a time.&lt;/p&gt;

&lt;p&gt;In addition to that, we also want to cache pages that already have been fetched, to spare the need for an additional request. To save you the hassle and help you manage this whole thing, we created the PaginatorPlugin.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Paginator Plugin
&lt;/h2&gt;

&lt;p&gt;The Paginator API provides two useful features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Caching of pages which have already been fetched.&lt;/li&gt;
&lt;li&gt;Pagination functionally, which gives you all the things you need to manage pagination in the application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the plugin in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1ynmyurgmym0l3sx4hdm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1ynmyurgmym0l3sx4hdm.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s learn how to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Scaffold
&lt;/h2&gt;

&lt;p&gt;We need to maintain a collection of contacts, so we’ll use an &lt;code&gt;EntityStore&lt;/code&gt;. You can think of an entity store as a table in a database, where each table represents a flat collection of entities.&lt;/p&gt;

&lt;p&gt;Let’s create a contacts table, i.e. an &lt;code&gt;EntityStore&lt;/code&gt; managing a &lt;code&gt;Contact&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** contacts.store.ts */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ContactsState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;EntityState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;StoreConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contacts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContactsStore&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;EntityStore&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ContactsState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** contacts.query.ts */&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContactsQuery&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;QueryEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ContactsState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContactsStore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** contacts.model.ts */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@datorama/akita&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Contact&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We created the basic building blocks of Akita. Now, let’s create the &lt;code&gt;ContactsService&lt;/code&gt; which is responsible for fetching the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** contacts.service.ts  */&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContactsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PaginationResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getContacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getContact&lt;/code&gt; function is a mock implementation which returns the required server data with a one-second delay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Pagination:
&lt;/h2&gt;

&lt;p&gt;First, we need to create a new provider for our contacts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** contacts-paginator.ts */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ContactsQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./state/contacts.query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PaginatorPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@datorama/akita&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONTACTS_PAGINATOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InjectionToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CONTACTS_PAGINATOR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contactsQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ContactsQuery&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PaginatorPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contactsQuery&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;withControls&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;withRange&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should already be familiar with the above code. This is the regular process of creating a factory provider in Angular.&lt;/p&gt;

&lt;p&gt;We are creating a &lt;code&gt;new PaginatorPlugin()&lt;/code&gt;, passing the query we want to use in our pagination.&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;withControls()&lt;/code&gt; will give us an array of pages so we &lt;code&gt;ngFor&lt;/code&gt; on them and &lt;code&gt;withRange()&lt;/code&gt; which will give us the from and to values to display to the user.&lt;/p&gt;

&lt;p&gt;Now, we can use it in our component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** contacts-page.component.ts */&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CONTACTS_PAGINATOR&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../contacts-paginator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Contact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../state/contact.model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PaginationResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PaginatorPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@datorama/akita&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./contacts-page.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContactsPageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;contacts$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PaginationResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONTACTS_PAGINATOR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaginatorPlugin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;contactsService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContactsService&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contacts$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;})&lt;/span&gt;
     &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paginator exposes a &lt;code&gt;pageChanges&lt;/code&gt; observable (which fires the first page immediately). When this observable emits, we call the &lt;code&gt;paginatorRef&lt;/code&gt; &lt;code&gt;getPage()&lt;/code&gt; method, passing the HTTP request we want to initialize when the page doesn’t exist in the cache&lt;/p&gt;

&lt;p&gt;Paginator expects to get the following fields as part of the response from the server (in our case, the &lt;code&gt;request&lt;/code&gt; service method):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** paginator-request.interface.ts */&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;perPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lastPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currentPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;total&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to that, Paginator also exposes all the data that you need to display as well as methods for controlling the page from the UI, for example:&lt;br&gt;
&lt;code&gt;isLoading$&lt;/code&gt;, &lt;code&gt;isFirst&lt;/code&gt;, &lt;code&gt;isLast&lt;/code&gt;, &lt;code&gt;prevPage()&lt;/code&gt;, &lt;code&gt;nextPage()&lt;/code&gt;, &lt;code&gt;setPage()&lt;/code&gt;, &lt;code&gt;isPageActive()&lt;/code&gt;, &lt;code&gt;pageControls&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;Let’s see how can we use it in the component’s template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;/** contacts-page.component.html */
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;content-loader&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.isLoading$ | async"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/content-loader&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"(contacts$ | async) as contacts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;[class.hide]=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.isLoading$ | async"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;thead&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"thead-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let contact of contacts.data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;{{ contact.id }}&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ contact.name }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ contact.email }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ contact.address }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;[class.disabled]=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.isFirst"&lt;/span&gt; 
                &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.prevPage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&amp;gt;&lt;/span&gt;Previous&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;[class.active]=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.isPageActive(page)"&lt;/span&gt;  
                &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.setPage(page)"&lt;/span&gt;  
                &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let page of contacts.pageControls"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&amp;gt;&lt;/span&gt;{{ page }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;[class.disabled]=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.isLast"&lt;/span&gt; 
                &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"paginatorRef.nextPage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s all you need in order to get fully working pagination including caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Router Integration
&lt;/h2&gt;

&lt;p&gt;There are times where we want to persist the current page in the URL address, for example: &lt;code&gt;http://app.com/contact?page=3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example of how can we implement it with the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** contacts-page-router.component.ts */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContactsPageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;contacts$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PaginationResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONTACTS_PAGINATOR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaginatorPlugin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;contactsService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContactsService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActivatedRoute&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryParamMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
       &lt;span class="nf"&gt;untilDestroyed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contacts$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;})&lt;/span&gt;
     &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each time the &lt;code&gt;page&lt;/code&gt; query parameter changes, we notify the plugin about the current page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Pagination
&lt;/h2&gt;

&lt;p&gt;There are times where we want to give our users the ability to filter the data, sort it, or change the number of entries per page. The vital step here is that when we change a filter, sort, etc. We want to invalidate the cache, because it may alter the server response.&lt;/p&gt;

&lt;p&gt;For example, let’s add a &lt;code&gt;sortBy&lt;/code&gt; filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** contacts-page-advanced.component.ts */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContactsPageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;contacts$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PaginationResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;sortByControl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONTACTS_PAGINATOR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaginatorPlugin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;contactsService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContactsService&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;pag&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortChanges$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sortByControl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valueChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contacts$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;sortChanges$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearCache&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageChanges&lt;/span&gt;
    &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sortBy&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;sortBy&lt;/code&gt; value changes, we need to invalidate the cache, so the Paginator will know that it needs to re-fetch the data from the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pagination Metadata
&lt;/h2&gt;

&lt;p&gt;Sometimes you want to save the current filters, so if the user navigates from the current route and comes back you want the filter values to persist. Paginator exposes a metadata property where you can set these values.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** contacts-page-metadata.component.ts */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;startWith&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContactsPageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortByValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sortBy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sortByControl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortByValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sort$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sortByControl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valueChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortByValue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contacts$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;sort$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearCache&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageChanges&lt;/span&gt;
    &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sortBy&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sortBy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paginatorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thank you for reading!&lt;br&gt;&lt;br&gt;
If you liked the article hit the 🧡 &amp;amp; 🦄 buttons and share it 🎉&lt;/p&gt;




&lt;p&gt;&lt;a href="https://docs.google.com/forms/d/e/1FAIpQLScZJsBWGDtyJ-izT9gKkIUU1Ig0VHfMjkUR3ikBjiD4x0Yidw/viewform" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwbrnapxsahbukgv3yee9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’re looking for great front-end developers. If you’re one of them, you’re passionate about technology, and you want to work for the best &lt;a href="https://www.salesforce.com/blog/2018/02/salesforce-fortune-100-best-companies-to-work.html" rel="noopener noreferrer"&gt;company&lt;/a&gt; in the world, come and join me.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>angular</category>
      <category>akita</category>
    </item>
  </channel>
</rss>
