<?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: Juan Manuel Azambuja</title>
    <description>The latest articles on DEV Community by Juan Manuel Azambuja (@juanazam).</description>
    <link>https://dev.to/juanazam</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%2F600146%2Fea398981-85d5-4f72-8cdf-bd5a01e7f1e4.jpeg</url>
      <title>DEV Community: Juan Manuel Azambuja</title>
      <link>https://dev.to/juanazam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juanazam"/>
    <language>en</language>
    <item>
      <title>Migrating Controllers to top-level Components in Ember</title>
      <dc:creator>Juan Manuel Azambuja</dc:creator>
      <pubDate>Tue, 06 Apr 2021 13:25:33 +0000</pubDate>
      <link>https://dev.to/juanazam/migrating-controllers-to-top-level-components-in-ember-ggc</link>
      <guid>https://dev.to/juanazam/migrating-controllers-to-top-level-components-in-ember-ggc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A while ago I came across the following tweet&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1361347296605200393-546" src="https://platform.twitter.com/embed/Tweet.html?id=1361347296605200393"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1361347296605200393-546');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1361347296605200393&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;After reading it, I had a few flashbacks to discussions in the community about routable components taking the place of controllers. That transition never happened, and controllers are still around.&lt;/p&gt;

&lt;p&gt;Given controllers are long-lived entities in the framework, they are a source of a lot of bugs while writing ember apps. The classic bug is to forget to reset certain state in a controller, so when the user re visits the route, the state of the controller is not automatically reset.&lt;/p&gt;

&lt;p&gt;After reading this response:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1361490151029940231-463" src="https://platform.twitter.com/embed/Tweet.html?id=1361490151029940231"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1361490151029940231-463');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1361490151029940231&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I decided to take a stab at migrating a controller on a real app and write about the process, so I could actually see how it would look in real life and also share knowledge with the community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real world example
&lt;/h2&gt;

&lt;p&gt;At Mimiquate, we have developed an open source app called &lt;a href="https://timo.mimiquate.xyz" rel="noopener noreferrer"&gt;Timo&lt;/a&gt;, that aims to find acceptable time slots to have meetings for remote teams with team members all round the world. If you are interested, you can check the &lt;a href="https://www.linkedin.com/pulse/timo-simplifying-scheduling-virtual-meetings-juan-azambuja" rel="noopener noreferrer"&gt;article&lt;/a&gt; I wrote on it's release. I decided to migrate Timo's largest controller, and write about the process while doing it.&lt;/p&gt;

&lt;p&gt;Here is a link to &lt;a href="https://github.com/mimiquate/timo/commit/08b881424a358e0ef9412fd8d29fa5adebb71f3e" rel="noopener noreferrer"&gt;the commit where the change is implemented&lt;/a&gt; if you want to go straight to the point.&lt;/p&gt;

&lt;p&gt;Here are a few details to go over, the template of the route is a lot simpler now, which was expected.&lt;/p&gt;


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


&lt;p&gt;All of its content was moved to the new top-level component.&lt;/p&gt;

&lt;p&gt;Regarding the component file, most of the changes are straight forward: basically stop relying on the model property, and used the passed arguments instead. I also had to make sure I imported the store and router services, given those are not automatically available within components. This resulted in a few small changes, for example, updating transitions to other routes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small hiccup
&lt;/h2&gt;

&lt;p&gt;I would have thought this was the end of it, but it wasn't. When doing this migration you would assume the state of the component would always be refreshed, given that we we have switched from a controller to a component, but that wasn't the case.&lt;/p&gt;

&lt;p&gt;On Timo, most of the action happens on the team route, and the user usually moves from one team to the other. This means the component is not destroyed, and only its arguments are updated. As a result, the state of the component never resets when navigating from team to team.&lt;/p&gt;

&lt;p&gt;With controllers, the solution would be simple, we would just reset the state of the controller on the &lt;code&gt;resetController&lt;/code&gt; hook of our route and that would be it.&lt;/p&gt;

&lt;p&gt;If we were using Ember Classic components, we could use the &lt;code&gt;didUpdateAttrs&lt;/code&gt; hook to reset these variables, since the parameters only update when the route is refreshed, but we don't have that possibility in Octane.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter ember-modifiers
&lt;/h3&gt;

&lt;p&gt;The simplest solution I could find to this problem was to use ember-modifiers.&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/ember-modifier" rel="noopener noreferrer"&gt;
        ember-modifier
      &lt;/a&gt; / &lt;a href="https://github.com/ember-modifier/ember-modifier" rel="noopener noreferrer"&gt;
        ember-modifier
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A library for writing Ember modifiers
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ember-modifier&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This addon provides an API for authoring &lt;a href="https://blog.emberjs.com/2019/03/06/coming-soon-in-ember-octane-part-4.html" rel="nofollow noopener noreferrer"&gt;element modifiers&lt;/a&gt; in Ember. It
mirrors Ember's &lt;a href="https://octane-guides-preview.emberjs.com/release/templates/writing-helpers" rel="nofollow noopener noreferrer"&gt;helper&lt;/a&gt; API, with variations for writing both simple
function-based modifiers and more complicated class-based modifiers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; this is the README for the v4 release. For the v3 README, see &lt;a href="https://github.com/ember-modifier/ember-modifier/blob/v3/README.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ember-modifier/ember-modifier#compatibility" rel="noopener noreferrer"&gt;Compatibility&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#typescript" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ember-modifier/ember-modifier#philosophy" rel="noopener noreferrer"&gt;Philosophy&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#whoa-whoa-whoa-hold-on-whats-a-side-effect" rel="noopener noreferrer"&gt;Whoa whoa whoa, hold on, what's a &lt;em&gt;"side effect"&lt;/em&gt;?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#managing-side-effects-effectively" rel="noopener noreferrer"&gt;Managing "side effects" effectively&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ember-modifier/ember-modifier#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ember-modifier/ember-modifier#function-based-modifiers" rel="noopener noreferrer"&gt;Function-Based Modifiers&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#generating-a-function-based-modifier" rel="noopener noreferrer"&gt;Generating a Function-Based Modifier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#example-without-cleanup" rel="noopener noreferrer"&gt;Example without Cleanup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#example-with-cleanup" rel="noopener noreferrer"&gt;Example with Cleanup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#ember-inspector-support" rel="noopener noreferrer"&gt;Ember Inspector Support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ember-modifier/ember-modifier#class-based-modifiers" rel="noopener noreferrer"&gt;Class-Based Modifiers&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#generating-a-class-modifier" rel="noopener noreferrer"&gt;Generating a Class Modifier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#example-without-cleanup-1" rel="noopener noreferrer"&gt;Example without Cleanup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#example-with-cleanup-1" rel="noopener noreferrer"&gt;Example with Cleanup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#example-with-service-injection" rel="noopener noreferrer"&gt;Example with Service Injection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#api" rel="noopener noreferrer"&gt;API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ember-modifier/ember-modifier#typescript-1" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#the-signature-type" rel="noopener noreferrer"&gt;The &lt;code&gt;Signature&lt;/code&gt; type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ember-modifier/ember-modifier#examples-with-typescript" rel="noopener noreferrer"&gt;Examples with TypeScript&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#function-based-modifier" rel="noopener noreferrer"&gt;Function-based modifier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#class-based" rel="noopener noreferrer"&gt;Class-based&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ember-modifier/ember-modifier#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Compatibility&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Ember.js v3.24 or above&lt;/li&gt;
&lt;li&gt;Embroider or ember-auto-import v2.0.0 or above (this is &lt;a href="https://emberjs.github.io/rfcs/0507-embroider-v2-package-format.html" rel="nofollow noopener noreferrer"&gt;v2 addon&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;TypeScript&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;This project follows the current draft of &lt;a href="https://github.com/emberjs/rfcs/blob/master/text/0730-semver-for-ts.md" rel="noopener noreferrer"&gt;the Semantic Versioning for TypeScript Types&lt;/a&gt; proposal.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Currently supported TypeScript versions:&lt;/strong&gt; v5.0 - v5.5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compiler support policy:&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ember-modifier/ember-modifier" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The addon comes with helpers we are familiar with, in this case, I used the &lt;code&gt;did-update&lt;/code&gt; helper, as shown below.&lt;/p&gt;


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


&lt;p&gt;I added a container div with the &lt;code&gt;did-update&lt;/code&gt; modifier, which is called every time the current team is updated. When that happens, the &lt;code&gt;resetCurrentTime&lt;/code&gt; function is executed, and the state is reset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div {{did-update this.resetCurrentTime this @team.id this}}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;Migrating to top-level components is not hard at all, but there are a few issues that can be found after testing your app in different circumstances.&lt;/p&gt;

&lt;p&gt;There are times when we will have to deal with Controllers like it or not. One of these situations, is when dealing with query params. Right now, the only way of dealing with them is via &lt;code&gt;queryParams&lt;/code&gt; interface on controllers, which has its fair share of quirkiness.&lt;/p&gt;

&lt;p&gt;Regarding issues related to glimmer components, most solutions can be found &lt;a href="https://guides.emberjs.com/release/upgrading/current-edition/glimmer-components/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As always, Ember's documentation goes above and beyond.&lt;/p&gt;

&lt;p&gt;In summary, not using controllers is definitely possible, but it’s not a solution that the framework fully supports, and that always has a cost. Although some controllers can be fully moved to components, others can’t, which means there is no uniform way of transforming all the code base this way without compromises.&lt;/p&gt;

&lt;p&gt;Special thanks to&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__97500"&gt;
    &lt;a href="/nullvoxpopuli" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F97500%2F556a088e-b9bf-4b41-9a82-b8a6e07970b1.jpg" alt="nullvoxpopuli image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/nullvoxpopuli"&gt;NullVoxPopuli&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/nullvoxpopuli"&gt;I like code.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;For helping me discuss some of the issues I faced while implementing these changes.&lt;/p&gt;

</description>
      <category>ember</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
