<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>DevIntent Blog</title>
        <link>https://devintent.com</link>
        <description>Our blog is where our experts highlight best practices, demonstrate solutions to common problems, and communicate information about recent software releases.</description>
        <lastBuildDate>Tue, 18 Nov 2025 23:25:28 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>DevIntent Blog</title>
            <url>https://devintent.com/DevIntentLogo.png</url>
            <link>https://devintent.com</link>
        </image>
        <copyright>DevIntent - All rights reserved 2025</copyright>
        <item>
            <title><![CDATA[Level Up Your App`s Speed with `NgOptimizedImage`]]></title>
            <link>https://devintent.com/blog/2024-11-23-level-up-your-apps-speed-with-ngoptimizedimage.md</link>
            <guid isPermaLink="false">blog/2024-11-23-level-up-your-apps-speed-with-ngoptimizedimage.md</guid>
            <pubDate>Sat, 23 Nov 2024 14:18:00 GMT</pubDate>
            <description><![CDATA[Explore how NgOptimizedImage transforms Angular app performance by optimizing image loading. Get a detailed breakdown of attributes, their usage, and impact. Learn how to achieve a perfect 100 Performance score.]]></description>
            <content:encoded><![CDATA[<p>If you've worked on a web app, you know that images significantly impact both design and performance. While
they make pages look great, they can also slow everything down. That’s where Angular’s <code>NgOptimizedImage</code>
directive comes in. It’s a handy tool for optimizing images, so they load faster without losing quality. Let’s
dive into how this directive can make your Angular app snappier and improve user experience.</p>
<hr />
<h2 id="whyoptimizeimagesanyway">Why Optimize Images Anyway?</h2>
<p>We all want our apps to look good, but images come with costlier load times. Optimizing images can
dramatically improve performance metrics, especially the
<a href="https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint">Largest Contentful Paint (LCP)</a>,
which measures how fast the largest piece of content appears on the screen. This is huge for user experience
and SEO. Angular’s <code>NgOptimizedImage</code> directive makes it easy to get it right without manual tweaks.</p>
<hr />
<h2 id="keyfeaturesofngoptimizedimage">Key Features of <code>NgOptimizedImage</code></h2>
<h3 id="1responsiveimageswithsrcsetandsizes">1. Responsive Images with <code>srcSet</code> and <code>sizes</code></h3>
<p>The <code>srcSet</code> and <code>sizes</code> attributes allow the browser to load the right image size for each device, which is
especially helpful for performance. The great thing about Angular’s <code>NgOptimizedImage</code> directive is that it
generates the <code>srcSet</code> for you, so you don’t need to do it manually.</p>
<p><strong>Example:</strong></p>
<pre><code class="html language-html">&lt;img
  ngSrc="angular.jpg"
  width="200"
  height="200"
  sizes="80vw"
/&gt;
</code></pre>
<p>Here, <code>sizes="80vw"</code> sets the image to 80% of the viewport width. Angular will handle the rest, creating a
<code>srcSet</code> with various resolutions so that each device gets the best fit. This saves time and ensures a smooth
load no matter the screen size.</p>
<h3 id="2customizingimagebreakpoints">2. Customizing Image Breakpoints</h3>
<p>If you’re working with specific screen sizes, Angular lets you customize breakpoints by setting an
<code>IMAGE_CONFIG</code> token. This way, you can pick just the breakpoints that match your app’s design.</p>
<p><strong>Example:</strong></p>
<pre><code class="typescript language-typescript">providers: [{
  provide: IMAGE_CONFIG,
  useValue: {
    breakpoints: [384, 640, 750]
  }
}]
</code></pre>
<p>Now Angular will only generate images for 384px, 640px, and 750px, which keeps your file sizes smaller and
your app faster.</p>
<hr />
<h3 id="3prioritizingkeyimageswithpriority">3. Prioritizing Key Images with <code>priority</code></h3>
<p>Ever noticed how long it can take to load a big image like a banner? The <code>priority</code> attribute tells Angular
which images are critical for loading first. If you set <code>priority</code>, Angular preloads the image, making sure it
appears quickly, improving that all-important LCP.</p>
<p><strong>Example:</strong></p>
<pre><code class="html language-html">&lt;img
  ngSrc="hero.jpg"
  width="1200"
  height="600"
  priority
/&gt;
</code></pre>
<p>For server-side rendered apps, Angular even adds a <code>&lt;link rel="preload"&gt;</code> tag for these images, so they start
loading right away. This is perfect for hero images or banners that you want users to see immediately.</p>
<hr />
<h3 id="4fillmodeforflexiblelayouts">4. Fill Mode for Flexible Layouts</h3>
<p>Need an image to fill a container, like a background? <code>fill</code> mode has you covered. It lets an image scale to
fit the container without needing fixed dimensions, which is perfect for layouts with unknown widths or
heights.</p>
<p><strong>Example:</strong></p>
<pre><code class="html language-html">&lt;img ngSrc="background.jpg" fill/&gt;
</code></pre>
<p>Just make sure your container has <code>position: relative</code>, <code>absolute</code>, or <code>fixed</code>, so the image fills it
properly. This feature is great for responsive layouts where you want images to adapt smoothly.</p>
<hr />
<h3 id="5lazyloadingforoffscreenimages">5. Lazy Loading for Off-Screen Images</h3>
<p>Angular makes lazy loading effortless with <code>loading="lazy"</code>, which defers loading images until they’re about
to be visible. This reduces the initial page load and is awesome for things like image galleries.</p>
<p><strong>Example:</strong></p>
<pre><code class="html language-html">&lt;img
  ngSrc="thumbnail.jpg"
  width="200"
  height="200"
  loading="lazy"
/&gt;
</code></pre>
<p>Just be cautious with images that are crucial to the layout, like a logo. For these, skip lazy loading to
ensure they load right away.</p>
<hr />
<h3 id="6placeholdersforabetterloadingexperience">6. Placeholders for a Better Loading Experience</h3>
<p>Nothing kills user experience like a blank loading image. With <code>placeholder</code>, you can show a temporary low-res
version or even a <a href="https://medium.com/@shimonmoyal/a-dive-into-base64-and-its-significance-in-web-development-b6bd4427f61d">Base64-encoded</a>
preview while the main image loads. This provides a smoother experience as users see a preview of the
image right away.</p>
<p>Here’s an example of implementing a placeholder:</p>
<pre><code class="html language-html">&lt;img
  ngSrc="profile.jpg"
  width="200"
  height="200"
  placeholder
/&gt;
</code></pre>
<p>To take it a step further, you can use a Base64-encoded image as a placeholder. For example, a blurred
version of the image can be used to indicate that the original is still loading.</p>
<p><img src="/blog/ngoptimizedimage-1/placeholder.gif" alt="A blurred circular spinner placeholder serving as a placeholder" /></p>
<p>The placeholder blur effect can be customized with the <a href="https://angular.dev/api/common/ImagePlaceholderConfig">placeHolderConfig</a>
object or turned off entirely. For example:</p>
<pre><code class="html language-html">&lt;img
  ngSrc="cat.jpg"
  width="400"
  height="200"
  placeholder
  [placeholderConfig]="{blur: false}"
/&gt;
</code></pre>
<p>If you'd like to use a Base64-encoded placeholder, you can easily generate the string using:</p>
<ul>
<li>Online Tools: Use a free online Base64 converter like <a href="https://www.base64-image.de/">Base64-Image</a>, and
it will generate the encoded string.</li>
<li>Command Line Tools: Open a terminal and type the following command:</li>
</ul>
<pre><code class="bash language-bash">  base64 -i input-image.jpg
</code></pre>
<p>Once you have the Base64 string, you can embed it directly into your HTML as the src for the placeholder:</p>
<pre><code class="html language-html">&lt;img
  ngSrc="profile.jpg"
  width="200"
  height="200"
  placeholder="data:image/jpeg;base64,/9j/4AAQSk..."
/&gt;
</code></pre>
<p>This approach makes the user experience smoother and creates a seamless visual flow.</p>
<p>If you use a CDN, you can <a href="https://cloudinary.com/blog/guest_post/create-image-loading-placeholders-in-nuxtjs">generate low-res placeholders</a>
automatically. Just keep them small (under 4 KB) to avoid slowing down the load. Angular will even throw
an error if the placeholder size is too big:</p>
<pre><code class="text language-text">NG02965: The NgOptimizedImage directive (activated on an &lt;img&gt; element with the ngSrc="angular.jpg") has
detected that the placeholder attribute is set to a data URL which is longer than 4000 characters. This
is discouraged, as large inline placeholders directly increase the bundle size of Angular and hurt page
load performance. For better loading performance, generate a smaller data URL placeholder.
</code></pre>
<hr />
<h2 id="cdnintegrationforfasterimagedelivery">CDN Integration for Faster Image Delivery</h2>
<p>By using a Content Delivery Network (CDN) with <code>NgOptimizedImage</code>, you get faster load times because images
are served from servers closer to your users. CDNs cache content across the globe, meaning shorter load times
and less data travel, which makes a huge difference, especially for users far from your primary server.</p>
<p>CDNs also often compress images, ensuring the best quality at the smallest size, which boosts performance even
further. When combined with <code>NgOptimizedImage</code>, CDNs can help you build a fast, responsive app that works well
for users everywhere.</p>
<hr />
<h2 id="apracticalexample">A Practical Example</h2>
<p>Now, let's look at a real-world example to see how the <code>NgOptimizedImage</code> directive can make a big difference
in performance. Imagine we’re building a site that displays 16 preview images.</p>
<p><img src="/blog/ngoptimizedimage-1/demo-app.png" alt="Preview of the Demo Site" /></p>
<p>Here’s the initial setup with the standard <code>src</code> attribute:</p>
<pre><code class="html language-html">&lt;div style="..."&gt;
  @for (image of list; track $index) {
  &lt;img
    width="300"
    height="300"
    [src]="image"
    alt="A 300x300 placeholder image with a light gray background and bold black 'Preview' text in the center"
  /&gt;
  }
&lt;/div&gt;
</code></pre>
<p>When we analyze the page in Lighthouse, the First Contentful Paint (FCP) comes in at 1.4 seconds, while the
Largest Contentful Paint (LCP) lags behind at 13.5 seconds—not ideal.</p>
<p><img src="/blog/ngoptimizedimage-1/demo-app-initial-lighthouse-score.png" alt="Lighthouse Performance Score for Non-Optimized Images" /></p>
<p>By making a few tweaks with <code>NgOptimizedImage</code>, we can get those numbers way down:</p>
<pre><code class="html language-html">&lt;div style="..."&gt;
  @for (image of list; track $index) {
    &lt;img
      width="300"
      height="300"
      [src]="image"
      alt="A 300x300 placeholder image with a light gray background and bold black 'Preview' text in the center"
      priority
      placeholder
    /&gt;
  }
&lt;/div&gt;
</code></pre>
<p>To go the extra mile, we add a <code>preconnect</code> link for our image server in the <code>&lt;head&gt;</code>:</p>
<pre><code class="html language-html">&lt;link rel="preconnect" href="https://fpoimg.com/"&gt;
</code></pre>
<p>And in our app configuration, we set up
a <a href="https://angular.dev/guide/image-optimization#configuring-an-image-loader-for-ngoptimizedimage">custom image loader</a>
for our CDN (e.g., <code>Imgix</code>):</p>
<pre><code class="typescript language-typescript">const appConfig: ApplicationConfig = {
  providers: [provideImgixLoader('https://fpoimg.com/')],
};
</code></pre>
<p>With these small adjustments, we see a huge performance boost: FCP drops to just 0.2 seconds, and LCP is down
to a quick 0.7 seconds! This is a perfect example of how <code>NgOptimizedImage</code> can make a real difference in your
app’s speed and user experience.</p>
<p><img src="blog/ngoptimizedimage-1/demo-app-final-lighthouse-score.png" alt="Lighthouse Performance Score for Optimized Images" /></p>
<hr />
<h2 id="wrappingup">Wrapping Up</h2>
<p>Angular’s <code>NgOptimizedImage</code> is a fantastic tool for improving image handling and app performance. Whether
you’re working with responsive images, lazy loading, or CDN integration, this directive makes it easy to get
things right. With these optimizations, you’ll have a faster, smoother app that keeps users happy. Give
<code>NgOptimizedImage</code> a try and see the difference in your next project!</p>
<hr />
<p>You can access the application used in the article on
<a href="https://github.com/jzolnowski/ngoptimizedimage-demo">GitHub</a>.</p>]]></content:encoded>
            <category>angular</category>
            <category>perf</category>
        </item>
        <item>
            <title><![CDATA[Testing Reactive Angular Components - A Closer Look]]></title>
            <link>https://devintent.com/blog/2024-08-20-testing-reactive-angular-components.md</link>
            <guid isPermaLink="false">blog/2024-08-20-testing-reactive-angular-components.md</guid>
            <pubDate>Tue, 20 Aug 2024 12:30:00 GMT</pubDate>
            <description><![CDATA[Explore the reactive testing of Angular components, focusing on the utilization of TestBed methods and Angular`s reactive signals and effects to create robust unit tests.]]></description>
            <content:encoded><![CDATA[<h1 id="testingreactiveangularcomponentsacloserlook">Testing Reactive Angular Components: A Closer Look</h1>
<p>In this article, we will take a look at how to test the reactive components in Angular, especially with some
of the nifty new features that have come along. Our case study involves a component we created for
demonstration, <code>UsersComponent</code>. Together, we'll unpack its code and walk through the testing process,
highlighting on the why's and how's of each step.</p>
<h2 id="gettingtoknowuserscomponent">Getting to Know UsersComponent</h2>
<p>First off, let's chat about our <code>UsersComponent</code>. It's a nifty standalone component designed to handle a user
list in a reactive manner, making good use of Angular's reactive features
like <a href="https://angular.io/api/core/Signal">signal</a> and <a href="https://angular.io/guide/signals#effects">effect()</a> for
handling the data and keep the UI fresh.</p>
<pre><code class="typescript language-typescript">@Component({
  standalone: true,
  // Component metadata...
})
export class UsersComponent implements OnInit {
  private readonly usersService = inject(UsersService);
  readonly dataSource: MatTableDataSource&lt;User&gt; =
    new MatTableDataSource&lt;User&gt;([]);
  readonly users: WritableSignal&lt;User[]&gt; = signal([]);

  constructor() {
    effect(() =&gt; {
      this.dataSource.data = this.users();
    });
  }

  async ngOnInit(): Promise&lt;void&gt; {
    this.users.set(await lastValueFrom(this.usersService.getUsers()));
  }

  addUser(): void {
    const iter = this.users().length + 1;
    this.users.update(users =&gt; [...users, newUser]);
  }

  removeUser(id: string): void {
    this.users.update(users =&gt; users.filter((user) =&gt; user.id !== id));
  }
}
</code></pre>
<p>The constructor is where the magic starts. We've got an <code>effect()</code> that set up the stage and ensures the
<a href="https://material.angular.io/components/table/overview#datasource">MatTableDataSource</a> is always reflecting
the latest users' data. It keeps our UI accurately updated, no manual refreshes needed.</p>
<p>When <a href="https://angular.io/api/core/OnInit">ngOnInit()</a> kicks in, it's all about fetching the async data and
setting it up in the users signal. This action gets the ball rolling for the effect to do its thing and
update the UI.</p>
<p>We have also implemented methods to add a new user or take one out. The <code>addUser()</code> and <code>removeUser()</code>
functions tweak the users signal, which also triggers the <code>effect()</code> to update the data source accordingly.</p>
<h2 id="thehowtooftesting">The How-To of Testing</h2>
<p>Now, when it comes to testing these reactive Angular pieces, there's a bit of know-how involved. We need to
understand several Angular-specific methods and concepts, along with strategies to avoid calls to the real
services. We're tackling <code>TestBed.flushEffects()</code>, the mechanics behind <code>effect()</code>, <code>signal.update()</code>,
<code>signal.set()</code> and <code>fixture.whenStable()</code>method, not to mention Jasmine's <code>spyOn</code> to keep our service calls in
check.</p>
<h3 id="understandingtestbedflusheffects">Understanding TestBed.flushEffects()</h3>
<p>The <a href="https://angular.io/api/core/testing/TestBed#flushEffects">TestBed.flushEffects()</a> method, introduced in
recent Angular updates (<a href="https://github.com/angular/angular/pull/51049/files">PR #51049</a>
and <a href="https://github.com/angular/angular/pull/53843/files">PR #53843</a>), is super important for testing
components with effects. It ensures that all the queued effects are executed in the test environment. This is
especially useful for those asynchronous moments when you want to make sure everything's settled before making
your assertions.</p>
<h3 id="thetrioeffectsignalsetandsignalupdate">The Trio: effect(), signal.set(), and signal.update()</h3>
<p>In our <code>UsersComponent</code>, we used the power of <code>effect()</code>,
<a href="https://angular.io/api/core/WritableSignal#update">signal.update()</a>, and
<a href="https://angular.io/api/core/WritableSignal#set">signal.set()</a> to keep things reactive and fresh.</p>
<p>The <code>effect()</code> function allows us to create a reactive link between the users signal and
the <code>MatTableDataSource</code>. This means whenever the users signal changes, the <code>effect()</code> function automatically
updates <code>dataSource.data</code>, ensuring the UI stays in sync with the state.</p>
<p><code>signal.set()</code> is our direct line to replace the signal's current value and kick the <code>effect()</code> into gear,
updating the data source with the fresh list of users.</p>
<pre><code class="typescript language-typescript">signal.set([...users, newUser]);
</code></pre>
<p>And for those times when you need to finesse the current signal value, <code>signal.update()</code> is the go-to,
allowing tweaking the signal's value based on its current state. Perfect for when you want to add a new user
without replacing the whole users list.</p>
<pre><code class="typescript language-typescript">signal.update(users =&gt; [...users, newUser]);
</code></pre>
<h3 id="ensuringstabilitywithfixturewhenstable">Ensuring Stability with fixture.whenStable()</h3>
<p>Asynchronous operations are the norm when fetching data, we need to ensure that our tests wait for these
operations to complete. This is
where <a href="https://angular.io/api/core/testing/ComponentFixture#whenStable">whenStable()</a> comes into play.</p>
<pre><code class="typescript language-typescript">await fixture.whenStable();
</code></pre>
<p>This function returns a promise that resolves when all pending asynchronous activities within the component
are completed. It's essential for ensuring that our assertions are made after the component has finished
processing the data.</p>
<h3 id="keepingitrealwithjasminespyon">Keeping it Real with Jasmine spyOn</h3>
<p>We definitely don't want our tests making actual calls out to the real services. So, we bring
in <a href="https://jasmine.github.io/api/edge/global.html#spyOn">Jasmine's spyOn</a> method to intercept calls to
the <code>UsersService.getUsers()</code> method and provide controlled, predictable responses.</p>
<pre><code class="typescript language-typescript">beforeEach(() =&gt; {
  spyOn(usersService, 'getUsers').and.returnValue(of(mockedUsers));
...
});
</code></pre>
<p>By doing so, we simulate the service's behavior without making actual HTTP requests. This approach ensures
that our tests remain fast and are not affected by external factors such as network latency or service
availability.</p>
<h3 id="firingupngoninit">Firing up ngOnInit()</h3>
<p>We used <a href="https://angular.io/guide/testing-components-scenarios#detectchanges">fixture.detectChanges()</a> to work
in the <a href="https://jasmine.github.io/api/edge/global.html#beforeEach">beforeEach</a> to get the component's lifecycle
rolling and make sure <code>ngOnInit</code> does its thing.</p>
<pre><code class="typescript language-typescript">beforeEach(() =&gt; {
  ...
  fixture.detectChanges();
});
</code></pre>
<p>This is essential for setting up the initial state of the component, such as bind properties or fetching the
initial list of users and ensures that tests have a consistent starting state, with the component fully
initialized and ready to respond to simulated user interactions.</p>
<h3 id="divingintotestinguserscomponent">Diving into Testing UsersComponent</h3>
<p>Armed with our understanding of Angular's reactive features and testing methods, we're now ready to delve into
the unit tests for UsersComponent. Each test case is meticulously crafted to verify the component's
functionality, ensuring it behaves as expected under various scenarios.</p>
<h4 id="test1populatingmattabledatasourcewithusers">Test 1: Populating MatTableDataSource with Users</h4>
<pre><code class="typescript language-typescript">it('should populate MatTableDataSource with users', async () =&gt; {
  expect(component.dataSource.data.length)
    .withContext('Data Source length before fetch').toBe(0);

  await fixture.whenStable();
  TestBed.flushEffects();

  expect(component.users()).withContext('User list after fetch')
    .toEqual(mockedUsers);
  expect(component.dataSource.data.length)
    .withContext('Data Source length after fetch').toBe(3);
  expect(component.dataSource.data).toEqual(mockedUsers);
});
</code></pre>
<p>In this test, we first assert that our data source is initially empty. After calling <code>fixture.whenStable()</code>,
we ensure all asynchronous operations have completed. Then, <code>TestBed.flushEffects()</code> is invoked to process any
effects, such as those linked to our users signal. This guarantees that our UI is synchronized with the
current state. We conclude by asserting that the data source now contains the mocked users, proving that our
effects correctly update the UI in response to the signal changes.</p>
<h4 id="test2addinganewuser">Test 2: Adding a New User</h4>
<pre><code class="typescript language-typescript">it('should add a new user', async () =&gt; {
  const newUser = {
    id: 'id_4',
    username: 'user_name_4',
    email: 'test4@email.com'
  }

  await fixture.whenStable();
  await component.addUser();
  TestBed.flushEffects();

  expect(component.dataSource.data.length)
    .withContext('Data Source length after new user addition').toBe(4);
  expect(component.dataSource.data).toEqual([...mockedUsers, newUser]);
});
</code></pre>
<p>This test focuses on adding a new user. We initiate by awaiting component stabilization and then invoke the
<code>async addUser()</code> method, which updates the users signal. Post this, <code>TestBed.flushEffects()</code> is called to
trigger the effects that update the UI. Our assertions confirm that the data source now includes the new user,
demonstrating the component's dynamic response to state changes.</p>
<h4 id="test3removingauser">Test 3: Removing a User</h4>
<pre><code class="typescript language-typescript">it('should remove user', async () =&gt; {
  await fixture.whenStable();
  await component.removeUser('id_2');
  TestBed.flushEffects();

  expect(component.dataSource.data.length)
    .withContext('Data Source length after user remove').toBe(2);
  expect(component.dataSource.data[1].id).toBe('id_3');
});
</code></pre>
<p>In the final test, we validate the removal of a user. After stabilizing the component, we call <code>removeUser()</code>,
updating the users signal. Following this with <code>TestBed.flushEffects()</code> ensures our effects process this
change. The assertions then verify that the data source has been updated to reflect the removal of the
specified user, again highlighting the reactive nature of our component.</p>
<h4 id="puttingitalltogether">Putting it All Together</h4>
<p>Here's the complete overview of our UsersComponent tests:</p>
<pre><code class="typescript language-typescript">describe('UserListComponent', () =&gt; {
  let component: UsersComponent;
  let usersService: UsersService;
  let fixture: ComponentFixture&lt;UsersComponent&gt;;
  const mockedUsers: User[] = [
    {"id": "id_1", "username": "user_name_1", "email": "test1@email.com"},
    {"id": "id_2", "username": "user_name_2", "email": "test2@email.com"},
    {"id": "id_3", "username": "user_name_3", "email": "test3@email.com"}
  ];

  beforeEach(async () =&gt; {
    await TestBed.configureTestingModule({
      imports: [UsersComponent, NoopAnimationsModule, HttpClientTestingModule],
      providers: [UsersService],
    }).compileComponents();

    usersService = TestBed.inject(UsersService);
    fixture = TestBed.createComponent(UsersComponent);
    component = fixture.componentInstance;
  });

  beforeEach(() =&gt; {
    spyOn(usersService, 'getUsers').and.returnValue(of(mockedUsers));
    fixture.detectChanges();
  });

  it('should create', () =&gt; {
    expect(component).toBeTruthy();
  });

  it('should initialize with default values', () =&gt; {
    expect(component.isLoading()).toBeTruthy();
    expect(component.dataSource.data.length).toBe(0);
    expect(component.displayedColumns.length).toBe(4);
  });

  it('should populate MatTableDataSource with users', async () =&gt; {
    expect(component.dataSource.data.length)
      .withContext('Data Source length before fetch').toBe(0);

    await fixture.whenStable();
    TestBed.flushEffects();

    expect(component.users()).withContext('User list after fetch')
      .toEqual(mockedUsers);
    expect(component.dataSource.data.length)
      .withContext('Data Source length after fetch').toBe(3);
    expect(component.dataSource.data).toEqual(mockedUsers);
  });

  it('should add a new user', async () =&gt; {
    const newUser = {
      id: 'id_4',
      username: 'user_name_4',
      email: 'test4@email.com'
    }

    await fixture.whenStable();
    await component.addUser();
    TestBed.flushEffects();

    expect(component.dataSource.data.length)
      .withContext('Data Source length after new user addition').toBe(4);
    expect(component.dataSource.data).toEqual([...mockedUsers, newUser]);
  });

  it('should remove user', async () =&gt; {
    await fixture.whenStable();
    await component.removeUser('id_2');
    TestBed.flushEffects();

    expect(component.dataSource.data.length)
      .withContext('Data Source length after user remove').toBe(2);
    expect(component.dataSource.data[1].id).toBe('id_3');
  });
});
</code></pre>
<h2 id="wrappingup">Wrapping Up</h2>
<p>I hope you found our stroll through <code>UsersComponent</code> testing as insightful as it was enjoyable. Testing,
especially with Angular's latest reactive features, doesn't have to be a pain in the neck. Actually, it's
quite the opposite—it's a smooth, straightforward, and enjoyable task.</p>
<p>We've seen how tools like <code>signal.set()</code>, <code>signal.update()</code>, and <code>effect()</code> can be game-changers, making our
tests not just necessary but a piece of cake. With the right approach and understanding, testing becomes
less of a chore and more of an exciting part of the development process.</p>
<p>Incorporating these new features into our testing routine has shown us that it's not just about ensuring our
components are up to snuff. It's about embracing a more dynamic and enjoyable workflow. The tests we've walked
through exemplify this mindset, proving that with Angular's advanced capabilities, we're fully equipped to
handle any reactive challenges that come our way, all with a smile.</p>
<p>So, let's shake off any old notions that testing is a drag. With Angular's reactive features, we're ushering
in a new era of testing that's efficient, effective, and, dare I say, fun :)</p>
<p><br>
<br></p>
<p>You can find access to the working application and tests on
<a href="https://github.com/jzolnowski/signal-testing">GitHub</a>.</p>]]></content:encoded>
            <category>angular</category>
            <category>testing</category>
        </item>
        <item>
            <title><![CDATA[The Progressive Journey of Change Detection in Angular]]></title>
            <link>https://devintent.com/blog/2024-08-19-the-progressive-journey-of-change-detection-in-angular.md</link>
            <guid isPermaLink="false">blog/2024-08-19-the-progressive-journey-of-change-detection-in-angular.md</guid>
            <pubDate>Mon, 19 Aug 2024 17:15:00 GMT</pubDate>
            <description><![CDATA[Angular change detection strategies evolution, detailing the transition from the default approach, OnPush and the upcoming Signals-based method, highlighting their impact on performance and application efficiency.]]></description>
            <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this article, we'll delve into the evolution of Angular's change detection strategies, exploring how
they've transformed our applications to be more responsive and effective. Angular has made significant strides
from the global
top-down <a href="https://angular.dev/best-practices/skipping-subtrees#an-event-is-handled-by-a-component-with-default-change-detection">Default</a>
approach to the widely
embraced <a href="https://angular.dev/best-practices/skipping-subtrees#an-event-is-handled-by-a-component-with-onpush">OnPush</a>
strategy. However, the introduction of Signals-based methodology, as outlined in
the <a href="https://angular.dev/guide/signals">Angular documentation</a> promises even more significant efficiency gains
in the change detection.</p>
<p>We'll explore the general inner workings of these strategies and analyze the performance gaps between them.
Furthermore, we'll speculate on the direction of Angular's change detection mechanisms.
So, let's get started!</p>
<h2 id="earlystage">Early Stage</h2>
<p>Change detection kicks off with any asynchronous browser events, and Angular relies on
the <a href="https://github.com/angular/angular/blob/main/packages/core/src/zone/ng_zone.ts#L96">NgZone</a> module to
observe these interactions. When an async event occurs, Angular triggers the change detection process,
traversing the <a href="https://github.com/angular/angular/blob/17.1.3/packages/core/src/render3/view_ref.ts">view</a>
tree from top to bottom. However, there's a contrast in how components are marked for update across various
strategies</p>
<h2 id="oldschoolchangedetection">Old-School Change detection</h2>
<p>Back in the early days, Angular's default change detection was like a noisy neighbor. It kept an eye on every
component, binding, and dependency whenever any event happened, leading to updates throughout the entire
application. This method works, but it often leads to performance issues in bigger apps because it tends to
perform checks even when everything has stayed the same.</p>
<h3 id="defaultchangedetectioninaction">Default Change Detection in Action</h3>
<p>With the default change detection strategy, Angular keeps an eye on all components unless the view is
explicitly <a href="https://github.com/angular/angular/blob/main/packages/core/src/render3/view_ref.ts#L200-L202">detached</a>:</p>
<pre><code class="typescript language-typescript">@Component({
  selector: 'detached',
  template: `Detached Component`
})
export class DetachedComponent {
  constructor(private cdr: ChangeDetectorRef) {
    cdr.detach();
  }
}
</code></pre>
<p>This strategy relies on the <code>CheckAlways</code> flag:</p>
<pre><code class="typescript language-typescript">let shouldRefreshView: boolean = !!(
  mode === ChangeDetectionMode.Global &amp;&amp; flags &amp; LViewFlags.CheckAlways
);
</code></pre>
<p>which ensures that Angular performs change detection on every view and executes
the <a href="https://github.com/angular/angular/blob/21741384f4/packages/core/src/render3/VIEW_DATA.md?plain=1#L90-L109">template function</a>
regardless of whether there are changes or not.</p>
<p>[<img src="/blog/change-detection-1/2-default-change-detection.png" alt="Default Change Detection" /></p>
<p>Click on component "H," which creates a domino effect throughout the entire app, even when it's just a false
alarm.</p>
<h2 id="arelaxedapproachtochangedetection">A Relaxed Approach to Change Detection</h2>
<p>To speed things up, Angular brought in the OnPush change detection strategy. The OnPush option has been around
just as long as the Default one. But to switch it on, developers needed to give their components a heads-up,
letting them know they wanted to use it. OnPush is like a more discerning detective, only springing into
action when a component's inputs change or events occur within that component. This optimized approach relied
on immutable states and reduced unnecessary checks, making our apps more straightforward and faster.
So, how does it work?</p>
<h3 id="unpackingtheonpushchangedetectionstrategy">Unpacking the OnPush Change Detection Strategy</h3>
<p>With the OnPush strategy, change detection takes a back seat unless a component is flagged as dirty:</p>
<pre><code class="typescript language-typescript">shouldRefreshView ||= !!(
  flags &amp; LViewFlags.Dirty &amp;&amp;
  mode === ChangeDetectionMode.Global &amp;&amp;
  !isInCheckNoChangesPass
);
</code></pre>
<p>To mark that a component as dirty, we can change an input property, emit an event, or manually
invoke the
<a href="https://github.com/angular/angular/blob/17.1.3/packages/core/src/render3/instructions/mark_view_dirty.ts#L24-L37">markForCheck()</a>
method, which marks the current view and all its folks up the family tree, all the way to the root view, for a
thorough check.</p>
<pre><code class="typescript language-typescript">@Component({
  selector: 'dirty',
  template: `Dirty Component`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DirtyComponent {
  constructor(private cdr: ChangeDetectorRef) {
    cdr.markForCheck();
  }
}
</code></pre>
<p>Angular then takes a tour of each dirty flagged view, executing the template function associated with its
respective component.</p>
<p><a href="/blog/change-detection-1/3-onpush-change-detection.png"><img src="/blog/change-detection-1/3-onpush-change-detection.png" alt="OnPush Change Detection" /></a></p>
<p>With OnPush, a click in the component "H" triggers an event through clicked component itself and its parents.</p>
<h2 id="signalsera">Signals Era</h2>
<p>From <a href="https://blog.angular.io/angular-v16-is-here-4d7a28ec680d">Angular v16</a> onwards, Angular has been moving
towards adopting <a href="https://github.com/angular/angular/discussions/49683">Signals</a>, altering front-end state
management. Unfortunately, as of <a href="https://blog.angular.io/introducing-angular-v17-4d7033312e4b">version 17</a>
, <a href="https://github.com/angular/angular/discussions/49682">Signal-based Components</a> remain under development,
delaying the full implementation of Signal-based change detection. In the meantime, Angular allowed us to
utilize the power of Signals and OnPush strategy to mark individual components as dirty. This Local Change
Detection ensures no more unnecessary checks for parent or child components designated as OnPush.</p>
<p>Additionally, Angular's recent advancements in event detection include
implementing <a href="https://github.com/angular/angular/pull/53521">signal inputs</a>, where input value updates occur
before the change detection cycle. This improvement ensures that change detection does not execute if the
template doesn't use the input. Moreover, changing the value bound to an input no longer triggers a refresh of
the parent view, as with the OnPush strategy.</p>
<h3 id="streamliningchangedetectionwithsignals">Streamlining Change Detection with Signals</h3>
<p>When we change the signal within a component's template using methods
like <a href="https://github.com/angular/angular/blob/f56b6555bd5d4498c0b2e4e406c220213d70e274/packages/core/src/signals/src/signal.ts#L30">set()</a>
or <a href="https://github.com/angular/angular/blob/f56b6555bd5d4498c0b2e4e406c220213d70e274/packages/core/src/signals/src/signal.ts#L36">update()</a>
, we kick off a chain reaction. This signal
<a href="https://github.com/angular/angular/blob/17.1.3/packages/core/primitives/signals/src/graph.ts#L292-L309">triggers a notification</a>
to the reactive live consumer within the view, marking it as dirty through the
<a href="https://github.com/angular/angular/blob/main/packages/core/src/render3/util/view_utils.ts#L233C17-L249">markAncestorsForTraversal()</a>.
But it doesn't stop there – it also marks all ancestors, up to the root, with the <code>HasChildViewsToRefresh</code>
flag. If the view is marked as dirty, the template function is called, and the current value is returned.</p>
<pre><code class="typescript language-typescript">shouldRefreshView ||= !!(
  consumer?.dirty &amp;&amp; consumerPollProducersForChange(consumer)
);
</code></pre>
<p>However, if the view is marked with the <code>HasChildViewsToRefresh</code> flag, there's no need to bother with the
template function. It just takes a shortcut, skipping the template function and diving right into checking the
children. This clever move helps Angular avoid unnecessary tasks, operations, calculations, and comparisons,
ensuring everything runs smoothly and efficiently.</p>
<pre><code class="typescript language-typescript">if (shouldRefreshView) {
  refreshView(tView, lView, tView.template, lView[CONTEXT]);
} else if (flags &amp; LViewFlags.HasChildViewsToRefresh) {
  detectChangesInEmbeddedViews(lView, ChangeDetectionMode.Targeted);
  const components = tView.components;
  if (components !== null) {
    detectChangesInChildComponents(lView, components,
      ChangeDetectionMode.Targeted);
  }
}
</code></pre>
<h2 id="thefuture">The future</h2>
<p>Looking ahead, Angular seems set to embrace a Signals-based Change Detection system fully. It's like getting a
superpower to track changes with laser precision, eliminating the need for NgZone to manage execution context
completely. By going zone-less, developers will have better, fine-grained control over change detection,
enabling a more efficient and focused approach and optimizing performance even further by running Change
Detection only when necessary. This approach will fundamentally change how Angular tracks and handles changes,
allowing developers to pinpoint precisely where and when updates should occur.</p>
<p>However, transitioning to this new paradigm requires developers to understand signals better to harness their
full potential. Despite the learning curve, the performance and scalability gains make it a worthwhile
investment for projects aiming for optimal performance.</p>
<p>As Angular continues to evolve, developers must stay updated with these advancements in Change detection
strategies.</p>
<p>The journey from the default strategy through OnPush and towards Signals-based Change Detection highlights
Angular's commitment to enhancing performance and scalability. By adopting these advanced strategies,
developers are empowered to build functional and exceptionally performant Angular applications.</p>
<p><a href="/blog/change-detection-1/4-signals-change-detection.png"><img src="/blog/change-detection-1/4-signals-change-detection.png" alt="Signal-based Change Detection" /></a></p>
<p>In the world of Local Change Detection, a change in component "F" gets the attention it deserves without
redundantly checking parent or component children.</p>
<h2 id="conclusions">Conclusions</h2>
<p>In conclusion, the evolution of change detection in Angular reflects a constant effort to refine and optimize
performance. Embracing these advancements empowers developers to create Angular applications that are not just
functional but also highly performant, ensuring a seamless user experience across a wide range of
applications. Given the progress that has been made in this regard, I look forward with optimism to further
releases of the Angular framework.</p>
<p><br>
<br></p>
<p>The principle of change detection can be viewed in
this <a href="https://github.com/jzolnowski/deep-dive-into-change-detection">GitHub application</a>.</p>]]></content:encoded>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Build time benchmarking using Angular CLI]]></title>
            <link>https://devintent.com/blog/2023-09-26-build-time-benchmarking-using-angular-cli.md</link>
            <guid isPermaLink="false">blog/2023-09-26-build-time-benchmarking-using-angular-cli.md</guid>
            <pubDate>Tue, 26 Sep 2023 12:30:00 GMT</pubDate>
            <description><![CDATA[Build time benchmarks of various configurations in the Angular CLI.]]></description>
            <content:encoded><![CDATA[<h1 id="buildtimebenchmarkofmonolithicapplicationbuildusingangularcli">Build time benchmark of monolithic application build using Angular CLI</h1>
<p>In this article, we’ll take a look at the impact of different build options of
the Angular CLI on the build time of a monolithic application. Building is
usually on a critical path of the continuous integration (CI) pipeline—that is,
any changes to build duration impact the total CI time. The Angular team makes
a few build optimizations available for developers, and in this post, we’ll
take a look at their impact.</p>
<h2 id="measurements">Measurements</h2>
<p>To make the data reproducible and relevant, I’ll run the test builds with
CircleCI. Using external servers for the build isolates the measurement from my
local environment. At the same time, the results come from machines that others
are using for building as well.</p>
<p>The key measurement I’ll pay attention to is the time needed to run the <code>npm
run build</code> command:</p>
<p><a href="/blog/ng-build-monolithic/1-build-time.jpg"><img src="/blog/ng-build-monolithic/1-build-time.jpg" alt="Screen shot of build summary at CircleCI" /></a></p>
<p>At this level, I expect to see the most direct results of the optimization we
use. If we manage to cut the build time in half, then we should see this impact
here.</p>
<p>Another value to consider is the time of a whole build job. This will be
especially important for optimizations that come with positives and negatives:
for example, caching can speed up some operations, but part of the gain will be
eaten by the downloading and uploading cache.</p>
<p><a href="/blog/ng-build-monolithic/2-job-time.jpg"><img src="/blog/ng-build-monolithic/2-job-time.jpg" alt="Screen shot of job result at CircleCI" /></a></p>
<p>The last measurement for us to consider is the overhead: the difference between
build script and build job. It will contain everything that is done before or
after the build: restoring the cache, installing dependencies, saving the
cache. With this number, we should see clearly the downsides of some
optimization.</p>
<p>I’ll repeat each test build 5 times under the same circumstances and use the
average of the measurements as the measurement value. In this way, I’ll be able
to reduce a bit of random noise in the data without turning it into a full
scientific experiment.</p>
<h2 id="applicationstructure">Application structure</h2>
<p>As a benchmark, I’m using the build time of a simple application generated and
built with the Angular CLI. The application models the real world complexity by
including 1000 components. This approach is inspired by <a href="https://github.com/nrwl/nx-incremental-large-repo">Nrwl’s Angular
benchmark</a>. Each component
is very simple:</p>
<p><code>src/app/component1/component1.component.ts</code>:</p>
<pre><code class="js language-js">import { Component } from '@angular/core';

@Component({
  selector: 'app-component1',
  templateUrl: './component1.component.html',
  styleUrls: ['./component1.component.css']
})
export class Component1Component {

}
</code></pre>
<p><code>src/app/component1/component1.component.html</code>:</p>
<pre><code class="html language-html">&lt;p&gt;component1 works!&lt;/p&gt;
</code></pre>
<p>And the whole application just displays each component one after another:</p>
<p><a href="/blog/ng-build-monolithic/3-app-interface.png"><img src="/blog/ng-build-monolithic/3-app-interface.png" alt="Application screenshot" /></a></p>
<p>The biggest blind spot is the lack of third-party libraries. This is something
that almost all real-world applications do, but including it in the benchmark
would tie the results to the set of libraries used in the example application.</p>
<h2 id="buildoptions">Build options</h2>
<p>In my test, I’m measuring the build time in the following setups.</p>
<h3 id="baseline">Baseline</h3>
<p>This is the standard build as it’s generated by Angular CLI. Important features are as follows:</p>
<ul>
<li>it uses webpack under the hood</li>
<li>it lacks <code>ng cache</code> for CI—so each build during CI starts from scratch</li>
<li>the build job provides cache for <code>npm install</code></li>
</ul>
<h3 id="esbuild">esbuild</h3>
<p>esbuild is a promising bundler with much better performance than Webpack:
according to its own website, it’s up to 100 times faster. Because of its
speed, since version 14, the Angular team has provided an experimental builder
based on esbuild. It was recently improved in version 15. It can be turned on
easily, with just 1 line change in <code>angular.json</code>:</p>
<pre><code>       "architect": {
         "build": {
-          "builder": "@angular-devkit/build-angular:browser",
+          "builder": "@angular-devkit/build-angular:browser-esbuild",
           "options": {
</code></pre>
<p>Note! So far, this change affects only the build—the development server is
still using Webpack. This is likely to change in version 16.</p>
<h3 id="ngcaching">ng caching</h3>
<p>For local builds, Angular CLI caches build results to save time on reruns. By
default, this feature is turned off for CI. To use caching during CI, we need
two changes:</p>
<ul>
<li>changing the cache configuration from local-only, and</li>
<li>reading and saving the cache during CI.</li>
</ul>
<p>You can turn on caching with two commands:</p>
<pre><code>ng config cli.cache.environment all
ng cache enable
</code></pre>
<p>Managing cache files for CI will require changes in configuration. You can find my change for CircleCI <a href="https://github.com/DevIntent/ng-build-monolithic/commit/37286152db9a2a114100181a92cc0ce7e606388d#diff-78a8a19706dbd2a4425dd72bdab0502ed7a2cef16365ab7030a5a0588927bf47">here</a>.</p>
<h3 id="typescript5">TypeScript 5</h3>
<p>TypeScript 5 promises up to 10% improvement for the build time. It’s not yet
available for Angular applications, but it’s on track to come in version 16.
For my tests, I’m updating Angular to pre-release version <code>16.0.0-next.4</code>.</p>
<h2 id="data">Data</h2>
<p>The builds I’ve run measured as follows:</p>
<p>|                  | npm run build (s) | Build job (s) | Overhead  (s) |
|------------------|-------------------|---------------|---------------|
| baseline         | 57.8              | 92            | 34.2          |
| esbuild          | 14.4              | 50.2          | 35.8          |
| hot build cache  | 31.4              | 67            | 35.6          |
| cold build cache | 66.8              | 104.2         | 35.6          |
| TypeScript 5     | 55                | 84.8          | 29.8          |</p>
<p>The baseline time needed to complete <code>npm run build</code> was on average 57.8s. The
biggest improvement we can see is with switching to <code>esbuild</code>: it becomes 4
times faster and takes only 14.4s to build. Both builds have very similar
overhead. With esbuild, the build job takes 56% of time that was needed in the
baseline case—an excellent improvement.</p>
<p>Another optimization—caching of the Webpack build—looks very promising as well.
Because there are more files cached, I expected a clear increase in the
overhead. It went from 34.2s to 35.6s, but this difference could be
statistically insignificant. Caching of the build has two effects:</p>
<ul>
<li>speed increases when cache is “hot”—with files already in place, the build
job finishes in 31.4s instead of 57.8s.</li>
<li>speed decreases when the cache is “cold”—most likely, the build takes more
time because there are way more files to be written on the disk. Build went
up from 57.8s to 66.8s.</li>
</ul>
<p>Lastly, an interesting case is updating to TypeScript 5. The time needed to
complete the npm run build lowered slightly from 57.8s to 55.5s. At the same
time, the overall build job took 84.5s instead of 92s, which is a better
improvement than the build script alone. This could be explained by the more
efficient installation—maybe TypeScript 5 or other v16 dependencies are faster
to install.</p>
<h2 id="conclusions">Conclusions</h2>
<ol>
<li>Check out esbuild—if it won’t introduce regressions to your code, you can
immediately enjoy faster builds!</li>
<li>If esbuild doesn't work in your case, try enabling caching for Webpack on
CI.</li>
<li>Don’t hold your breath for the speed increase that comes with switching to
TypeScript 5.</li>
</ol>
<h2 id="links">Links</h2>
<p>You can find our test application <a href="https://github.com/DevIntent/ng-build-monolithic">here</a>.</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in web development, including
framework migration and updates. Check out our <a href="https://www.devintent.com/">offerings</a>
or <a href="https://www.devintent.com/contact-us">reach out</a>.</p>]]></content:encoded>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Angular v16 Features And Improvements We’re Excited About]]></title>
            <link>https://devintent.com/blog/2023-05-01-angular-v-16-features-and-improvements-we-re-excited-about.md</link>
            <guid isPermaLink="false">blog/2023-05-01-angular-v-16-features-and-improvements-we-re-excited-about.md</guid>
            <pubDate>Mon, 01 May 2023 12:30:00 GMT</pubDate>
            <description><![CDATA[Some of our favorite improvements coming in the new release.]]></description>
            <content:encoded><![CDATA[<p>With Angular version 15 released on November 16 and the next version expected
before summer, let’s see what upcoming changes look the most exciting.</p>
<h2 id="newbundlers">New bundlers</h2>
<p>A lot of optimization in Angular happens at build time. For this to be
possible, Angular provides a custom compiler. The compiler takes care of things
specific to Angular: ahead-of-time compilation or catching issues in the
templates. The build is complex, but Angular CLI provides you all the
configuration you need. Under the hood, Angular CLI uses Webpack, a well
established bundler with a very active community.</p>
<p>While Webpack is the most popular bundler available, it has its
downsides—especially speed when it builds larger codebases. Whereas Webpack is
in active development and there are incremental improvements in speed between
versions, there are other bundlers that take a fundamentally different approach
and boast greatly improved speeds. A slower bundler causes slower builds, and
this can negatively affect productivity in the project at all stages—from
development to continuous integration.</p>
<p>To allow the Angular community to enjoy the benefits of faster bundlers,
the Angular CLI has offered an experimental esbuild configuration since
<a href="https://blog.angular.io/angular-v14-is-now-available-391a6db736af#43b4">version 14</a>,
and it’s been
<a href="https://dev.to/fabiobiondi/angular-esbuild-2540-build-time-3mfa">reported</a> to
lower build time by up to 44%. The
<a href="https://angular.io/guide/roadmap#investigate-modern-bundles">Roadmap</a> also
lists further investigation and progress toward making the improved builds
stable, so we hope to see continued speed increases coming to applications
built with the Angular CLI.</p>
<h2 id="furtherdevelopmentoftheimagedirective">Further development of the image directive</h2>
<p>Due to their size, images have a disproportionately large impact on web
performance. Managing them well is especially important for the mobile user
experience for a couple of reasons:</p>
<ul>
<li>When on the go, mobile users can experience slower and less stable internet
connections or may be charged for the data transfer.</li>
<li>Because of their often smaller screens, images on mobile devices don’t need
the same high resolution as desktop users.</li>
</ul>
<p>Managing images well can be difficult, especially in applications rendered on
the client side. Improvements to image management for both users and developers
are welcome. So it’s promising to
<a href="https://angular.io/guide/roadmap#improvements-in-the-image-directive">see on the roadmap</a>
further enhancements to <a href="https://angular.io/api/common/NgOptimizedImage">NgOptimizedImage</a>
that the Angular team plans to add to the framework.</p>
<h2 id="debuggingdependencyinjection">Debugging dependency injection</h2>
<p>In my AngularJS development work, I often use this snippet to access my
services from the dev tools console:</p>
<pre><code class="js language-js"> angular.element(document.body).injector().get('serviceName')
</code></pre>
<p>I find it very helpful to be able to test my methods interactively in the
browser as I develop them. For that reason, I’m looking forward to seeing the
updates in Angular DevTools that will bring
<a href="https://angular.io/guide/roadmap#introduce-dependency-injection-debugging-apis">dependency injection debugging APIs</a>.</p>
<h2 id="upcomingchanges">Upcoming changes</h2>
<p>Those are the changes I’m the most excited about in that are on the way to
becoming part of Angular v16. You can find the list of priorities for the
current development in the project’s <a href="https://angular.io/guide/roadmap">roadmap</a>.</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in Angular development, testing,
and software quality. If you'd like to chat about how we can help you, please
contact us at sales@devintent.com.</p>]]></content:encoded>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[How To Speed Up Your Web Application With Brotli Compression]]></title>
            <link>https://devintent.com/blog/2023-04-28-how-to-speed-up-your-web-application-with-brotli-compression.md</link>
            <guid isPermaLink="false">blog/2023-04-28-how-to-speed-up-your-web-application-with-brotli-compression.md</guid>
            <pubDate>Fri, 28 Apr 2023 21:00:00 GMT</pubDate>
            <description><![CDATA[Overview of Brotli—compression optimized for web documents.]]></description>
            <content:encoded><![CDATA[<p>Lossless compression is a great way of lowering the amount of data that users
have to download to access your application. Minimizing data transfer improves
several critical metrics of your application:</p>
<ul>
<li>The load time of the application will be lowered, improving your users’
overall experience—this is important for users with a slow internet
connection, which is critical for applications primarily used on mobile
devices.</li>
<li>The amount of data transferred out of your servers—which can impact your
cloud or data center cost, depending on the use case and hosting setup.</li>
</ul>
<h2 id="introducingbrotli">Introducing Brotli</h2>
<p>Currently, Brotli is the most efficient compression algorithm for website code.
According to <a href="https://www.opencpu.org/posts/brotli-benchmarks/">benchmarks</a>,
HTML, CSS, and JS files are more than 10% smaller when compressed with Brotli
compared to traditional GZIP. Brotli offers better results and is supported
across all modern browsers—in most cases, it should be the go-to solution for
compressing website data.</p>
<h2 id="whoseresponsibilityisittocompressthefiles">Whose responsibility is it to compress the files?</h2>
<p>Isn’t compression something done automatically by your hosting provider? It can
be, but there are few downsides to depending on a third party to compress the
application:</p>
<ul>
<li>Compressing files is fast, but doing it when users request the files will
introduce unnecessary delay. It’s safe to assume this is what happens when
you are using compression support provided by hosting.</li>
<li>You are limited to what is provided by the hosting company. GZIP may be the
only option, which will produce files bigger than those compressed with
Brotli.</li>
</ul>
<p>As an alternative to automatic compression provided by hosting, you can
generate <code>.br</code> files every time you build your app for deployment. In this way,
you can ensure that <code>.br</code> files are up to date and ready on the server when
needed—and that the user experience will not be affected by slow compression.
Depending on your hosting setup, there will be different ways to configure your
server to use <code>.br</code> files for user agents that accept Brotli.</p>
<h2 id="howtosetupbrotliinyourangularbasedapplication">How to set up Brotli in your Angular-based application</h2>
<p>If you are interested in using Brotli for your AngularJS or Angular application, our team recently
published a guide on the XLTS.dev blog
<a href="https://xlts.dev/blog/2023-01-25-how-to-efficiently-serve-an-angularjs-app-using-brotli">here</a>.</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in Angular development, testing,
and software quality. If you'd like to chat about how we can help you, please
contact us at sales@devintent.com.</p>]]></content:encoded>
            <category>perf</category>
            <category>ux</category>
        </item>
        <item>
            <title><![CDATA[Highlighting the Release of Angular v15]]></title>
            <link>https://devintent.com/blog/2023-01-23-release-of-angular-15.md</link>
            <guid isPermaLink="false">blog/2023-01-23-release-of-angular-15.md</guid>
            <pubDate>Mon, 23 Jan 2023 21:00:00 GMT</pubDate>
            <description><![CDATA[What's new in the latest Angular release.]]></description>
            <content:encoded><![CDATA[<p>On November 16, 2022, the Angular team published version 15 of the framework.
Let’s look at what changes are available in the newest version.</p>
<h2 id="standalonecomponents">Stand-alone Components</h2>
<p>Stand-alone components are components that are defined outside any NgModule.
They are providing a simplified API that reduces the boilerplate necessary to
define a component. Stand-alone components, directives and pipes integrate
nicely with the existing Angular landscape. They</p>
<ul>
<li>can be used in traditional modules,</li>
<li>can import modules to reuse existing code, and</li>
<li>can even be used to bootstrap an application.</li>
</ul>
<p>You can learn more in the <a href="https://angular.io/guide/standalone-components">official guide</a>.</p>
<h2 id="newtreeshakeableapis">New Tree-shakeable APIs</h2>
<p>Along with the stand-alone components, some services are available in a lighter
form that works better with tree shaking. These APIs will help you keep your
reusable code smaller—instead of including entire modules with all the features
you don’t use. Thus, you can pick only the things that you need. All the rest
is dropped during the build process with tree shaking.</p>
<h3 id="router">Router</h3>
<p><a href="https://angular.io/api/router/provideRouter"><code>provideRouter</code></a> allows you to
pick various <a href="https://angular.io/api/router/RouterFeatures">features</a> of the
router to optimize your build size:</p>
<pre><code class="ts language-ts">type RouterFeatures = PreloadingFeature | DebugTracingFeature | InitialNavigationFeature | InMemoryScrollingFeature | RouterConfigurationFeature;
</code></pre>
<h3 id="httpclient"><code>HttpClient</code></h3>
<p>Similarly,
<a href="https://angular.io/api/common/http/provideHttpClient"><code>provideHttpClient</code></a>
allows you to choose from the following
<a href="https://angular.io/api/common/http/HttpFeatureKind">features</a>:</p>
<pre><code class="ts language-ts">enum HttpFeatureKind {
  Interceptors
  LegacyInterceptors
  CustomXsrfConfiguration
  NoXsrfProtection
  JsonpSupport
  RequestsMadeViaParent
}
</code></pre>
<h2 id="imagedirective">Image Directive</h2>
<p>The <a href="https://angular.io/api/common/NgOptimizedImage">NgOptimizedImage</a> directive
has become stable. The directive enforces best practices in loading images,
improving the page's load performance.</p>
<p>Together with an <a href="https://angular.io/api/common/ImageLoader">ImageLoader</a>, it
can be used to generate the appropriate resource URL for a given image file.
You can learn more about this (including plans for the future) on the Chrome blog in
<a href="https://developer.chrome.com/blog/angular-image-directive/">Optimizing Images with the Angular Image Directive</a>.</p>
<h2 id="directivecompositionapi">Directive Composition API</h2>
<p>As of version 15, Angular allows you to reuse existing directives as building
blocks when creating new directives or components. With
<a href="https://angular.io/api/core/Directive#hostDirectives"><code>hostDirectives</code></a>, you
can add directives to your host element, effectively combining a few directives
into one. It is similar to how some languages support multiple inheritance in
classes. You can learn more, including performance implications, in the
<a href="https://angular.io/guide/directive-composition-api">official guide</a>.</p>
<h2 id="migrationofangularmaterialcomponentstonewcomponentsbasedonmdc">Migration of Angular Material Components to new components based on MDC</h2>
<p>The Angular team migrated the Angular Material components to reuse
framework-independent code available in <a href="https://github.com/material-components/material-components-web">Material Design Components for the
Web</a> ("MDC"). This
results in an improvement in how close the components are following the
<a href="https://m2.material.io/">Material Design 2</a> specification; in the future, it will allow for switching styling
to <a href="https://m3.material.io/">Material Design 3</a>.</p>
<p>If you overwrite many styles in Angular Material components, be prepared for
a large amount of refactoring. Migration requires changing the internal DOM structure and
styling of the components, as well as some changes to the external API. You can
learn more about what was changed and what updates are needed in the application in
<a href="https://github.com/angular/components/blob/main/guides/v15-mdc-migration.md">the MDC migration guide</a>.
The previous components are deprecated, but are still available to smoothen the
migration.</p>
<h2 id="deprecatedfeatures">Deprecated Features</h2>
<p>Besides new additions to the framework, a few things were deprecated and will
be removed in a future version. If you are using any of the features below in
your apps, you should start making plans to move away from them.</p>
<h3 id="angularflexlayout"><code>@angular/flex-layout</code></h3>
<p>The Angular team will stop releasing new versions of <code>@angular/flex-layout</code> — but
they will publish security and browser compatibility updates for the following
year. Instead, there are two alternatives available in pure CSS:</p>
<ul>
<li><a href="https://developer.mozilla.org/docs/Web/CSS/CSS_Flexible_Box_Layout">flexbox</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/CSS/grid">grid</a></li>
</ul>
<p>You can find the official recommendations in the article on the Angular blog in
<a href="https://blog.angular.io/modern-css-in-angular-layouts-4a259dca9127">Modern CSS in Angular: Layouts</a>.</p>
<h3 id="providedinanyandprovidedinngmodule"><code>providedIn: any</code> and <code>providedIn: NgModule</code></h3>
<p>Both options were decided to be uncommon and confusing enough to be deprecated.
If you use them, check the official <a href="https://blog.angular.io/angular-v15-is-now-available-df7be7f2f4c8#05d0">release
announcement</a>
to see the way forward. We will no longer be able to register services in lazy
loaded modules using <code>providedIn: NgModule</code>, but only by using an old fashion
technique—using the <code>NgModule.providers</code> array.</p>
<h2 id="updateguide">Update Guide</h2>
<p>As always, you can find relevant update instructions in the <a href="https://update.angular.io/">Angular Update
Guide</a>.</p>
<h2 id="angularv1510update">Angular v15.1.0 update</h2>
<h3 id="selfclosingtagsfornonnativehtmlelements">Self-closing Tags for Non-native HTML Elements</h3>
<p>Starting with version 15.1.0, Angular supports self-closing tags for non-native
HTML elements (including Angular components). This will allow decluttering your
templates by omitting closing tags. For example, you can replace
<code>&lt;my-component&gt;&lt;/my-component&gt;</code> with just <code>&lt;my-component /&gt;</code>.</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in web development, including
framework migration and updates.  Check out our <a href="https://www.devintent.com">offerings</a> or
<a href="https://www.devintent.com/contact-us">reach out</a>.</p>]]></content:encoded>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[A Better Way to Share Components]]></title>
            <link>https://devintent.com/blog/2023-01-20-better-way-to-share-components-in-angular.md</link>
            <guid isPermaLink="false">blog/2023-01-20-better-way-to-share-components-in-angular.md</guid>
            <pubDate>Fri, 20 Jan 2023 21:00:00 GMT</pubDate>
            <description><![CDATA[A way to replace shared modules with a Single Component Angular / AngularJS Module.]]></description>
            <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In order for large web applications to be scalable, they are usually broken up into a number of modules.
Very often, we need to reuse individual <a href="https://angular.io/api/core/Component">Components</a>,
<a href="https://angular.io/api/core/Pipe">Pipes</a>, and <a href="https://angular.io/api/core/Directive">Directives</a> in many
places of our application. Duplicating code for repetitious items is not the best practice. This is why we
usually create a shared module, registering all reusable and generic elements of our application there, so
that we can use them later in any feature module.</p>
<p>It makes sense to create a global place for all reusable items. Unfortunately, it also has disadvantages.</p>
<p>As the project evolves and the demand for more and more reusable elements increases, the shared module can grow significantly. We
must be aware. that in order to use one component, we have to import all the elements registered in the shared
module, which becomes inefficient.</p>
<h2 id="sharedmodules">Shared Modules</h2>
<p><a href="/blog/scam-1/shared.jpg"><img src="/blog/scam-1/shared.jpg" alt="Shared Modules Image" /></a></p>
<p>Let's look at the situation from a <a href="https://github.com/jzolnowski/angularjs-scam">sample application</a>.</p>
<p><a href="/blog/scam-1/folder-structure.png"><img src="/blog/scam-1/folder-structure.png" alt="Angular Icon" /></a></p>
<p>We have defined 2 modules, <code>AppModule</code> and <code>UsersModule</code>. They both use <code>ButtonComponent</code>.
Additionally, <code>UsersModule</code> uses a <code>FilteredListComponent</code> with users, which is also a reusable component - it
accepts any shape of a single list element. We put both reusable components in a shared module.</p>
<pre><code class="typescript language-typescript">export module SharedModule {
  export const name: string = 'Shared';

  angular
    .module(SharedModule.name, […])
    .component(FilteredListComponent.componentName, FilteredListComponent.componentConfig)
    .component(ButtonComponent.componentName, ButtonComponent.componentConfig);
}
</code></pre>
<pre><code class="typescript language-typescript">angular.module('AppModule', [SharedModule.name])
</code></pre>
<pre><code class="typescript language-typescript">angular.module(UsersModule.name, [SharedModule.name]);
</code></pre>
<p>As we can see, <code>AppModule</code> needs to import the entire <code>SharedModule</code> to access the reusable <code>ButtonComponent</code>.</p>
<p>Now imagine that our application defines hundreds of such reusable elements. We won't need all of
these elements in every module. A Single Component Angular Module ("SCAM") comes to the rescue.</p>
<h2 id="whatisscam">What is SCAM?</h2>
<p>Single Component Angular Module, or SCAM for short, is the concept of creating small, encapsulated and
reusable AngularJS / Angular modules with only one <code>Component</code> (or <code>Directive</code>, or <code>Filter / Pipe</code>).</p>
<h2 id="scaminaction">SCAM in action</h2>
<p>Instead of a global module with elements shared between the entire application, we can define modules for each
of the elements:</p>
<pre><code class="typescript language-typescript">export module ButtonModule {
  export const name: string = 'ButtonModule';
  angular
    .module(ButtonModule.name, ['ngMaterial'])
    .component(ButtonComponent.componentName, ButtonComponent.componentConfig);
}
</code></pre>
<pre><code class="typescript language-typescript">export module FilteredListModule {
  export const name: string = 'FilteredListModule';
  angular
    .module(FilteredListModule.name, ['ngMaterial'])
    .component(FilteredListComponent.componentName, FilteredListComponent.componentConfig);
}
</code></pre>
<p>We can see that we can easily build a module architecture that provides only the required elements for given
views, without the need to import unused <code>Components</code>, <code>Filters / Pipes</code>, or <code>Directives</code>.</p>
<pre><code class="typescript language-typescript">export module UsersModule {
  angular.module(UsersModule.name, [ButtonModule.name, FilteredListModule.name]);
}
</code></pre>
<pre><code class="typescript language-typescript">module AppModule {
  angular.module('AppModule', [ButtonModule.name]);
}
</code></pre>
<h2 id="scamandrefactoring">SCAM and Refactoring</h2>
<p>Note that the SCAM-based architecture allows you to refactor the code quickly. If you reach the point where
<code>UsersModule</code> no longer requires the use of buttons, you would need to delete the dependency to remove it.
Adopting this method gives you a considerable advantage over shared modules when migrating from AngularJS
to Angular. You can now migrate application sections more efficiently by breaking them into independent
but valuable parts because you depend on only one component and not on sets of components.</p>
<h2 id="scamandstandalonecomponents">SCAM and Standalone Components</h2>
<p>Another point I would like to make is the similarity with Standalone Components. Let's recall that since
Angular version 14, we can write code without using Angular modules. Having SCAM defined:</p>
<pre><code class="typescript language-typescript">import {UpperCasePipe} from '@angular/common';

@Component({
  selector: 'app-button',
  template: `
    &lt;button mat-button&gt;Sample Button&lt;/button&gt;
  `,
})
export class ButtonComponent {
  // your component's code
}

@NgModule({
  declarations: [ButtonComponent],
})
export class ButtonComponentModule {
}
</code></pre>
<p>we can easily migrate to Standalone Components without worrying that we messed up something in other parts
of the application, since it is an independent piece of code.</p>
<pre><code class="typescript language-typescript">@Component({
  standalone: true,
  selector: 'app-button',
  template: `
    &lt;button mat-button&gt;Sample Button&lt;/button&gt;
  `,
})
export class ButtonComponent {
  // your component's code
}
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>Using common SCAMs creates some overhead because you have more modules and more imports in your feature
modules. On the other hand, you get smaller, better encapsulated modules that are less
cumbersome to maintain. SCAM-based code refactoring is much more straightforward and less time-consuming.
Even more complicated migrations from AngularJS to Angular will be simpler to implement, and applying
Standalone Components in the project will reduce the risk of bugs.</p>
<p>As I mentioned <strong>SCAM is a concept, not imposed by a specific framework or API version. So it can be used
wherever we are dealing with shared components</strong>.</p>
<p>The source code for this example is in <a href="https://github.com/jzolnowski/angularjs-scam">this GitHub repository</a>.</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.
Check out our <a href="https://www.devintent.com">offerings</a> or <a href="https://www.devintent.com/contact-us">reach out</a>.</p>]]></content:encoded>
            <category>angularjs</category>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Ensuring An Easier Migration Path With Framework-agnostic Libraries Using Axios]]></title>
            <link>https://devintent.com/blog/2023-01-11-ensuring-an-easier-migration-path-with-framework-agnostic-libraries-using-axios.md</link>
            <guid isPermaLink="false">blog/2023-01-11-ensuring-an-easier-migration-path-with-framework-agnostic-libraries-using-axios.md</guid>
            <pubDate>Wed, 11 Jan 2023 09:20:00 GMT</pubDate>
            <description><![CDATA[The benefits of using framework-agnostic libraries when migrating to newer technologies.]]></description>
            <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>How often do you use data in your applications? I do this in every application I implement.</p>
<p>We typically fetch data using an HTTP client in a service. Sometimes, the HTTP client is even used
directly in a component, which is not very good practice. But this article is not about good and bad practices,
so let’s move on.</p>
<p>So inside the <code>Service</code>, we can inject another <code>Service,</code> for
example, <a href="https://docs.angularjs.org/api/ng/service/$http">$http</a> (AngularJS),
or <a href="https://angular.io/api/common/http/HttpClient">HttpClient</a> (Angular). The built-in HTTP Angular services
are outstanding.</p>
<h3 id="whyareweusingthem">Why are we using them?</h3>
<p>When AngularJS was written, the browsers didn't have a
<a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch">fetch()</a> API. Well, now times have changed, and
they do!</p>
<p>So why don’t we use <code>fetch()</code> instead of the HTTP client? You might think:</p>
<blockquote>
  <p>Well, it’s just easier to use the build-in HTTP client</p>
</blockquote>
<p>or simply:</p>
<blockquote>
  <p>Why should I use something else if I get an HTTP client with the framework I’m using?</p>
</blockquote>
<p>Think about <a href="https://reactjs.org/">React</a>, <a href="https://vuejs.org/">Vue.js</a>, other web frameworks or just plain
JavaScript. What are they using? Well, they use the <code>fetch()</code> API. And if they need something more
complex and involved, they can use things like <a href="https://axios-http.com/">Axios</a> - a promise-based HTTP client
for Node.js and the browser.</p>
<p><a href="/blog/axios-1/axios-logo.png"><img src="/blog/axios-1/axios-logo.png" alt="Axios Logo" /></a></p>
<h2 id="axiosinaction">Axios in action</h2>
<p>Let’s look at an AngularJS and Angular-based application that does not use the built-in HTTP client.
Here’s what it might look like in AngularJS:</p>
<pre><code class="typescript language-typescript">import axios, {AxiosResponse} from 'axios';
import {User} from '../users.module';

export class UsersService {
  loadAllUsers(): Promise&lt;AxiosResponse&lt;User[]&gt;&gt; {
    return axios.get('assets/mocks/users.json');
  }
}
</code></pre>
<p>and Angular:</p>
<pre><code class="typescript language-typescript">import {Injectable} from '@angular/core';
import axios, {AxiosResponse} from 'axios';
import {User} from '../users.module';

@Injectable({
  providedIn: 'root'
})
export class UsersService {
  loadAllUsers(): Promise&lt;AxiosResponse&lt;User[]&gt;&gt; {
    return axios.get('assets/mocks/users.json');
  }
}
</code></pre>
<p>So, as we can see, we define a service called <code>UsersService</code> in both cases. And you’ll notice we're pulling in
Axios. We can also see a method named <code>loadAllUsers()</code>. That method invokes Axios APIs, which return
a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a> which
will eventually resolve with the returned data.</p>
<p>The code examples above are straightforward and very similar. But notice what you do not see as well. It’s
not just the HTTP service switched out for Axios in this case.</p>
<p>Where are the <a href="https://rxjs.dev/guide/observable">Observables</a> in the Angular-based code example?</p>
<p>Now <a href="https://rxjs.dev/guide/overview">RxJS</a> is extremely powerful and valuable. But do you ever feel
weighed down when you’re getting into a new technology? Maybe you feel like:</p>
<blockquote>
  <p>I don’t need this yet</p>
  <p>I shouldn't need to learn all of these concepts to understand a basic example.</p>
</blockquote>
<p>Well, with this, you don’t have to. With <code>fetch()</code> and Axios, you can jump right into using Promises. But
there is an even more significant advantage that we may overlook at first glance.</p>
<h2 id="migrationfromangularjstoangular">Migration from AngularJS to Angular</h2>
<p>As some of you know, migrating an AngularJS-based application to Angular is a real challenge. Interfaces and
APIs are so <strong>different</strong> that it's safe to say that they are two completely different frameworks. The way the
HTTP client is used in the two mentioned versions is also completely different.</p>
<p>Here is an example of how we use the built-in <code>$http</code> service in AngularJS:</p>
<pre><code class="typescript language-typescript">import {IHttpResponse, IHttpService} from 'angular';
import {User} from '../users.module';

export class UsersService {
  constructor(private $http: IHttpService) {
  }

  loadAllUsers(): Promise&lt;IHttpResponse&lt;User[]&gt;&gt; {
    return this.$http.get('assets/mocks/users.json');
  }
}
</code></pre>
<p>And here is an example of using the built-in <code>HttpClient</code> service for Angular:</p>
<pre><code class="typescript language-typescript">@NgModule({
  imports: [HttpClientModule],
  ...
})
export class UsersModule {
}
</code></pre>
<pre><code class="typescript language-typescript">import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {User} from '../users.module';

@Injectable({
  providedIn: 'root'
})
export class UsersService {

  constructor(private http: HttpClient) {
  }

  loadAllUsers(): Observable&lt;User[]&gt; {
    return this.http.get&lt;User[]&gt;('assets/mocks/users.json');
  }
}
</code></pre>
<p>Maybe we should consider using a library that is independent of the framework used and guarantees a consistent
API, whether in AngularJS, Angular or even React. Is Axios worth using? We would
save ourselves the problem and time of rewriting all Services to an entirely new API.</p>
<h2 id="sodoesthebuiltinhttpclienthaveanyuse">So, does the built-in HTTP client have any use?</h2>
<p>There are some reasons why AngularJS/Angular have their HTTP clients.</p>
<p>In both frameworks, the respective HTTP clients tie into the change detection system, automatically triggering
a change detection as soon as a response is received.</p>
<p>If we use <code>fetch()</code> or Axios, we might need to handle that ourselves. This is not necessarily
prohibitively complicated, but it’s worth remembering.</p>
<p>Another difference in AngularJS that could break your application if not addressed is that the built-in HTTP
client returns <a href="https://docs.angularjs.org/api/ng/service/$q">$q</a> promises, the AngularJS’s built-in promise
type rather than regular <code>Promise</code> instances. So it is worth paying attention to what type is returned from
the services and considering this argument when making a decision about the HTTP client.</p>
<p>Another difference worth mentioning when using <code>fetch()</code> is that it does not support some features
offered by built-in clients, such as request/response interception, transformations, etc.</p>
<p>One last difference between <code>fetch()</code> and Axios is that they might be a little less easy to handle in tests
compared to the built-in HTTP clients, which offer utilities that make testing easier.</p>
<p>With the above in mind, we should decide on the HTTP client based on our goals and objectives.</p>
<h2 id="summary">Summary</h2>
<p>I am not trying to convince anyone that Axios is better than <code>HttpClient</code>. But I hope I have
succeeded in getting you to reflect on the future of your application. Perhaps years from now, Angular will be
another completely different framework implementing a new API. Regardless, using a framework-agnostic
library like Axios will ensure that your code that fetches data will look and function similarly!</p>
<p>Sample application code based on AngularJS and Axios is available in
<a href="https://github.com/jzolnowski/angularjs-axios">this GitHub repository</a>.</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.
Check out our <a href="https://www.devintent.com">offerings</a> or <a href="https://www.devintent.com/contact-us">reach out</a>.</p>
<p><br></p>
<hr>
<h6 id="ahrefhttpswwwfreepikcomfreevectorconceptchoicehardeasyway_9395722htmqueryeasyposition5from_viewsearchtracksphtarget_blankrelnoopenerimagebyupklyakaonfreepik"><a href="https://www.freepik.com/free-vector/concept-choice-hard-easy-way_9395722.htm#query=easy&position=5&from_view=search&track=sph" target="_blank" rel="noopener">Image by upklyak</a> on Freepik</h6>]]></content:encoded>
            <category>angularjs-migration</category>
        </item>
        <item>
            <title><![CDATA[Why an Expert Migration Partner Ultimately Saves You Money]]></title>
            <link>https://devintent.com/blog/2022-12-22-why-an-expert-migration-partner-ultimately-saves-you-money.md</link>
            <guid isPermaLink="false">blog/2022-12-22-why-an-expert-migration-partner-ultimately-saves-you-money.md</guid>
            <pubDate>Thu, 26 Jan 2023 22:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to ensure the success of your migration while saving money, shortening the project timeline, and avoiding critical errors.]]></description>
            <content:encoded><![CDATA[<p>Web application platform migrations are large and often daunting undertakings.
Especially when new feature developments, budgets, and revenue-driving business priorities have you pulled in
many, and sometimes conflicting, directions.</p>
<p>When evaluating a migration strategy, one of the first questions is whether to use internal resources or
partner with a migration expert. Initially, in-house migrations often feel like the easier choice, and the
sticker shock can scare some away from bringing in outside help.</p>
<p>However, internal teams can become overwhelmed with competing priorities or need more technical expertise,
causing the migration to drag on for years or, worse yet, never reach successful completion. With a closer
look, you’ll find the upfront costs of a partner return significant savings from many angles over the life of
the project.</p>
<p>Let’s see how partnering with a migration expert helps save time and money while achieving a successful
migration.</p>
<h2 id="toplinegrowth">Top Line Growth</h2>
<p>Migrations to newer web application platforms are an experienced migration architect’s specialty. Their
migration-specific expertise provides a blueprint for your application to work right, not only when the
migration is complete but also along the way. By deploying a hybrid environment, they can ensure the
application will be in a workable and releasable state throughout the migration. Compared to attempting a
migration in-house, this is a significant advantage that allows your team to focus on the core business goals
of developing new features and applications that grow your top and bottom line.</p>
<h2 id="inhousedevelopervsexpertmigrationarchitect">In-house Developer vs. Expert Migration Architect</h2>
<p>When you already have developer talent in-house, why should you trust outside help? Because a migration
architect’s skillset is unique to migrations, drastically differing from a developer’s proficiency in writing
application code. The mammoth undertaking of ramping up your team’s knowledge for a successful platform
migration is a legacy tech investment that won’t result in an ROI. You’ve burnt months or years of valuable
time preparing for an undertaking having high odds of failure. Instead, by using an expert partner, you can
have confidence in your approach while significantly increasing your success rate and starting your migration
immediately.</p>
<h2 id="budgeting">Budgeting</h2>
<p>A migration expert can complete the project with fewer costs and a shorter delivery time when compared to
using in-house resources. Additionally, you’ll have confidence the correct route was taken, not requiring
costly revisits to address something twice. You can get where you need to go faster and at a lower cost than
in-house. Depending on your budget allocations, you can dynamically throttle up your project’s momentum with
fully dedicated migration services or with consistently dedicated part-time work.</p>
<h2 id="stopsthebleeding">Stops the Bleeding</h2>
<p>Stops the accumulation of technical debt by ceasing the creation of antiquated end-of-life code. Each
incrementally migrated module is proven to work when complete, not just verified at the end of the migration.
Further application development, like fixes and new features, can continue alongside the migration. Your team
can quickly develop on a modern platform, improving your application performance and security while reducing
implementation times for new features.</p>
<h2 id="headcount">Head Count</h2>
<p>No need to hire, train, or maintain migration-specific talent for the project, allowing you to avoid overhead
costs and the time spent recruiting. Choosing to upskill internal talent for a migration comes with
considerable risk. Many developers are unwilling to learn competencies on a deprecated platform or lack the
spare time required. There are also chances of a fatal architecture error or newly trained developers
transitioning away from the project part-way through. These obstacles could leave you upside down with a
broken application or scrambling to hire replacements with a skill set that’s becoming obsolete.</p>
<h2 id="riskmanagement">Risk Management</h2>
<p>You mitigate substantial risk by involving a proven web application migration expert early in the planning
stages. Common errors avoided include confusing the easiest migration path as optimal for your future needs,
choosing the incorrect migration tools, or not knowing when an app is better suited for a complete rewrite.
Ultimately all these things could have severe negative consequences and huge costs associated.</p>
<h2 id="conclusions">Conclusions</h2>
<p>The points above demonstrate a compelling business case of how teaming with a migration expert saves money and
time. Whether you’re in the planning stages of a migration, stuck in a perpetual rut of deciding which
platform to move to, or stalled halfway through, help is available. Keep your momentum moving forward and
project on target without breaking the bank.</p>
<p>To learn more about the best path for your business, <a href="https://calendly.com/devintent/15min">schedule</a>
a quick introductory chat with our team.</p>]]></content:encoded>
            <category>it-leadership</category>
        </item>
        <item>
            <title><![CDATA[How to Support Users’ Light/Dark Mode Preferences in Your Web Application?]]></title>
            <link>https://devintent.com/blog/2022-12-01-how-to-support-users-light-dark-mode-preferences-in-your-web-application.md</link>
            <guid isPermaLink="false">blog/2022-12-01-how-to-support-users-light-dark-mode-preferences-in-your-web-application.md</guid>
            <pubDate>Thu, 01 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[How to automatically switch styling between dark and light modes.]]></description>
            <content:encoded><![CDATA[<p>Your website will be used in many contexts, and you should ensure that it can adapt to them. We have responsive websites for different screen sizes—a layout that changes to fit the screen width. Similarly, we can make sure our website looks good in the dark. In this article, I'll show you how to switch your web application automatically to dark mode—thereby ensuring that your users are always interacting with the version of your app that best suits their needs.</p>
<h2 id="whatisdarkmodeandhowtocontrolit">What is dark mode, and how to control it</h2>
<p>Dark mode is a color scheme optimized for use in a low-light environment. Usually, it inverts the traditional color combination and uses light letters on a dark background. Light or dark mode is controlled by either the operating system or the browser. On macOS, you can select one of three options:</p>
<ul>
<li>always light</li>
<li>always dark</li>
<li>auto—light during the day and dark at night</li>
</ul>
<p>Some browsers—for example, Firefox—either use a theme based on the OS setting or allow the user to override it on the browser level.</p>
<p>How do websites use switch to dark mode to respect users' preferences? With the media query option <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-color-scheme</a>, which is supported by 93% of browsers according to <a href="https://caniuse.com/prefers-color-scheme">Can I use</a> data.</p>
<h2 id="howotherwebsiteslookindarkmode">How other websites look in dark mode</h2>
<p>Many websites already switch to dark mode automatically based on the users' preferences. For example:</p>
<p>Google:</p>
<p><a href="/blog/darkmode/1-google-screenshot.png"><img src="/blog/darkmode/1-google-screenshot.png" alt="Screenshot of Google in the dark mode" /></a></p>
<p>Twitter:</p>
<p><a href="/blog/darkmode/2-twitter-screenshot.jpg"><img src="/blog/darkmode/2-twitter-screenshot.jpg" alt="Screenshot of Twitter in the dark mode" /></a></p>
<h2 id="whyyoushouldsupportitaswell">Why you should support it as well</h2>
<p>As <a href="https://mobilea11y.com/quick-wins/dark-mode/">others</a> have pointed out, supporting dark mode increases accessibility for your web application. Some visual impairments cause users to prefer viewing websites and applications in dark mode.  Thus, by implementing it in your application, you make sure everyone in your user base can use your product effectively.</p>
<p>Besides accessibility concerns, for many users, dark mode is their preferred way of using applications. When the operating system is set to dark mode, most of the interface elements become dark. With many applications and websites following this setting, any application that sticks to the bright colors stands out negatively because it forces the bright colors onto the user.</p>
<h2 id="examplewithcssvariables">Example with CSS variables</h2>
<p>In order to support two color schemes on your website, every color on your website has to be set twice—for the light and the dark mode. To avoid code duplication, you can use native CSS variables—they have widespread support (<a href="https://caniuse.com/css-variables">source</a>):</p>
<p><a href="/blog/darkmode/3-css-variables.jpg"><img src="/blog/darkmode/3-css-variables.jpg" alt="Support table for CSS variables" /></a></p>
<p>You can use it very easily in any web application. You define two files defining variables:</p>
<p><code>styles.light.css</code>:</p>
<pre><code class="css language-css">:root {
  --main-bg-color: #fafafa;
  --main-color: #000000de;
}
</code></pre>
<p><code>styles.dark.css</code>:</p>
<pre><code class="css language-css">:root {
  --main-bg-color: #303030;
  --main-color: #fff;
}
</code></pre>
<p>Then, in your main style file you use those variables for styling and import the color mode file based on user preferences.</p>
<p><code>styles.css</code>:</p>
<pre><code class="css language-css">@import url("styles.light.css") (prefers-color-scheme: light);
@import url("styles.dark.css") (prefers-color-scheme: dark);

body {
  background-color: var(--main-bg-color);
  color: var(--main-color);
}
</code></pre>
<p>Here you can find the <a href="https://github.com/DevIntent/css-variables-dark-mode">example code</a>, and the <a href="https://devintent.github.io/css-variables-dark-mode/">website in action</a></p>
<p>Depending on your use case, you may need some fallback values to ensure support for older browsers, <code>styles.css</code> with fallback:</p>
<pre><code class="css language-css">body {
  background-color: #fafafa;
  background-color: var(--main-bg-color);
  color: #000000de;
  color: var(--main-color);
}
</code></pre>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.
Check out our <a href="https://www.devintent.com">offerings</a> or <a href="https://www.devintent.com/contact-us">reach out</a>.</p>]]></content:encoded>
            <category>UX</category>
            <category>accessibility</category>
        </item>
        <item>
            <title><![CDATA[Back and Better Than Ever - Takeaways from ng-conf 2022]]></title>
            <link>https://devintent.com/blog/2022-10-15-back-and-better-than-ever-takeaways-from-ng-conf-2022.md</link>
            <guid isPermaLink="false">blog/2022-10-15-back-and-better-than-ever-takeaways-from-ng-conf-2022.md</guid>
            <pubDate>Sat, 15 Oct 2022 21:20:00 GMT</pubDate>
            <description><![CDATA[Review of interesting sessions at the ng-conf 2022 conference]]></description>
            <content:encoded><![CDATA[<p>Earlier this month marked another successful year of ng-conf, Angular's most prominent conference. This year's
conference was the first one back in-person since 2020 and hosted more than 50 speakers from around the world.
While we wait for <a href="https://www.youtube.com/playlist?list=PLOETEcp3DkCpNBWRSCq82AK2LTDfR2zDf">more presentations</a>
to be released online, our team wanted to share some of our key takeaways from the event, focusing
specifically on the areas of security, performance, and architecture.</p>
<p>Let's get started!</p>
<h2 id="performance">Performance</h2>
<p><a href="/blog/ng-conf-2022/performance.jpg"><img src="/blog/ng-conf-2022/performance.jpg" alt="Loading" /></a></p>
<p>From performance at scale, to tuning, to general best practices, web application performance was a big topic
at ng-conf 2022. While we didn't have the opportunity to attend every presentation, we picked out a few
highlights we thought were particularly valuable.</p>
<p>Lara Newsom's "The Tell-Tale Code" listed three standard Angular Code Smells:</p>
<ul>
<li>Calling functions inside Angular templates causes our method to be called multiple times instead of once</li>
<li>Optional chaining EVERYTHING, which, when misused, increases the size of the bundle</li>
<li>Tightly coupled component logic, which will require significant refactoring at a later stage for
the application to be maintained and scaled appropriately because it can cause a loss of reusability
of components or difficulty in identifying dependencies between them</li>
</ul>
<p>In a presentation focused on the anatomy of slow web applications, Misko Hevery shared that the amount of
JavaScript code in applications has caused performance problems for even the most mature players in the
space. This increase, he said, is not necessarily due to bad practices but can be attributed to the evolution
of JavaScript itself. Today, JavaScript is capable of so much more and, naturally, developers want to
take advantage of that increased functionality.</p>
<p>Misko shared that the most common problem is extraneous JavaScript code. By optimizing that code, we can correct
a lot of existing performance issues, even in larger web applications. He demonstrated one method by
comparing <code>Replayable</code> (<code>Angular</code>, <code>Vue</code>, <code>React</code>, <code>Svelte</code>), where JavaScript code is fetched
from the server and executed on the browser side, and <code>Resumable</code> frameworks (<a href="https://markojs.com/">Marko</a>,
<a href="https://github.com/google/jsaction">Wiz</a>, <a href="https://github.com/BuilderIO/qwik">Qwik</a>), where code is
executed on the server side, is serialized, and then encapsulated in HTML for user interaction.</p>
<p>Ady Ngom presented seven basic principles to develop faster Angular applications. He mentioned that the
size of the application does not matter much when discussing performance. Budget plays a key role. He shared
practical strategies, like lazy loading images, optimizing event detection with
<a href="https://angular.io/api/core/NgZone">ngZone</a>, the <a href="https://docs.angular.lat/guide/ivy">Ivy</a> engine,
non-blocking processes, and prefetching all possible resources. These are captured in his "Angular Checklist"</p>
<ul>
<li>a list of practices that will help boost the performance of Angular applications.</li>
</ul>
<p>Michael Hladky spoke to Runtime Performance, comparing the performance of a regular Angular application with
a Zone-Less Angular application. He explained how event detection works in the framework and presented an
efficient way of event detection and template re-rendering using the <a href="https://rx-angular.io/">RxAngular</a>
library as an example.</p>
<p>Ben Lesh, in turn, mentioned a patch release for <a href="https://rxjs.dev">RxJS</a> version 7.5.4,
where stream operations are performed <strong>31 times faster than in previous versions!</strong> So it's worth checking
the library version you're working with.</p>
<p>On the last day, Houssein Djirdeh talked about Chrome browser features and improvements in the area of web
application performance:</p>
<ul>
<li>Updated the Largest Contentful Paint (LCP) metric in version 88 - previous versions did not consider
elements removed from the DOM tree</li>
<li>Automatically inline Google Fonts and critical CSS, so we don't have to make additional HTTP requests</li>
<li>Image optimization during build time thanks to the
new <a href="https://angular.io/api/common/NgOptimizedImage">NgOptimizedImage</a> module, which enforces best practices</li>
</ul>
<p>Finally, we got to experience a deep dive into image optimization best practices for Angular, presented by
Kara Erickson during her session called "Image Optimization Best Practices with Angular".</p>
<h2 id="security">Security</h2>
<p><a href="/blog/ng-conf-2022/security.jpg"><img src="/blog/ng-conf-2022/security.jpg" alt="Security" /></a></p>
<p>Security is one of the greatest challenges in software development. It is a critical defense mechanism meant
to cover any potentially vulnerable surfaces, as it's impossible to predict every form an attack may come in.
However, despite its inherent importance, security is often overlooked or treated as an afterthought during
development.</p>
<p>After all, we count on the framework to do the security work for us, and the rest of the
dependencies… well, since they have been released for production, they should be safe, right? :) Of course
not!</p>
<p>In their cleverly-named presentation, "OAyDaBy AAmn=/y SAinRe9L TArT, wait what?" Jessica Janiuk
and Joey Perrot raised topics related to the security of the Angular framework. They covered topics on secure
software development, operations to deploy and run applications securely in production, and how to ensure
that applications are protected by default when using Angular.</p>
<p>Alisa Duncan's session, on the other hand, focused on the <strong>TOP 2 OWASP vulnerabilities</strong> from 2021:</p>
<ul>
<li><code>Broken Access Control</code>, which is the failure to properly enforce policies such that users cannot act
outside their intended permissions</li>
<li><code>Injection</code> - the attacker sends data to an application in a way that will change the meaning of commands
being sent to an interpreter.</li>
</ul>
<p>She highlighted what can happen when an attacker has elevated access within the application and explained
some of the defenses we have against these attacks, both built into Angular and what we can do ourselves, as
developers.</p>
<h2 id="architecture">Architecture</h2>
<p><a href="/blog/ng-conf-2022/architecture.jpg"><img src="/blog/ng-conf-2022/architecture.jpg" alt="Diagram" /></a></p>
<p>As you might expect, architecture was another topic covered in more than a few presentations.</p>
<p>One of our consultants, Alain Chautard, walked us through creating generic components with content projection
on Thursday, using the <code>Dialog</code> and <code>Tabs</code> Components in an example.</p>
<p>Manfred Steyer focused on topics related to Micro-frontend architecture
and <a href="https://webpack.js.org/concepts/module-federation/">Webpack Module Federation</a>. He discussed Static
and Dynamic Federation configuration and showed how to share libraries and modules between independent
applications.</p>
<p>In a similar vein, Adrian Iskandar Espinosa Caballero discussed some advantages of using Micro frontends,
namely:</p>
<ul>
<li>Scalability</li>
<li>Reusability</li>
<li>Visual Continuity</li>
</ul>
<p>Both speakers presented sample Micro-frontend applications using React, AngularJS, and various versions of
Angular.</p>
<p>There were also topics related to Monorepos, which have <a href="https://nx.dev/more-concepts/why-monorepos">Nx</a> at
their heart. Michael Madsen and Erik Slack presented 20 reasons why you should use Nx.</p>
<p>There was also a session on state management using NgRx as an example. Kate Sky and, in a later session,
Brandon Roberts talked about some of the best and worst (or suboptimal, at least) practices for using
<a href="https://ngrx.io/">NgRx</a>. They also discussed separating smart and presentational components, clean code,
and state management in a monorepo, using Nx as an example.</p>
<p>In another session, Mike Ryan and Brandon Roberts presented the new v14 version of NgRx and its features,
such as <a href="https://github.com/ngrx/platform/discussions/3337">createActionGroup</a>, the new API
for <a href="https://angular.io/guide/standalone-components">Standalone Components</a>,
and <a href="https://github.com/timdeschryver/eslint-plugin-ngrx">@ngrx/eslint-plugin</a>. The topic of new features
in NgRx was continued by Marko Stanimirović, discussing
the <a href="https://github.com/ngrx/platform/discussions/3099">createFeature</a>
function that can help us to reduce repetitive code in selector files.</p>
<p>The <a href="https://www.youtube.com/watch?v=hnVckmM6GZk&list=PLOETEcp3DkCpNBWRSCq82AK2LTDfR2zDf">session</a> with Pawel
Kozlowski provided some additional insight into Standalone Components. We learned more about their power,
motivation, and how they differ from NgModules. We also found how we can use Standalone Components to
drastically reduce the number of lines of code and can break inheritance restrictions.</p>
<p><a href="/blog/ng-conf-2022/standalone-components.jpg"><img src="/blog/ng-conf-2022/standalone-components.jpg" alt="Standalone Components example" /></a></p>
<p>Manfred Steyer, on the other hand, in his talk on Standalone Components, showed us route handling in an
application without NgModules and a recommendation for file and folder structure in such applications.</p>
<p>In his session, Mike Ryan demonstrated <a href="https://v10.ngrx.io/guide/component-store">ComponentStore</a>
in action using a sample drawing application as an example. He explained best practices for sharing states
between components, managing streams and lifecycle <code>Subscriptions</code>, decoupling component logic, removing
responsibility outside the element, and making them easier to read, write, and test.</p>
<p>We found Ward Bell's session on validating <a href="https://angular.io/guide/reactive-forms">Reactive Forms</a> to be
particularly enlightening. He talked about frontend architecture and its role in form validation.
He said that it's the model that sets the rules, not the UI; that it's the model that should know if a field
is required, not the UI; and that it's the model that should understand the relationships between fields in
different forms on a page. He also demonstrated what the model could look like using the <a href="https://github.com/wardbell/ngc-validate">ngc-validate</a>
library. Ward’s fuchsia-colored outfit also attracted considerable attention. So if you were looking for Ward
at the conference, you had no problem recognizing him :)</p>
<p>In the last session of the conference, Deborah Kurata discussed best practices for RxJS, mentioned the
declarative approach, and the differences between different
<a href="https://rxjs.dev/guide/higher-order-observables">Higher-Order Maps</a>.</p>
<h2 id="finalthoughts">Final thoughts</h2>
<p>The conference ended with a Q&amp;A session with the Angular Team, during which attendees asked questions for
nearly an hour. Among other things, they asked about <code>ngUpgrade</code> support for Standalone Components and the
future of <a href="https://rxjs.dev/guide/observable">Observables</a> in Angular. It was an excellent opportunity for the
community to learn about the upcoming but more distant plans for the framework.</p>
<p>Each of the three days of the conference presented fascinating information and touched on the essential
aspects of Angular development and its community. There were topics on Angular's history, current best
practices, and items still in the pipeline.</p>
<p>What were my takeaways? First, I gained a better understanding of the mechanisms under Angular's hood,
learned more about the causes of poor performance in web applications, and the power
of Standalone Components.</p>
<p>I'm particularly looking forward to doing tests using the new <code>NgOptimizedImage</code> module and playing around
with RxAngular a bit more. I'm also curious about the new <code>Qwik</code> framework offering, according to Miško
Hevery, the fastest possible page load times.</p>
<p>The only thing I missed was a lack of topics related to hybrid architecture that didn't depend upon using
Micro frontends. The Angular Team officially
<a href="https://www.devintent.com/blog/2022-01-25-angularjs-end-of-life-what-next">stopped supporting the AngularJS framework in December 2021</a>,
but many projects are stuck on the old framework with no clear path for migrating to the latest version of
Angular.</p>
<p>Hopefully, the materials from the conference will be released soon. It's worth checking out the videos when
they are published, and you have spare time. Next year, I hope there will be another ng-conf, may it be as
successful!</p>
<p>Thank you for your attention!</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.
Check out our <a href="https://www.devintent.com">offerings</a> or <a href="https://www.devintent.com/contact-us">reach out</a>.</p>]]></content:encoded>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[React To Screen-size Changes In Angular]]></title>
            <link>https://devintent.com/blog/2022-10-04-react-to-screen-size-changes-in-angular.md</link>
            <guid isPermaLink="false">blog/2022-10-04-react-to-screen-size-changes-in-angular.md</guid>
            <pubDate>Tue, 04 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Using BreakpointObserver with MediaQuery to respond to screen-size changes]]></description>
            <content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>Imagine that you have an application where you display different content depending on the size of the screen.
There are different ways to solve this issue, for example
with <a href="https://www.w3schools.com/cssref/css3_pr_mediaquery.asp">@media css</a>. Media queries with CSS is really
helpful, but if we have business logic to implement depending on the screen size, creating custom classes with
separate CSS just to handle these kinds of problems will create unnecessary chaos in our project.</p>
<p><a href="/blog/cdk-1/1-react-to-screen-size-changes-in-angular.jpg"><img src="/blog/cdk-1/1-react-to-screen-size-changes-in-angular.jpg" alt="Responsiveness Image" /></a></p>
<p>This is where <a href="https://material.angular.io/cdk/categories">Angular CDK</a> jumps in. In this article, we will
focus on the solution provided by the Angular team, the two main classes
from <a href="https://github.com/angular/components/tree/master/src/cdk/layout">@angular/cdk/layout</a>
package: <a href="https://material.angular.io/cdk/layout/overview#breakpointobserver">BreakpointObserver</a>
and <a href="https://material.angular.io/cdk/layout/overview#mediamatcher">MediaMatcher</a>. We will also build an
application that will track changes in the screen size and display different content depending on the
resolution.</p>
<p>Let's get started!</p>
<h2 id="angularcdklayout">Angular CDK Layout</h2>
<p>The layout package helps to build responsive UIs that react to screen-size changes. With it, we can catch any
resize and know when the screen exits or enters a breakpoint.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>If you would like to follow along with this article, you will need:</p>
<ul>
<li><a href="https://nodejs.org/en/download/">Node.js</a> installed locally</li>
<li><a href="https://www.npmjs.com/package/@angular/cli">@angular/cli</a> installed globally</li>
</ul>
<p>In this article, the examples are based on <code>Angular CLI 14.2.2</code> and <code>Node 16.13.1</code>.</p>
<h2 id="projectsetup">Project Setup</h2>
<p>Let's open a terminal, navigate to the directory where we want to create the project, and type:</p>
<pre><code>ng new cdk-breakpointobserver-example
</code></pre>
<p>It will create and initialize a new Angular application.</p>
<p>Navigate to the newly created project and install <code>@angular/cdk</code> package:</p>
<pre><code>npm i --save @angular/cdk
</code></pre>
<p>To use services from Layout Module, we will first need to import it. Lets do that in app.module:</p>
<pre><code class="typescript language-typescript">import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { LayoutModule } from '@angular/cdk/layout';
import { MatCardModule } from '@angular/material/card';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    LayoutModule,
    MatCardModule,
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
</code></pre>
<p>Now we can start using the available utilities from the <code>LayoutModule</code>.</p>
<h2 id="breakpointobserver">BreakpointObserver</h2>
<p><code>BreakpointObserver</code> lets you evaluate media queries to determine the current screen size and react to changes
when the viewport size crosses a breakpoint.</p>
<pre><code class="typescript language-typescript">export declare class BreakpointObserver implements OnDestroy {
  isMatched(value: string | readonly string[]): boolean;

  observe(value: string | readonly string[]): Observable&lt;BreakpointState&gt;;
  ...
}
</code></pre>
<p>There are two main methods defined in the class: <code>observe</code> and <code>isMatched</code>. The <code>observe</code> method is used to
observe when the screen-size changes between
different [breakpoints](when the viewport changes between a matching media query). The <code>isMatched</code> tells us
whether one or more media queries match the current viewport size.</p>
<h2 id="mediamatcher">MediaMatcher</h2>
<p><code>MediaMatcher</code> is a low-level utility that wraps around
JavaScript’s <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia">matchMedia</a>, which can be
used to get a native <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList">MediaQueryList</a>.</p>
<pre><code class="typescript language-typescript">export declare class MediaMatcher {
  matchMedia(query: string): MediaQueryList;
  ...
}
</code></pre>
<p>As we can see, it gives us access to the native <code>MediaQueryList</code> object through the public method <code>matchMedia</code>
.</p>
<h2 id="breakpointobserverandmediamatcherinaction">BreakpointObserver and MediaMatcher in action</h2>
<p>Let's return to <a href="https://github.com/jzolnowski/cdk-breakpointobserver-example">our application</a>. We want to
track the changes of the viewport size, and also list the values of each predefined breakpoint.</p>
<p>To do this, we need to inject <code>BreakpointObserver</code> and <code>MediaMatcher</code> into the class constructor and call
the <code>observe</code> and <code>matchMedia</code> methods for class instances.</p>
<pre><code class="typescript language-typescript">import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core';
import {BreakpointObserver, Breakpoints, BreakpointState, MediaMatcher} from '@angular/cdk/layout';
import {Observable} from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnInit {
  breakpointsInfo: {name: string, value: MediaQueryList}[] = [];
  breakpointState: Observable&lt;BreakpointState&gt; | undefined;
  xSmall: string = Breakpoints.XSmall;
  small: string = Breakpoints.Small;
  medium: string = Breakpoints.Medium;
  large: string = Breakpoints.Large;
  xLarge: string = Breakpoints.XLarge;
  webLandscape: string = Breakpoints.WebLandscape;

  constructor(public breakpointObserver: BreakpointObserver, private mediaMatcher: MediaMatcher) {}

  ngOnInit(): void {
    this.breakpointsInfo = this.getBreakpointsInfo();

    this.breakpointState = this.breakpointObserver.observe([
      Breakpoints.XSmall,
      Breakpoints.Small,
      Breakpoints.Medium,
      Breakpoints.Large,
      Breakpoints.XLarge,
      Breakpoints.WebLandscape,
      Breakpoints.WebPortrait,
    ])
  }

  getBreakpointsInfo(): {name: string, value: MediaQueryList}[] {
    return [
      Breakpoints.XSmall,
      Breakpoints.Small,
      Breakpoints.Medium,
      Breakpoints.Large,
      Breakpoints.XLarge,
      Breakpoints.Web,
      Breakpoints.WebLandscape,
      Breakpoints.WebPortrait,
      Breakpoints.Handset,
      Breakpoints.HandsetLandscape,
      Breakpoints.HandsetPortrait,
      Breakpoints.Tablet,
      Breakpoints.TabletLandscape,
      Breakpoints.TabletPortrait
    ].map((breakpoint, index) =&gt; ({name: Object.keys(Breakpoints)[index], value: this.mediaMatcher.matchMedia(breakpoint)}));
  }
}
</code></pre>
<p>The observe method returns <a href="https://rxjs.dev/guide/observable">Observable</a>
of <a href="https://material.angular.io/cdk/layout/api#BreakpointState">BreakpointState</a> type, that we need to
subscribe to for observing when the viewport of your application changes. We can do this manually in the
component class with <a href="https://rxjs.dev/guide/observable#subscribing-to-observables">subscribe</a> method, or in
the component template with <a href="https://angular.io/api/common/AsyncPipe">async pipe</a>.</p>
<pre><code class="html language-html">&lt;div *ngIf="breakpointState | async as state" style="display: flex; gap: 10px"&gt;
  &lt;h2 *ngIf="state.breakpoints[xSmall]"&gt;Breakpoint: Extra Small&lt;/h2&gt;
  &lt;h2 *ngIf="state.breakpoints[small]"&gt;Breakpoint: Small&lt;/h2&gt;
  &lt;h2 *ngIf="state.breakpoints[medium]"&gt;Breakpoint: Medium&lt;/h2&gt;
  &lt;h2 *ngIf="state.breakpoints[large]"&gt;Breakpoint: Large&lt;/h2&gt;
  &lt;h2 *ngIf="state.breakpoints[xLarge]"&gt;Breakpoint: Extra Large&lt;/h2&gt;
  &lt;h2&gt;Orientation: {{ breakpointObserver.isMatched(webLandscape) ? 'Landscape' : 'Portrait' }}&lt;/h2&gt;
&lt;/div&gt;
</code></pre>
<p>It is worth adding that we can listen for non-standard breakpoints that we define ourselves:</p>
<pre><code class="typescript language-typescript">this.breakpointObserver.observe(['(min-width: 500px)'])
</code></pre>
<p>To additionally display information about the value of
individual <a href="https://material.angular.io/cdk/layout/overview#predefined-breakpoints">Breakpoints</a>, we need to
loop through <code>breakpointsInfo</code> collection and display the values of the <code>name</code> and <code>value</code> property:</p>
<pre><code class="html language-html">&lt;mat-card&gt;
  &lt;mat-card-title&gt;Breakpoints ranges&lt;/mat-card-title&gt;
  &lt;mat-card-content&gt;
    &lt;ul&gt;
      &lt;li *ngFor="let breakpoint of breakpointsInfo"&gt;
        &lt;p&gt;&lt;strong&gt;{{breakpoint.name}}&lt;/strong&gt;: {{breakpoint.value.media}}&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/mat-card-content&gt;
&lt;/mat-card&gt;
</code></pre>
<p>As a result, we should see the following effect:</p>
<p><a href="/blog/cdk-1/2-resolution-and-breakpoints-info.jpg"><img src="/blog/cdk-1/2-resolution-and-breakpoints-info.jpg" alt="Breakpoints Info Image" /></a></p>
<h2 id="conclusions">Conclusions</h2>
<p>We saw how to react to viewport size changes using <code>BreakpointObserver</code> and <code>MediaMatcher</code> classes. We can
easily handle the elements of business logic, not being limited only to files with the styles, but also have
control over them in the component and its template.</p>
<p>Source code with a working application described in the article can be found on
the <a href="https://github.com/jzolnowski/cdk-breakpointobserver-example">GitHub repository</a>.</p>
<p>Thank you for your attention!</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.
Check out our <a href="https://www.devintent.com">offerings</a> or <a href="https://www.devintent.com/contact-us">reach out</a>.</p>]]></content:encoded>
            <category>angular</category>
            <category>angular-cdk</category>
        </item>
        <item>
            <title><![CDATA[Testing Angular Applications With Playwright]]></title>
            <link>https://devintent.com/blog/2022-07-29-testing-angular-applications-with-playwright.md</link>
            <guid isPermaLink="false">blog/2022-07-29-testing-angular-applications-with-playwright.md</guid>
            <pubDate>Fri, 29 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[A brief introduction to writing end-to-end tests with Playwright.]]></description>
            <content:encoded><![CDATA[<p>Playwright is an excellent option for end-to-end (E2E) testing your Angular applications if you're looking to transition away from Protractor. According to this <a href="https://github.com/angular/protractor/issues/5502">summary</a>, it's the third most popular E2E tool in the Angular community—just after Cypress and Protractor.</p>
<h2 id="whatisplaywright">What is Playwright</h2>
<p>Playwright is developed by Microsoft—the company that brought us TypeScript. It has a large following on GitHub; with 40k stars, and almost 2k forks, it is one of the most popular open-source projects for E2E testing.</p>
<h3 id="howplaywrightworks">How Playwright works</h3>
<p>Playwright runs tests and controls the browser from the outside. The test runner runs the test scripts, controls the browsers via API, and doesn't share the execution context with the application—the same approach as in Protractor or Selenium.</p>
<h3 id="strengths">Strengths</h3>
<p>Because Playwright tests run outside the browser, there is a bigger choice of languages in which you can write your tests: you’re not restricted to just JS or its flavors like in Protractor, Cypress, or Nightwatch.js. Currently, you can write your test in:</p>
<ul>
<li>JavaScript</li>
<li>Python</li>
<li>Java</li>
<li>.Net</li>
</ul>
<p>This provides the flexibility to adapt the tests to the project and pick the language to get the most out of the skills you have available within your team.</p>
<p>Playwright allows you to run your tests in major browsers:</p>
<ul>
<li>Chromium (Chrome and Edge)</li>
<li>Firefox</li>
<li>WebKit (Safari)</li>
</ul>
<p>Playwright emphasizes speed, and according to <a href="https://blog.checklyhq.com/cypress-vs-selenium-vs-playwright-vs-puppeteer-speed-comparison/#scenario-1-single-end-to-end-test-against-a-static-website">this article</a>, they deliver on that.</p>
<h2 id="exampletests">Example tests</h2>
<p>Let's take a look at an example test suite in Playwright.</p>
<h3 id="application">Application</h3>
<p>The application we will test is the final step from the official Angular tutorial <a href="https://angular.io/tutorial/toh-pt6">Tour of Heroes</a>. You can find the repository with the example code <a href="https://github.com/marcin-wosinek/tour-of-heroes-playwright/tree/playwright">here</a>.</p>
<h3 id="configurationupdates">Configuration updates</h3>
<p>An easy way to initialize the Playwright tests in a project is to run:</p>
<p><a href="/blog/playwright-1/1-init.png"><img src="/blog/playwright-1/1-init.png" alt="npm init playwright@latest" /></a></p>
<p>For easy access to running the tests, let's update <code>package.json</code>:</p>
<p><a href="/blog/playwright-1/2-diff.png"><img src="/blog/playwright-1/2-diff.png" alt="package.json example" /></a></p>
<p>With this change, <code>npm run e2e</code> will run Playwright with the default configuration—running tests on three headless browsers: Chromium, Firefox, and WebKit. Headless runs are faster and happen in isolation from the user, but they make debugging tests more difficult. For this, we have <code>npm run e2e:debug</code>, starting with only one visible browser.</p>
<h3 id="tests">Tests</h3>
<p>Example tests in <a href="https://github.com/marcin-wosinek/tour-of-heroes-playwright/blob/playwright/tests/example.spec.ts"><code>tests/example.spec.ts</code></a>:</p>
<pre><code class="js language-js">import { test, expect, type Page } from '@playwright/test';

test.describe('Tour of Heroes pages', () =&gt; {
  test('should load default route', async ({page}) =&gt; {
    await page.goto('http://localhost:4200');

    await expect(page).toHaveURL(/\/dashboard$/);
  });

  test('should allow edits', async ({page}) =&gt; {
    await page.goto('http://localhost:4200');

    await page.locator('[data-test="detail-link"]').first().click();

    await expect(page).toHaveURL(/\/detail\/\d+/);

    await page.locator('#hero-name').fill('lorem ipsum');

    await page.locator('[data-test="save-button"]').click();

    await expect(page.locator('[data-test="detail-link"]').first()).toContainText('lorem ipsum');
  });

  test('should search for heroes', async ({page}) =&gt; {
    await page.goto('http://localhost:4200');

    await page.locator('#search-box').fill('nice');

    await expect(page.locator('[data-test="search-result-link"]')).toHaveCount(1);

    await page.locator('[data-test="search-result-link"]').click();

    await expect(page).toHaveURL(/\/detail\/12/);
  });

  test('should delete heroes', async ({page}) =&gt; {
    await page.goto('http://localhost:4200/heroes');

    await expect(page.locator('.delete')).toHaveCount(9);

    await page.locator('.delete').first().click();

    await expect(page.locator('.delete')).toHaveCount(8);
  });

  test('should add heroes', async ({page}) =&gt; {
    await page.goto('http://localhost:4200/heroes');

    await page.locator('#new-hero').fill('Lorem Ipsum');

    await page.locator('.add-button').click();

    await expect(page.locator('.delete')).toHaveCount(10);
  });
});
</code></pre>
<p>The way of organizing tests in Playwright is similar to how it’s done in Protractor or Cypress. The API is returning promises, and we use <code>await</code> to ensure that each step is done executing before the next one is started.</p>
<h3 id="runningtests">Running tests</h3>
<p>To run tests, we need to start the application server in the background:</p>
<pre><code class="sh language-sh">$ npm run start

&gt; angular.io-example@0.0.0 start
&gt; ng serve

…

** Angular Live Development Server is listening on localhost:4200. Open your browser on http://localhost:4200/ **

…

✔ Compiled successfully.
</code></pre>
<p>With the server running, we can run all tests with:</p>
<p><a href="/blog/playwright-1/3-run.png"><img src="/blog/playwright-1/3-run.png" alt="npm run e2e" /></a></p>
<h2 id="summary">Summary</h2>
<p>As you see, setting E2E tests with Playwright for Angular applications is pretty straightforward. Thanks to its broad language support, you can choose a language depending on what skills are available in your team. E2E tests are an essential tool to maintain a high quality of an application in fast-moving teams.</p>
<h2 id="lookingformoresupportforyourangularprojects">Looking for more support for your Angular projects?</h2>
<p>Our team at DevIntent is highly experienced in Angular development, testing, and software quality. If you'd like to chat about how we can help you, please contact us at <a href="mailto:sales@devintent.com">sales@devintent.com</a>.</p>]]></content:encoded>
            <category>angular</category>
            <category>testing</category>
        </item>
        <item>
            <title><![CDATA[AngularJS End-of-Life - What Next?]]></title>
            <link>https://devintent.com/blog/2022-01-25-angularjs-end-of-life-what-next.md</link>
            <guid isPermaLink="false">blog/2022-01-25-angularjs-end-of-life-what-next.md</guid>
            <pubDate>Tue, 25 Jan 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[What options are available now that Google has dropped support for AngularJS?]]></description>
            <content:encoded><![CDATA[<p>When AngularJS was first launched in 2010 it was ground-breaking for web development. After more than a
decade, millions of projects around the world still rely on this framework.
AngularJS is still one of the most popular frontend frameworks today. In StackOverflow's 2021 survey which
included responses from over 50,000 developers, nearly
<a href="https://insights.stackoverflow.com/survey/2021#most-popular-technologies-webframe-prof">13% said they are still using AngularJS</a>.</p>
<p><a href="/large-images/end-of-road.jpg"><img src="/large-images/end-of-road.jpg" alt="End of Road Image" /></a></p>
<h2 id="angularjsendoflife">AngularJS End-of-Life</h2>
<p>On <a href="https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c">July 1, 2018</a>, AngularJS
entered its <a href="https://docs.angularjs.org/misc/version-support-status">Long-term Support (LTS) period</a>. The
support was originally scheduled to end on June 30th, 2021.</p>
<p>Given the COVID-19 pandemic and its impact on teams migrating from AngularJS, the Google team extended the
LTS for another 6 months, until December 31st, 2021.</p>
<p>As of <strong>January 1st, 2022 AngularJS has reached End-of-Life.</strong> You can read more about it on the official
Angular blog in
<a href="https://blog.angular.io/discontinued-long-term-support-for-angularjs-cc066b82e65a">Discontinued Long Term Support for AngularJS</a>.
For those who are still using this framework, it will have a profound impact on their development and support
plans. AngularJS will <strong>not</strong> receive patches for security vulnerabilities or breaking issues caused by new
browser releases.</p>
<h2 id="whatifyouarestillusingangularjs">What if you are still using AngularJS?</h2>
<p>Now that AngularJS has reached its End-of-Life, AngularJS applications will continue to function, at least
until the next breaking browser change happens.</p>
<p>Nevertheless, using old versions of the framework is critical to the security of your application and your
user's data. Since security patches will no longer be provided by Google, your business and your customers may
be vulnerable to new / previously unknown security threats. Before a major vulnerability is disclosed to the
public or there is an announcement that it is being exploited in the wild, you will need to have a mitigation
plan in place.</p>
<h2 id="whatoptionsdoyouhave">What options do you have?</h2>
<h3 id="getuptodate">Get up to date</h3>
<p>If your project is based on an older version of AngularJS, consider upgrading to AngularJS <code>1.8.2</code>. The latest
version of AngularJS improves security, imposes a component-based architecture, fixes a few bugs and will make
the process of migrating to modern Angular much faster. If you aren't on AngularJS <code>1.8.0</code>, or later, then
your application and your users are already exposed to a
<a href="https://snyk.io/vuln/npm:angular">range of security vulnerabilities</a>, including Cross-site Scripting (XSS)
attacks. Get protected now, by updating to the latest AngularJS version, if you haven't already done so!</p>
<h3 id="extendyoursupport">Extend your support</h3>
<p>You can get Extended Long-term Support via <a href="https://xlts.dev/angularjs">XLTS for AngularJS</a> from XLTS.dev.
This will allow you to continue developing or maintaining your application while using supported software.
This means that you will receive fixes for security vulnerabilities and breakages to browsers or jQuery when
they occur. If you have regulatory or other compliance obligations, this can help you stay compliant and
get the customer approvals that your business needs.</p>
<h3 id="hybridapplicationmigration">Hybrid application migration</h3>
<p>If you're ready to start migrating your legacy AngularJS application to modern <a href="https://angular.io/">Angular</a>,
a good first step is to refactor your application step-by-step, module by module, creating a
hybrid AngularJS/Angular application. Using this hybrid approach minimizes risk since small chunks of your
existing application can be migrated and tested. Using the <code>ngUpgrade</code> tool, you can mix and match AngularJS
and Angular code in the same application and ensure their smooth cooperation.</p>
<h3 id="rewritingfromscratch">Rewriting from scratch</h3>
<p>If your current AngularJS application is small and the business logic and other requirements are
well-documented, you may be able to perform a full re-write in a modern framework
(e.g. Angular, React, Vue, etc.) without running into major issues. A full rewrite is a riskier approach for
large or medium-sized applications. Careful planning, selection of the right tools/technologies, and building
a team with the right skill-sets is necessary to avoid broken/missing functionality, costly delays, or even
complete project failure.</p>
<h2 id="stillunsureinneedofexpertassistance">Still unsure? In need of expert assistance?</h2>
<p>If you require expert assistance or are unsure how to identify the best solution for your project,
DevIntent has the expertise to help. Contact us at
<a href="mailto:consulting@devintent.com">consulting@devintent.com</a> to get in touch. We have worked with many
enterprise and mid-sized companies since 2013 to help them update and migrate their AngularJS <code>1.x</code> based
applications. We can help make your Angular or AngularJS project a success.</p>
<p><br><br><br><br><br></p>
<h4 id="areyouanexperiencedangularjsdeveloper">Are you an experienced AngularJS developer?</h4>
<p><small><bold>We are hiring!<bold> As part of the DevIntent team, you’ll get to work with current and former
members of the Angular team, as well as other experts from the Angular Community.</p>
<p>We’ve worked on projects like: Angular, AngularJS, Angular CDK, Angular Material, AngularJS Material, and the
Angular CLI.</p>
<p>Apply today at <a href="mailto:careers@devintent.com">careers@devintent.com</a> to join us in moving the Angular
community forward from AngularJS.
</small></p>]]></content:encoded>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Angular v13 Is Out!]]></title>
            <link>https://devintent.com/blog/2021-12-30-angular-13-is-out.md</link>
            <guid isPermaLink="false">blog/2021-12-30-angular-13-is-out.md</guid>
            <pubDate>Tue, 09 Aug 2022 23:45:00 GMT</pubDate>
            <description><![CDATA[Information about the Angular v13 Release.]]></description>
            <content:encoded><![CDATA[<blockquote class="twitter-tweet" data-theme="light"><p lang="en" dir="ltr">Angular v13 is here 🎉<a href="https://twitter.com/hashtag/ngUpdate?src=hash&amp;ref_src=twsrc%5Etfw">#ngUpdate</a> for built-in improvements like:<br>- Faster prod builds<br>- Enhanced component a11y<br>- Improved test times and debugging<br>- Modern Angular Package Format<br><br>Read more:<br>📚 <a href="https://t.co/dx1HzBY9z6">https://t.co/dx1HzBY9z6</a><br><br>Join us Friday at 10am PST:<br>📅 <a href="https://t.co/6GGtgkJDpl">https://t.co/6GGtgkJDpl</a> <a href="https://t.co/ZZqIpja50M">pic.twitter.com/ZZqIpja50M</a></p>&mdash; Angular (@angular) <a href="https://twitter.com/angular/status/1456050398020653067?ref_src=twsrc%5Etfw">November 4, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>It's been six months since the last major version of the Angular framework was released. A completely new
version of Angular has just been released.</p>
<p>In this article we'll look at some features and updates that will help you create amazing applications. We
will go through a few optimizations of the Ivy engine. We will also talk about what is being deprecated and
briefly discuss the process of migrating the application to <strong>Angular v13</strong>.</p>
<p>So let's get started!</p>
<h1 id="upgradetoangularv13">Upgrade to Angular v13</h1>
<p>With the release of the new version, the Angular team provides
a <a href="https://update.angular.io/?l=3&v=12.0-13.0">complete guide</a> to upgrade from previous versions. By following
the guide, you shouldn't have any problems with getting migrated to the latest version.</p>
<p>If you are using Nx, please follow the <a href="https://nx.dev/l/a/core-concepts/updating-nx">guidelines</a> provided by
the Nwrl team. By running <code>nx migrate latest</code>, you will also update Angular and all its dependencies.</p>
<h1 id="angulardependencyupdates">Angular dependency updates</h1>
<p>In the latest release of Angular, there are also changes in the dependencies of the framework. Angular v13
introduces TypeScript 4.4 support, which means that we can now
use <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html">its new features</a>.
Support for older versions of TypeScript has been dropped.</p>
<p>Moreover, version 7.4 is now the default version for RxJs. To learn more about the changes from version 6 to
version 7, please read <a href="https://rxjs.dev/6-to-7-change-summary">this</a> article.</p>
<p>Additionally, Angular v13 has dropped support for NodeJS versions below v12.20.0 and has introduced
support for NodeJS &gt;=16.10.</p>
<h1 id="ie11supportdropped">IE11 support dropped</h1>
<p>And it happened. IE11 is no longer supported by Angular v13. This is one of the most important pieces of news
for this release. Dropping support for IE11 is a good thing - it means Angular gets to fully embrace the Web
APIs of modern browsers. It also means that we no longer have to include polyfills for IE, which makes
applications lighter and load faster than in previous versions of Angular. It is worth noting that the
migration process described previously will automatically remove polyfills for IE.</p>
<p>The Angular team put out an <a href="https://github.com/angular/angular/issues/41840">RFC</a> (request for comments) about
dropping IE11 support, and the feedback they received was overwhelmingly in favor of doing so.</p>
<p><a href="/large-images/responses-rfc.png"><img src="/large-images/responses-rfc.png" alt="Emote responses to the RFC on GitHub" /></a></p>
<p>Note that Angular 12 will continue to support IE11 until <strong>November 2022</strong>.</p>
<h1 id="ivyftw">Ivy FTW</h1>
<h3 id="ivyftwviewengine">Ivy FTW View Engine</h3>
<p>As promised in past announcements, Angular version 13 no longer supports the old rendering View Engine. For
the average Angular dev, this doesn't mean much (other than reaping the benefits of a more performant
framework). For library builders in Angular, though, this is a big deal.</p>
<p>As mentioned in the official announcement, removing View Engine also means that Angular can reduce its
reliance on <a href="https://angular.io/guide/glossary#ngcc">ngcc</a> (Angular compatibility compiler) in the future, and
teams can look forward to faster compilation because metadata and summary files are no longer included.</p>
<h3 id="angularpackageformatapf">Angular Package Format (APF)</h3>
<p>As mentioned in the official announcement,
the <a href="https://angular.io/guide/angular-package-format">Angular Package Format</a> (APF) has been streamlined and
modernized to better serve developers. To streamline the APF in Angular v13, older output formats such
as <code>CommonJS</code> (CJS) and <code>UMD</code> have been removed. Thanks to this change, the whole Web community will be better
off once <code>ES Modules</code> (ESM) are used everywhere.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Angular v13 will ship with the most modern version of APF (Angular Package Format): ES Modules+ES2020<br><br>If you&#39;ve ever maintained an npm library, you know how hard it is to come up with the right package format that is modern &amp; works for most use-cases! 🚀<a href="https://t.co/A8HPqixfKk">https://t.co/A8HPqixfKk</a></p>&mdash; Igor Minar (@IgorMinar) <a href="https://twitter.com/IgorMinar/status/1455593870851330048?ref_src=twsrc%5Etfw">November 2, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>The Angular team has also updated the APF to support Node Package Exports. This will help developers from
inadvertently relying on internal APIs that may change.</p>
<p>It is now time for Angular library authors to stop using <code>enableIvy: false</code>, and to instead
use <code>compilationMode: partial</code> (in <code>tsconfig.prod.json</code>), as recommended by Younes.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">⏳ tired of ngcc?<br><br>🚀 get ready for <a href="https://twitter.com/hashtag/Angular?src=hash&amp;ref_src=twsrc%5Etfw">#Angular</a> 13!<br><br>🧹 meanwhile, fellow library authors, let&#39;s move from &quot;enableIvy: false&quot; to &quot;compilationMode: partial&quot;<br>Cf. <a href="https://t.co/8ahrmiUp5R">https://t.co/8ahrmiUp5R</a><a href="https://twitter.com/hashtag/javascript?src=hash&amp;ref_src=twsrc%5Etfw">#javascript</a> <a href="https://t.co/iXL541Ui1Z">pic.twitter.com/iXL541Ui1Z</a></p>&mdash; Younes (@yjaaidi) <a href="https://twitter.com/yjaaidi/status/1455543855332397071?ref_src=twsrc%5Etfw">November 2, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>The partial compilation mode is a partial-Ivy code format that is stable between different versions of
Angular, and thus safe to publish to npm. Angular code that uses this partial format is processed during the
build of the application using the same version of the Angular compiler. The benefit is that both the
application and its libraries rely on a single version of Angular, removing potential compatibility issues.</p>
<blockquote>
  <p>Existing libraries will be automatically migrated to use “partial” compilation mode and some metadata previously required for the legacy View engine will be removed.</p>
</blockquote>
<p>To learn more check out
the <a href="https://angular.io/guide/creating-libraries#building-libraries-with-ivy">official guidelines</a> for library
authors.</p>
<h3 id="createcomponentsdynamicallyfromapiupdates">Create components dynamically from API updates</h3>
<p>Ivy enables a simpler way to create dynamic components. Angular no longer requires component factories to
dynamically create components. Ivy creates the opportunity to instantiate the component
with <a href="https://github.com/angular/angular/pull/43022">ViewContainerRef.createComponent</a> without creating an
associated factory. So, instead of:</p>
<pre><code class="typescript language-typescript">@Directive({...})
export class CustomyDirective {
  constructor(
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) {
  }

  createCustomComponent() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(CustomComponent);
    this.viewContainerRef.createComponent(componentFactory);
  }
}
</code></pre>
<p>We can now write:</p>
<pre><code class="typescript language-typescript">@Directive({...})
export class CustomDirective {
  constructor(private viewContainerRef: ViewContainerRef) {
  }

  createCustomComponent() {
    this.viewContainerRef.createComponent(CustomComponent)
  }
}
</code></pre>
<p>As we can see, the new approach requires much less boilerplate code!</p>
<h1 id="angularcliimprovements">Angular CLI improvements</h1>
<p>With this release, Angular supports the use of persistent build cache by default,
as <a href="https://github.com/angular/angular-cli/issues/21545">requested by the community</a>. The persistent build
cache is a feature that caches build results on disk (under the <code>.angular/cache</code> folder). This results in up
to 68% improvement in compilation speed.</p>
<p>In order to enable this feature in existing projects that have been upgrading to v13, we need to add the
following configuration to <code>angular.json</code>:</p>
<pre><code class="json language-json">{
  "$schema": "...",
  "cli": {
    "cache": {
      "enabled": true,
      "path": ".cache",
      "environment": "all"
      // other supported values: "ci" and "local"
    }
  }
}
</code></pre>
<p>We can also disable this feature (which is not recommended) with ng config <code>cli.cache.enabled false</code>.</p>
<p>If we need to clear the cache, we should delete the <code>.angular / cache</code> folder.</p>
<p>For those who use <a href="https://github.com/evanw/esbuild">esbuild</a> as a build tool, there is good news as well. The
performance has been improved. The Angular team has introduced esbuild, which now works
with <a href="https://terser.org/">terser</a> to optimize global scripts. In addition, <em>ESBuild</em> supports CSS sourcemaps
and can optimize global CSS, as well as optimizing all style sheets.</p>
<h1 id="routerimprovements">Router improvements</h1>
<h3 id="disablealinksnavigation">Disable a link’s navigation</h3>
<p>Setting the <code>routerLink</code> directive value to <code>null</code> or <code>undefined</code> will completely disable navigation. Recall
that in the previous version, the <code>null</code> and <code>undefined</code> inputs for the <code>routerLink</code> directive were
interpreted as an empty string.</p>
<h3 id="observerouterlinkactivestate">Observe router link active state</h3>
<p>A new output for the <code>routerLinkActive</code> directive called <code>isActiveChange</code> has been added. It emits
whenever <a href="https://github.com/angular/angular/pull/43280">the link becomes active or inactive</a>.</p>
<h3 id="lazyloadmodules">Lazy load modules</h3>
<p>The <code>loadChildren</code> property in the route definition no longer supports string values. It's been deprecated for
a while now. This has been replaced by the ESM dynamic import statement.</p>
<h3 id="restorehistory">Restore history</h3>
<p>A new property has been added to Router public API</p>
<ul>
<li><a href="https://github.com/angular/angular/commit/3c6b653089837459809a370ebcaf8911c3bab9ed#diff-03cb1ea13f0b5890eb24ce6fef7a42eed85429da0a90cdb48ab06b58c30cb1c1L537">canceledNavigationResolution</a>
, which configures how Router attempts to restore the state when a navigation is canceled.</li>
</ul>
<pre><code class="typescript language-typescript">RouterModule.forRoot(routes, {canceledNavigationResolution: 'computed'});
</code></pre>
<h3 id="neweventswhenanoutletgetsattacheddetached">New events when an outlet gets attached/detached</h3>
<p>Router now also provides new outputs for subscribing when an outlet gets attached/detached.</p>
<h3 id="otherimprovementsandchanges">Other improvements and changes</h3>
<ul>
<li>Support for question marks in query param values</li>
<li><a href="https://github.com/angular/angular/pull/42434">Custom route reuse strategy</a> through dependency injection
for the <code>RouterTestingModule</code></li>
</ul>
<pre><code class="typescript language-typescript">  TestBed.configureTestingModule({
    imports: [RouterTestingModule],
    providers: [{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy}]
  });
</code></pre>
<h1 id="formimprovements">Form improvements</h1>
<p>In this version, a little more attention is paid to Angular Forms, improving the security of reactive forms.
Let's take a look at the changes.</p>
<h3 id="bettertypecheckingforformstatus">Better type checking for form status</h3>
<p>A specific type called <code>FormControlStatus</code> has been introduced, which is the union type of all possible status
strings for form controls: <code>'VALID' | 'INVALID' | 'WAITING' | 'OFF'</code>. Until now, we could not use <em>Typescript</em>
checking because <code>AbstractControl.status</code> was entered as a string and <code>AbstractControl.statusChanges</code>
was <code>Observable&lt;any&gt;</code>.</p>
<p>This is a breaking change! As mentioned in the release notes, this can break applications if an invalid form
status string is used or if <code>statusChanges</code> events were something other than strings.</p>
<h3 id="newmethodstomanagevalidators">New methods to manage validators</h3>
<p>New form methods have been added to <code>AbstractControl</code>:</p>
<ul>
<li><code>addValidators</code>: Add one or more synchronous validator(s) to the control, without affecting other validators</li>
<li><code>setValidators</code>: Sets one or multiple validators by overriding the registered ones. For removing all
registered validators we can pass a value of <code>null</code></li>
<li><code>hasValidator</code>: Determines whether a validator or validators array has a given validator</li>
<li><code>removeValidators</code>: Remove synchronous validators from this control</li>
</ul>
<p>All of these methods also have an async version: <code>addAsyncValidators</code>, <code>setAsyncValidators</code>
, <code>removeAsyncValidators</code>, and <code>hasAsyncValidator</code>.</p>
<p>These new methods provide us with more control over the validation process. We can now easily add/remove
synchronous and asynchronous validators.</p>
<h1 id="templatesimprovements">Templates improvements</h1>
<p>Angular now
supports <a href="https://twitter.com/AlisaDuncan/status/1456293065988128768?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1456293065988128768%7Ctwgr%5E%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdsebastien.net%2F%2Fblog%2F">autocompletion for string literal union types</a>
. The language service of Angular is now able to automatically insert the optional chaining operator (i.e.,
?.) when property access (i.e., .) is done on a nullable symbol.</p>
<p>Also, the <code>fullTemplateTypeCheck</code> compiler option has been deprecated. Instead, we should use <code>strictTemplates</code>
.</p>
<h1 id="componentsimprovements">Components improvements</h1>
<h3 id="accessibility">Accessibility</h3>
<p>The new version of Angular has also resulted in significant improvements and changes to the components of
Angular Material.</p>
<p>All MDC-based components have been assessed to meet elevated a11y standards in areas such as contrast, tactile
targets, ARIA, and more. For example let’s compare touch target sizes. The sizes on the right are the new
sizes.</p>
<p><a href="/large-images/touch-target-sizes-comparation.png"><img src="/large-images/touch-target-sizes-comparation.png" alt="Comparison of touch target sizes" /></a></p>
<p>or for better support for high contrast mode for many components:</p>
<p><a href="/large-images/components-in-high-contrast-mode.png"><img src="/large-images/components-in-high-contrast-mode.png" alt="Material Components in high contrast mode" /></a></p>
<p>It’s always a pleasure to see large organizations put energy into improving accessibility.</p>
<h3 id="angularmaterial">Angular Material</h3>
<p>There are also a few changes for Angular Material.</p>
<p>It is now possible to define content sections in test harnesses for the Dialog component. Also, a new
injection token called <code>MAT_PROGRESS_BAR_DEFAULT_OPTIONS</code> has been added to the progress bar. It can be used
to configure the default options as follows:</p>
<pre><code class="typescript language-typescript">provide: MAT_PROGRESS_BAR_DEFAULT_OPTIONS,
useValue: {
  mode: 'buffer',
  color: 'warn'
}
</code></pre>
<h1 id="testsimprovements">Tests improvements</h1>
<p>Together with Angular v13, TestBed has also been improved. It now takes better care of tearing down test
modules and environments after each test. The DOM is now cleaned up after every test, avoiding side effects.
Overall, tests should execute faster, use less memory, and be less interdependent.</p>
<p>The automatic teardown functionality was an opt-in feature since Angular v12.1.0 and is now enabled by default.
As mentioned in the announcement, this behavior can be configured for the entire test suite via
the <code>TestBed.initTestEnvironment</code> method:</p>
<pre><code class="typescript language-typescript">beforeEach(() =&gt; {
  TestBed.resetTestEnvironment();
  TestBed.initTestEnvironment(
    BrowserDynamicTestingModule,
    platformBrowserDynamicTesting(),
    {
      teardown: {destroyAfterEach: true}
    }
  );
});
</code></pre>
<p>Or it can be configured per module by updating the <code>TestBed.configureTestingModule</code> method:</p>
<pre><code class="typescript language-typescript">beforeEach(() =&gt; {
  TestBed.resetTestEnvironment();
...
  TestBed.configureTestingModule({
    declarations: [TestComp],
    teardown: {destroyAfterEach: true}
  });
});
</code></pre>
<p>This allows us to approach testing differently depending on the situation.</p>
<h1 id="summary">Summary</h1>
<p>The new release of Angular introduced a lot of new improvements and minor changes, but also unlocked the way
to the critical ones, such as the <a href="https://www.youtube.com/watch?v=AdvQ_lBDLUY">optional NgModules</a>.
ViewEngine is gone for good and Ivy has become ubiquitous.</p>
<p>This is another release that improves runtime performance, shortens build time, simplifies API, and improves
tests.</p>
<p>Finally, I encourage you to check
the <a href="https://github.com/angular/angular/blob/master/CHANGELOG.md">full list of changes</a>.</p>
<p>Until next time!</p>
<p><a href="/large-images/transamerica-pyramid.jpg"><img src="/large-images/transamerica-pyramid.jpg" alt="Transamerica Pyramid" /></a></p>]]></content:encoded>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.2.4 Release]]></title>
            <link>https://devintent.com/blog/2021-12-16-announcing-the-angularjs-material-v1-2-4-release.md</link>
            <guid isPermaLink="false">blog/2021-12-16-announcing-the-angularjs-material-v1-2-4-release.md</guid>
            <pubDate>Thu, 16 Dec 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.2.4 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.4/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.4/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>panel, select:</strong> fix Trusted Types violations during initialization (<a href="https://github.com/angular/material/issues/12128">#12128</a>) (<a href="https://github.com/angular/material/commit/4e354a6ef15362920f23167194e52fb40cb70ea9">4e354a6</a>)</li>
</ul>
<h3 id="coderefactoring">Code Refactoring</h3>
<ul>
<li><strong>sass:</strong> migrate from node-sass to sass (<a href="https://github.com/angular/material/commit/5e2d21350cd0278f210c1e2bb951786c4047bbb6">5e2d213</a>)<ul>
<li>If you consume our <code>.scss</code> files directly in your build, you will need to switch
from the deprecated <code>node-sass</code> package to the <code>sass</code> package for compiling your Sass.</li></ul></li>
<li><strong>sass:</strong> fix division deprecation warnings (<a href="https://github.com/angular/material/commit/b5a1a026202f9544847f2fba8e039c3abf1cdb1c">b5a1a02</a>)</li>
</ul>
<h3 id="documentation">Documentation</h3>
<ul>
<li>fix API docs issues related to <code>marked</code> Markdown rendering (<a href="https://github.com/angular/material/commit/441a9127676ba4a28aa0c5bc18a70c09815c7221">441a912</a>)</li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.2.4 release:</p>
<p><a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> |<a href="https://github.com/bjarkler"><img alt="bjarkler" src="https://avatars.githubusercontent.com/u/66124740?v=4&s=117" width="117"></a> |<a href="https://github.com/superheri"><img alt="superheri" src="https://avatars.githubusercontent.com/u/30275781?v=4&s=117" width="117"></a> |
:---: |:---: |:---: |
<a href="https://github.com/Splaktar">Splaktar</a> |<a href="https://github.com/bjarkler">bjarkler</a> |<a href="https://github.com/superheri">superheri</a> |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.2.3 Release]]></title>
            <link>https://devintent.com/blog/2021-07-15-announcing-the-angularjs-material-v1-2-3-release.md</link>
            <guid isPermaLink="false">blog/2021-07-15-announcing-the-angularjs-material-v1-2-3-release.md</guid>
            <pubDate>Thu, 15 Jul 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.2.3 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.3/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.3/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>datepicker:</strong> ISO 8601 dates decorated as invalid in forms (<a href="https://github.com/angular/material/commit/0a06f995be1f9cbaf963d60e848f2006309fcf12">0a06f99</a>), closes <a href="https://github.com/angular/material/issues/12075">#12075</a></li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li><strong>menu:</strong> add a new backdropParent option (<a href="https://github.com/angular/material/commit/78b107331e9903874cbb71404683f191f9172f7e">78b1073</a>)</li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.2.3 release:</p>
<p><a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> |<a href="https://github.com/atfzls"><img alt="atfzls" src="https://avatars2.githubusercontent.com/u/55975318?v=4&s=117" width="117"></a> |
:---: |:---: |
<a href="https://github.com/Splaktar">Splaktar</a> |<a href="https://github.com/atfzls">atfzls</a> |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.2.2 Release]]></title>
            <link>https://devintent.com/blog/2020-12-21-announcing-the-angularjs-material-v1-2-2-release.md</link>
            <guid isPermaLink="false">blog/2020-12-21-announcing-the-angularjs-material-v1-2-2-release.md</guid>
            <pubDate>Mon, 21 Dec 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.2.2 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.2/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.2/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes and enhancements.</p>
<ul>
<li>This is the final release of AngularJS Material prior to entering our
<a href="https://material.angularjs.org/latest/#long-term-support">Long Term Support (LTS) period</a>.</li>
<li>This release includes many accessibility and localization improvements to components like autocomplete,
checkbox, datepicker, dialog, and fab speed dial.</li>
<li>It fixes regressions with radio buttons in IE11 and with the datepicker modifying the model value (time)
before a date is selected.</li>
<li>A few long-standing issues with the fab speed dial have been fixed, significantly improving the UX of the
component.</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>aria:</strong> radio buttons throw argument not optional errors in IE11 (<a href="https://github.com/angular/material/commit/eab5c815846c91fdda3cf2a369aee28169ca6272">eab5c81</a>)</li>
<li><strong>autocomplete:</strong> prevent flashing of invalid state (<a href="https://github.com/angular/material/issues/12064">#12064</a>) (<a href="https://github.com/angular/material/commit/a4732a9808db5ccaf062ec50ef314bf124ee2feb">a4732a9</a>), closes <a href="https://github.com/angular/material/issues/10975">#10975</a></li>
<li><strong>checkbox:</strong> aria-checked state is not computed correctly in all cases (<a href="https://github.com/angular/material/commit/c60938552c1a007b24b0cd2de5248453161ae012">c609385</a>), closes <a href="https://github.com/angular/material/issues/12046">#12046</a></li>
<li><strong>datepicker:</strong> null model with timezone throws exception (<a href="https://github.com/angular/material/commit/78568835c283ac327c85016f5d43f5ec57ff9c73">7856883</a>), closes <a href="https://github.com/angular/material/issues/12025">#12025</a></li>
<li><strong>datepicker:</strong> time is modified before even selecting a date (<a href="https://github.com/angular/material/commit/b406623f08cd229ea76cc06298eea764bd51ab84">b406623</a>), closes <a href="https://github.com/angular/material/issues/12028">#12028</a> <a href="https://github.com/angular/material/issues/12026">#12026</a></li>
<li><strong>dialog:</strong> shift+tab does not cycle through tabbable elements (<a href="https://github.com/angular/material/commit/7d5e262b5606f0e83faac86966aa6947bc6125c0">7d5e262</a>), closes <a href="https://github.com/angular/material/issues/10963">#10963</a></li>
<li><strong>fab-speed-dial:</strong> action items are in tab order when closed (<a href="https://github.com/angular/material/commit/da86e6282ce01c6ec31758350946b9ee1e8536f5">da86e62</a>), closes <a href="https://github.com/angular/material/issues/10101">#10101</a></li>
<li><strong>fab-speed-dial:</strong> keyboard navigation issues with tab and shift+tab (<a href="https://github.com/angular/material/commit/41c71ed1eb7826c1927902f19dc8d8ea5bbfda22">41c71ed</a>), closes <a href="https://github.com/angular/material/issues/12043">#12043</a></li>
<li><strong>fab-speed-dial:</strong> opens when trigger button is disabled (<a href="https://github.com/angular/material/commit/e7dfcc166a8dbb7cb07d5c5f339a41e396025733">e7dfcc1</a>), closes <a href="https://github.com/angular/material/issues/9467">#9467</a></li>
<li><strong>input:</strong> check that containerCtrl.label is defined before accessing it (<a href="https://github.com/angular/material/commit/f79186faaca9ff477720a976bd9cf10b8047a4ec">f79186f</a>), closes <a href="https://github.com/angular/material/issues/10831">#10831</a></li>
<li><strong>menu:</strong> menu focus is lost when menu-item has custom content (<a href="https://github.com/angular/material/commit/6391b13af979e63430b0c5f162cc1389bccdef0c">6391b13</a>), closes <a href="https://github.com/angular/material/issues/12054">#12054</a></li>
<li><strong>select:</strong> floating label hidden w/ placeholder and no value (<a href="https://github.com/angular/material/commit/3ea56303a284d1c3987ec760a9b781895b39ca00">3ea5630</a>), closes <a href="https://github.com/angular/material/issues/10116">#10116</a></li>
<li><strong>select:</strong> form remains valid after empty option is selected (<a href="https://github.com/angular/material/commit/61412b4b73a05c384c86fcd272d6e7d1ce78623c">61412b4</a>), closes <a href="https://github.com/angular/material/issues/10005">#10005</a></li>
<li><strong>tabs:</strong> md-align-tabs should only affect the current component (<a href="https://github.com/angular/material/commit/d77fbc4dad198e22cb4ada396b15512f3daa3b03">d77fbc4</a>), closes <a href="https://github.com/angular/material/issues/10541">#10541</a></li>
<li><strong>theming:</strong> fix CSS with nested rules parsing when registering a theme (<a href="https://github.com/angular/material/commit/71dc4eb38d8120ba1e49a9420debfe7aaf0c8e34">71dc4eb</a>), closes <a href="https://github.com/angular/material/issues/9869">#9869</a></li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li><strong>autocomplete:</strong> allow localization of query result announcements (<a href="https://github.com/angular/material/commit/5157f94f192f64cc948adafe033361539d945408">5157f94</a>), closes <a href="https://github.com/angular/material/issues/11789">#11789</a></li>
<li><strong>chips:</strong> md-max-chips support for md-contact-chips (<a href="https://github.com/angular/material/commit/e6b5482231520a69ab196a2e508f1c1dc1f3a081">e6b5482</a>), closes <a href="https://github.com/angular/material/issues/10827">#10827</a></li>
<li><strong>datepicker:</strong> add input-aria-describedby and input-aria-labelledby (<a href="https://github.com/angular/material/commit/5f8472c433d175c39019acc271f80344d6a58ed3">5f8472c</a>), closes <a href="https://github.com/angular/material/issues/11762">#11762</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.2.2 release:</p>
<p><a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> |<a href="https://github.com/FreedCapybara"><img alt="FreedCapybara" src="https://avatars2.githubusercontent.com/u/7003723?v=4&s=117" width="117"></a> |<a href="https://github.com/shishkinilya"><img alt="shishkinilya" src="https://avatars0.githubusercontent.com/u/20458127?v=4&s=117" width="117"></a> |<a href="https://github.com/kylekatarnls"><img alt="kylekatarnls" src="https://avatars1.githubusercontent.com/u/5966783?v=4&s=117" width="117"></a> |<a href="https://github.com/natete"><img alt="natete" src="https://avatars2.githubusercontent.com/u/4098303?v=4&s=117" width="117"></a> |
:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/Splaktar">Splaktar</a> |<a href="https://github.com/FreedCapybara">FreedCapybara</a> |<a href="https://github.com/shishkinilya">shishkinilya</a> |<a href="https://github.com/kylekatarnls">kylekatarnls</a> |<a href="https://github.com/natete">natete</a> |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.2.1 Release]]></title>
            <link>https://devintent.com/blog/2020-09-23-announcing-the-angularjs-material-v1-2-1-release.md</link>
            <guid isPermaLink="false">blog/2020-09-23-announcing-the-angularjs-material-v1-2-1-release.md</guid>
            <pubDate>Wed, 23 Sep 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.2.1 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.1/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.1/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>You can now tab in and out of <code>md-calendar</code> when it is used in outside of a datepicker</li>
<li>Calendar and Datepicker regressions related to GMT+X timezones and MomentJS custom format
support have been resolved</li>
<li>Fixes a regression where <code>md-select</code> when used with the <code>md-select-header</code> attribute
and without the <code>multiple</code> attribute, closes when clicking the filter input</li>
<li>Fixes a regression where the ink-bar in <code>md-select</code> would be black instead of using the
theme color</li>
<li>We now publish a list of supported screen readers on our
<a href="https://material.angularjs.org/latest/#screen-reader-support">home page</a></li>
<li><code>md-icon</code> has been updated to match the behavior defined in the docs when you provide
<code>aria-label=""</code> or <code>alt=""</code>, i.e. apply <code>aria-hidden="true"</code></li>
<li>Improved the handling of <code>md-list-items</code> that are clickable by screen readers</li>
<li>Allow selecting the currently focused item in a radio group using the <code>space</code> key</li>
<li>We now enable iOS long-press context menus in all AngularJS Material apps. If you don't
want this behavior, you can set the <code>-webkit-touch-callout: none;</code> style on your app's
<code>html, body</code></li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>calendar:</strong> allow tabbing out when in standalone mode (<a href="https://github.com/angular/material/commit/93518bb05306e0a9d70c890a150a8c06d0fbad5b">93518bb</a>), closes <a href="https://github.com/angular/material/issues/9794">#9794</a></li>
<li><strong>calendar, datepicker:</strong> fix issues with GMT+X timezones (<a href="https://github.com/angular/material/commit/90d24cfa2914e78bbbd43e9523400f2755ed0754">90d24cf</a>), closes <a href="https://github.com/angular/material/issues/12000">#12000</a></li>
<li><strong>calendar, datepicker:</strong> fix MomentJS custom format support (<a href="https://github.com/angular/material/commit/8f9e21318f21713f1f47bd35e4742919321a9e99">8f9e213</a>), closes <a href="https://github.com/angular/material/issues/12003">#12003</a> <a href="https://github.com/angular/material/issues/11949">#11949</a></li>
<li><strong>datepicker:</strong> min-date validation is incorrect in GMT+X timezones (<a href="https://github.com/angular/material/commit/73959142c9ed327d6218fe90c6335bc88f8c5ddf">7395914</a>), closes <a href="https://github.com/angular/material/issues/11963">#11963</a></li>
<li><strong>dialog:</strong> remove focus trap focus listeners onRemove (<a href="https://github.com/angular/material/commit/33e8bac352522bf38b23ff2a4d2c281f2c14dc5f">33e8bac</a>), closes <a href="https://github.com/angular/material/issues/12010">#12010</a></li>
<li><strong>icon:</strong> providing empty alt or aria-label attributes do not hide them from a11y (<a href="https://github.com/angular/material/commit/37f15357089a87b0e3f94467a93c6511ff71d481">37f1535</a>), closes <a href="https://github.com/angular/material/issues/10721">#10721</a></li>
<li><strong>list:</strong> case where list items are read twice by screen readers (<a href="https://github.com/angular/material/commit/5c455d30b8bcf4902add2c1ed0a6e9216147b43c">5c455d3</a>), closes <a href="https://github.com/angular/material/issues/11582">#11582</a></li>
<li><strong>radio-button:</strong> Cannot read property 'nodeName' of null (<a href="https://github.com/angular/material/commit/f43ff639a678edeb387a43b28faa10ca0c8b881f">f43ff63</a>), closes <a href="https://github.com/angular/material/issues/10546">#10546</a></li>
<li><strong>radio-button:</strong> support selection using the space key (<a href="https://github.com/angular/material/commit/3cf78a7d7ed7ff2682c88eaf9e547144225e41d5">3cf78a7</a>), closes <a href="https://github.com/angular/material/issues/11960">#11960</a></li>
<li><strong>select:</strong> respect theme color when select has focus (<a href="https://github.com/angular/material/commit/4afba571c8a91e17a354c61a1ab7d711d9f9f3b6">4afba57</a>)</li>
<li><strong>select:</strong> in popup, hover and focus background colors are the same (<a href="https://github.com/angular/material/commit/d5863b8bc4a3a4666310ea03963d87537a27a69e">d5863b8</a>), closes <a href="https://github.com/angular/material/issues/000">#000</a> <a href="https://github.com/angular/material/issues/9851">#9851</a></li>
<li><strong>select:</strong> md-select-header closes on mouse click when not using multiple (<a href="https://github.com/angular/material/commit/f2fca2eea9d01be9f72e1dc2a275f1fdbc40764e">f2fca2e</a>), closes <a href="https://github.com/angular/material/issues/11969">#11969</a></li>
<li><strong>typography:</strong> enable iOS long-press context menus (<a href="https://github.com/angular/material/commit/3d98b6e276ea65417aeba0df398cbd4a6fb8fb58">3d98b6e</a>), closes <a href="https://github.com/angular/material/issues/10622">#10622</a></li>
</ul>
<h3 id="documentation">Documentation</h3>
<ul>
<li><strong>mdSticky:</strong> update and clarify the usage and behavior (<a href="https://github.com/angular/material/commit/0d431e07330f1ea42c933ae80400adfae79b60d9">0d431e0</a>)</li>
<li><strong>a11y:</strong> add a list of supported screen readers (<a href="https://github.com/angular/material/commit/8ce08134c4f305832a96a2edbe24204802a9d881">8ce0813</a>), closes <a href="https://github.com/angular/material/issues/11449">#11449</a></li>
<li><strong>home:</strong> simplify and clarify that browser support policy is for major versions (<a href="https://github.com/angular/material/commit/1babe8c83b79702a5a980d5c602da659b88db739">1babe8c</a>)</li>
<li><strong>icon:</strong> documentation refinement and cleanup (<a href="https://github.com/angular/material/commit/c644d6a29ce4d05e0bfb4588d62340157a98df52">c644d6a</a>)</li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.2.1 release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/mmalerba"><img alt="mmalerba" src="https://avatars1.githubusercontent.com/u/14793288?v=4&s=117" width="117"></a> | <a href="https://github.com/josephperrott"><img alt="josephperrott" src="https://avatars2.githubusercontent.com/u/10864441?v=4&s=117" width="117"></a> | <a href="https://github.com/cgx"><img alt="cgx" src="https://avatars2.githubusercontent.com/u/1088448?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                              <a href="https://github.com/mmalerba">mmalerba</a>                                              |                                              <a href="https://github.com/josephperrott">josephperrott</a>                                              |                                             <a href="https://github.com/cgx">cgx</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.26 Release]]></title>
            <link>https://devintent.com/blog/2020-09-01-announcing-the-angularjs-material-v1-1-26-release.md</link>
            <guid isPermaLink="false">blog/2020-09-01-announcing-the-angularjs-material-v1-1-26-release.md</guid>
            <pubDate>Tue, 01 Sep 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.26 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.26/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.26/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>Fixes a regression that broke MomentJS custom format support</li>
</ul>
<p>This is the last planned patch release for the <code>1.1.x</code> release branch. Future patch releases
will be based upon the <code>1.2.x</code> release branch.</p>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>calendar, datepicker:</strong> fix MomentJS custom format support (<a href="https://github.com/angular/material/commit/667a78f955b0980735aab744eeb5a2b22f6fbfa1">667a78f</a>), closes <a href="https://github.com/angular/material/issues/12003">#12003</a> <a href="https://github.com/angular/material/issues/11949">#11949</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.1.26 release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/mmalerba"><img alt="mmalerba" src="https://avatars0.githubusercontent.com/u/14793288?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                              <a href="https://github.com/mmalerba">mmalerba</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.25 Release]]></title>
            <link>https://devintent.com/blog/2020-08-31-announcing-the-angularjs-material-v1-1-25-release.md</link>
            <guid isPermaLink="false">blog/2020-08-31-announcing-the-angularjs-material-v1-1-25-release.md</guid>
            <pubDate>Mon, 31 Aug 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.25 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.25/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.25/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>Fixes a regression where <code>md-select</code> when used with the <code>md-select-header</code> attribute
and without the <code>multiple</code> attribute, closes when clicking the filter input</li>
<li>Fixes date selection and <code>min-date</code> validation issues in GMT+X timezones</li>
</ul>
<h3 id="knownissues">Known Issues</h3>
<ul>
<li>There is a regression that broke MomentJS custom format support. Fixed in <code>1.1.26</code>
via PR <a href="https://github.com/angular/material/pull/12006">#12006</a>.</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>calendar, datepicker:</strong> fix date selection issues with GMT+X timezones (<a href="https://github.com/angular/material/commit/a897a67cf1eee6f524dce91c5e0d31b1ad8601b3">a897a67</a>), closes <a href="https://github.com/angular/material/issues/12000">#12000</a></li>
<li><strong>datepicker:</strong> min-date validation is incorrect in GMT+X timezones (<a href="https://github.com/angular/material/commit/dd150fa780c78177521c99ed50f9fb0916fab8c8">dd150fa</a>), closes <a href="https://github.com/angular/material/issues/11963">#11963</a></li>
<li><strong>select:</strong> md-select-header closes on mouse click when not using multiple (<a href="https://github.com/angular/material/commit/b32b473ffbc645ea921f650cc425c82ba9d42bf0">b32b473</a>), closes <a href="https://github.com/angular/material/issues/11969">#11969</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.1.25 release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/jelbourn"><img alt="jelbourn" src="https://avatars3.githubusercontent.com/u/838736?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                             <a href="https://github.com/jelbourn">jelbourn</a>                                             |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.2.0 Release]]></title>
            <link>https://devintent.com/blog/2020-08-03-announcing-the-angularjs-material-v1-2-0-release.md</link>
            <guid isPermaLink="false">blog/2020-08-03-announcing-the-angularjs-material-v1-2-0-release.md</guid>
            <pubDate>Mon, 03 Aug 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.2.0 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.0/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.2.0/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a major release that includes breaking changes, deprecation removals, enhancements,
and bug fixes.</p>
<ul>
<li>Long awaited updates to align with the
<a href="https://material.io/archive/guidelines/">Material Design (2017) Specification</a>, including:</li>
<li>Button</li>
<li>Checkbox</li>
<li>Chips</li>
<li>Input and Input Container</li>
<li>List</li>
<li>Tabs</li>
<li>Palette contrast colors</li>
<li>Toolbar</li>
<li>More robust opacity and contrast configuration for theming to meet the AA level of the WAI-ARIA
accessibility guidelines.</li>
<li>The full minified CSS is now 24 KB smaller. This translates to 3 KB smaller (37 KB) gzipped.</li>
<li>Fixes and <a href="https://material.angularjs.org/latest/api/directive/mdInputContainer#aligning-form-elements">docs for aligning form components</a>
using containers with the <code>md-inline-form</code> class.</li>
<li>New Sass mixin (<code>auto-horizontal-margin($selector)</code>) for more easily laying out components
in <code>layout="row"</code> containers.</li>
<li>See below for the details on breaking changes.</li>
</ul>
<h3 id="knownissues">Known Issues</h3>
<ul>
<li><code>min-date</code> validation in <code>md-datepicker</code> is broken for GMT+T timezones
<a href="https://github.com/angular/material/issues/11963">#11963</a>.</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>autocomplete:</strong> change md-escape-options default to 'clear' (<a href="https://github.com/angular/material/commit/47106ba036eac11d4417fd2066b26d2a02283954">47106ba</a>), closes <a href="https://github.com/angular/material/issues/11767">#11767</a></li>
<li><strong>button:</strong> horizontal padding should match the spec (<a href="https://github.com/angular/material/commit/3205b33b57bc08ef92aae28ac2fb898f307c0ac1">3205b33</a>), closes <a href="https://github.com/angular/material/issues/10535">#10535</a> <a href="https://github.com/angular/material/issues/10535">#10535</a></li>
<li><strong>checkbox:</strong> handle links in transcluded label in an a11y-friendly way (<a href="https://github.com/angular/material/commit/4d36fd27be8960c9a5fceed5b8750e201668e4a0">4d36fd2</a>), closes <a href="https://github.com/angular/material/issues/11134">#11134</a></li>
<li><strong>checkbox:</strong> update CSS to match spec (<a href="https://github.com/angular/material/commit/c8930506996a56adb1cbce20a236b7c2f76cbe93">c893050</a>), closes <a href="https://github.com/angular/material/issues/9351">#9351</a> <a href="https://github.com/angular/material/issues/9927">#9927</a> <a href="https://github.com/angular/material/issues/8713">#8713</a></li>
<li><strong>checkbox, date-picker, input, radio-button, select, switch:</strong> md-inline-form support (<a href="https://github.com/angular/material/commit/b3e9ffec50cdfb560fa4bf0a32df3ad22d553291">b3e9ffe</a>)</li>
<li><strong>chips:</strong> chip remove icon isn't sized to match the spec (<a href="https://github.com/angular/material/issues/10491">#10491</a>) (<a href="https://github.com/angular/material/commit/29c0a4a7fb53bb92ef97422df8e5c9fa7199d6b1">29c0a4a</a>), closes <a href="https://github.com/angular/material/issues/9619">#9619</a></li>
<li><strong>chips:</strong> placeholder is truncated even though there is room (<a href="https://github.com/angular/material/commit/aa4e29b8a1b382ccf524abe4e654196813703412">aa4e29b</a>), closes <a href="https://github.com/angular/material/issues/10630">#10630</a></li>
<li><strong>chips:</strong> update to latest Material Design spec (2017) updates (<a href="https://github.com/angular/material/commit/01351b11754fdd661f3314b00d94e76a9de1c068">01351b1</a>), closes <a href="https://github.com/angular/material/issues/9883">#9883</a></li>
<li><strong>datepicker:</strong> support ng-model-options timezone w/ Moment (<a href="https://github.com/angular/material/commit/e24d09c68ce255ed82cac68361c8ee3dfeeb56e4">e24d09c</a>), closes <a href="https://github.com/angular/material/issues/11945">#11945</a> <a href="https://github.com/angular/material/issues/10598">#10598</a></li>
<li><strong>input-container:</strong> align indentation with spec (<a href="https://github.com/angular/material/commit/31a596f484fa32b07f42e116abad91999c4385d3">31a596f</a>), closes <a href="https://github.com/angular/material/issues/10105">#10105</a> <a href="https://github.com/angular/material/issues/11421">#11421</a></li>
<li><strong>list:</strong> fix checkbox alignment and match dense heights to spec (<a href="https://github.com/angular/material/commit/a13722ee69ab01babefe1f0bcc5af77f55a3f76c">a13722e</a>), closes <a href="https://github.com/angular/material/issues/11966">#11966</a></li>
<li><strong>nav-bar:</strong> throws exception when indexing null tabs variable (<a href="https://github.com/angular/material/commit/b1c7154bfe684c92497fb08dea6ce98af94ed1a8">b1c7154</a>), closes <a href="https://github.com/angular/material/issues/11964">#11964</a></li>
<li><strong>panel:</strong> demos need to access locals in controller's \$onInit (<a href="https://github.com/angular/material/commit/6e91c621393cd2f5260689cec2c799eef3056a2c">6e91c62</a>)</li>
<li><strong>panel:</strong> don't throw exceptions when the groupName is a string (<a href="https://github.com/angular/material/commit/4178459c4251f92fac44e4eb9f182704085a2ab9">4178459</a>)</li>
<li><strong>radio-button:</strong> when no value selected, first button not announced on focus (<a href="https://github.com/angular/material/commit/91593844b772db77c81b32461e9c5361689e7733">9159384</a>), closes <a href="https://github.com/angular/material/issues/11973">#11973</a> <a href="https://github.com/angular/material/issues/11923">#11923</a> <a href="https://github.com/angular/material/issues/11974">#11974</a></li>
<li><strong>select:</strong> support for md-inline-form, more configurable SCSS (<a href="https://github.com/angular/material/commit/0d4d37f079c44979be934c5babd4ed1c62383762">0d4d37f</a>), closes <a href="https://github.com/angular/material/issues/8712">#8712</a> <a href="https://github.com/angular/material/issues/8716">#8716</a></li>
<li><strong>select:</strong> md-select-header closes on mouse click when not using multiple (<a href="https://github.com/angular/material/commit/f2fca2eea9d01be9f72e1dc2a275f1fdbc40764e">f2fca2e</a>), closes <a href="https://github.com/angular/material/issues/11969">#11969</a></li>
<li><strong>tabs:</strong> update min-width to follow the spec (<a href="https://github.com/angular/material/commit/693eccad4e0c1605513e9b9f747cff53fef6d62a">693ecca</a>), closes <a href="https://github.com/angular/material/issues/10406">#10406</a> <a href="https://github.com/angular/material/issues/11432">#11432</a></li>
<li><strong>tabs:</strong> align theming with spec updates (<a href="https://github.com/angular/material/commit/d237715ff5cdd9238a36853ed4590c5e2f64e3b6">d237715</a>), closes <a href="https://github.com/angular/material/issues/7685">#7685</a></li>
<li><strong>theming:</strong> dark contrast used incorrectly when only contrastStrongLightColors defined (<a href="https://github.com/angular/material/commit/4e3f7a7e0839d9adce8327e67bdb9237e1e91f78">4e3f7a7</a>)</li>
<li><strong>theming:</strong> update palette contrast types to current spec (<a href="https://github.com/angular/material/commit/d716fde69983273940cf67c641c003ba3ffc32c7">d716fde</a>), closes <a href="https://github.com/angular/material/issues/8992">#8992</a> <a href="https://github.com/angular/material/issues/10164">#10164</a></li>
<li><strong>theming, toolbar, subheader, input:</strong> align color palettes and contrasts with AA standards (<a href="https://github.com/angular/material/commit/3a291ac6f6ae52093375f4c3dab5f15c4cf476b8">3a291ac</a>), closes <a href="https://github.com/angular/material/issues/8992">#8992</a> <a href="https://github.com/angular/material/issues/10164">#10164</a> <a href="https://github.com/angular/material/issues/8993">#8993</a></li>
<li><strong>toast:</strong> improve position handling to better align with docs (<a href="https://github.com/angular/material/commit/96ec741e69bfb3d2637a00366e05c11d9538371f">96ec741</a>), closes <a href="https://github.com/angular/material/issues/11843">#11843</a></li>
<li><strong>toolbar:</strong> input placeholders and ink need more contrast (<a href="https://github.com/angular/material/commit/a82fc93d54793472878da18a64ac8780295fac1f">a82fc93</a>), closes <a href="https://github.com/angular/material/issues/7987">#7987</a> <a href="https://github.com/angular/material/issues/11376">#11376</a></li>
<li><strong>toolbar:</strong> default to 500 hue and contrasts when using accent/warn palettes (<a href="https://github.com/angular/material/commit/98a94db8b4ad3ff6ec8c38b7e848574defe4f43f">98a94db</a>), closes <a href="https://github.com/angular/material/issues/7685">#7685</a></li>
</ul>
<h3 id="coderefactoring">Code Refactoring</h3>
<ul>
<li><strong>autofocus:</strong> remove deprecated md-auto-focus attribute (<a href="https://github.com/angular/material/commit/bf0ec8c853c17cd60547ead11b2c1e9310ca8377">bf0ec8c</a>)</li>
<li><strong>card:</strong> remove styles for md-actions class (<a href="https://github.com/angular/material/commit/75aa734674324df42b3e5e57508281f60d576090">75aa734</a>)</li>
<li><strong>chips:</strong> remove deprecated md-on-append attribute (<a href="https://github.com/angular/material/commit/1a2e3d0b424fec4d2e3f68071b6520a5477284c8">1a2e3d0</a>)</li>
<li><strong>chips:</strong> remove deprecated MdChipsCtrl.selectAndFocusChip (<a href="https://github.com/angular/material/commit/01d2cde76fdc127bef4d52027c143b33dc0666c0">01d2cde</a>)</li>
<li><strong>dialog:</strong> remove deprecated content options and methods (<a href="https://github.com/angular/material/commit/e3b52a0c84134faaa7371041b732ee4c3f1ec713">e3b52a0</a>)</li>
<li><strong>dialog:</strong> remove styles for deprecated md-actions class (<a href="https://github.com/angular/material/commit/93e20819053117fa2b8679178840bbb65c97a301">93e2081</a>)</li>
<li><strong>layout:</strong> remove deprecated <em>-lt-</em> ("less than") attributes (<a href="https://github.com/angular/material/commit/e8e785e5a3a118026ca8e10e087bc76aa8db745a">e8e785e</a>)</li>
<li><strong>\$mdCompilerProvider:</strong> remove deprecated \$mdCompilerProvider.respectPreAssignBindingsEnabled() (<a href="https://github.com/angular/material/commit/579a3271698381c49803210c2efaa3b1f9e802bb">579a327</a>)</li>
<li><strong>menu:</strong> removed deprecated \$mdOpenMenu API (<a href="https://github.com/angular/material/commit/f023ce766a816035fb3de8c1a47f9d089cb2f11d">f023ce7</a>)</li>
<li><strong>panel:</strong> remove deprecated MdPanelRef.addClass/removeClass/toggleClass (<a href="https://github.com/angular/material/commit/bafbd96905a016878fb45f5c6ff9992d0d743e6d">bafbd96</a>), closes <a href="https://github.com/angular/material/issues/9310">#9310</a></li>
<li><strong>select:</strong> rename ngMultiple to mdMultiple (<a href="https://github.com/angular/material/commit/4c758589f5ff8ad1b6fc1c990ffbbfd5dba913f7">4c75858</a>)</li>
<li><strong>sidenav:</strong> remove deprecated access to \$media in md-is-locked-open (<a href="https://github.com/angular/material/commit/baa7563fc9ef32c179add7071e794771f729c991">baa7563</a>)</li>
<li><strong>sidenav:</strong> remove md-sidenav-focus directive (<a href="https://github.com/angular/material/commit/8fc36d4a7ce1f15cb1398a31e5ea6cea36bcfcda">8fc36d4</a>)</li>
<li><strong>theming:</strong> remove support for deprecated \$mdThemingProviderTheme.primaryColor() and related APIs (<a href="https://github.com/angular/material/commit/00a50deb39997c73c89e5567b76b028f0cf6e16c">00a50de</a>)</li>
<li><strong>tabs:</strong> remove deprecated md-no-disconnect (<a href="https://github.com/angular/material/commit/05bee8fb2350b066a778052db08a6009c0465ee1">05bee8f</a>)</li>
<li><strong>toast:</strong> remove deprecated content() method and option and updateContent() method (<a href="https://github.com/angular/material/commit/cf3d56c74fe28b7500bd1d8bc312c132ba06d2b9">cf3d56c</a>)</li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li><strong>layout:</strong> add mixin for responsive support of rows (<a href="https://github.com/angular/material/commit/c2c336b946b8c017c12dcb80955767339da3eb3b">c2c336b</a>), closes <a href="https://github.com/angular/material/issues/9112">#9112</a> <a href="https://github.com/angular/material/issues/9220">#9220</a></li>
<li><strong>theming:</strong> add contrast opacity values for all color types and hues (<a href="https://github.com/angular/material/commit/68c1d02fb40951ea95bf3a136e12e0ff66b2a780">68c1d02</a>)</li>
</ul>
<h3 id="documentation">Documentation</h3>
<ul>
<li><strong>theming, colors:</strong> md-colors demo was broken. improve JSDoc and fix lint issues (<a href="https://github.com/angular/material/commit/01917b37ec6a8b6a913f9594130b841912e37244">01917b3</a>)</li>
</ul>
<h3 id="breakingchanges">BREAKING CHANGES</h3>
<ul>
<li><strong>autocomplete:</strong> The default behavior of <code>md-autocomplete</code>, when the options panel is visible and the Escape key is pressed, has changed. <code>md-escape-options</code> now defaults to <code>'clear'</code> instead of <code>'blur clear'</code>. This better aligns with the <a href="https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.0pattern/combobox-autocomplete-list.html">WAI-ARIA Authoring Practices</a> as the focus is not sent to another element (like the <code>&lt;body&gt;</code>) when the Escape key is pressed.</li>
</ul>
<p>If you want to restore the previous behavior, add the following to your <code>md-autocomplete</code> components:</p>
<pre><code class="html language-html">md-escape-options="blur clear"
</code></pre>
<ul>
<li><strong>autofocus:</strong> Removed the deprecated <code>md-auto-focus</code> directive. It was deprecated in favor of <code>md-autofocus</code>. Please see the <a href="https://material.angularjs.org/latest/api/directive/mdAutofocus">md-autofocus Docs</a> for examples.</li>
<li><strong>button:</strong> <code>md-button</code>'s internal horizontal padding has changed from <code>6px</code> to <code>8px</code> to match the Material Design spec. This may affect the layout of portions of your application where <code>md-button</code>, <code>md-datepicker</code>, or <code>md-toast</code> with actions are used.</li>
</ul>
<p>If you are using our SCSS files, you can override this back to the default, or another value, in your app's SCSS files:</p>
<pre><code class="scss language-scss">$button-left-right-padding: rem(0.6); // For 6px horizontal padding
</code></pre>
<ul>
<li><strong>card:</strong> Removed support for the <code>class="md-actions"</code> inside of an <code>md-card</code> template. This is deprecated in favor of using the <code>&lt;md-card-actions&gt;</code> element.</li>
<li><strong>checkbox:</strong> If you've created a custom solution to style links within <code>md-checkbox</code> labels, then you may need to remove or change that code now. This is because we automatically detect <code>&lt;a&gt;</code> tags in these labels and re-render them in an accessible way.</li>
<li><strong>checkbox:</strong> The default size and spacing for <code>md-checkbox</code> has been updated to align with the Material Design specification. Additionally, many new Sass variables have been added for customizing the size and spacing of <code>md-checkbox</code>. The <code>md-dense</code> class is now supported. After updating to this version, you may need to adjust the layout of your app due to the larger touch-friendly size of checkbox. You may also want to make use of <code>md-dense</code> in cases where space is limited.</li>
<li><strong>chips:</strong> Chips have been updated to latest Material Design spec (2017). <code>$chip-font-size</code> was reduced to <code>13px</code> from <code>16px</code>. <code>$chip-remove-padding-right</code> was increased to <code>28px</code> from <code>22px</code>. These changes may cause your chips to have a smaller, denser layout now. In certain scenarios, this may require minor changes to your app's layout. You can change these variables back to their old values if your app consumes Sass. Additionally, the remove chip icon has been changed, but you can use the custom chip template demo as a guide to changing back to the old icon, if desired.</li>
<li><strong>chips:</strong> Removed the deprecated, since 2015, <code>md-on-append</code> attribute. It was deprecated in favor of <code>md-transform-chip</code> or the simple notifier <code>md-on-add</code>. Please see the <a href="https://material.angularjs.org/latest/demo/chips">md-chips Demos</a> for examples of using <code>md-transform-chip</code>.</li>
<li><strong>chips:</strong> The deprecated <code>MdChipsCtrl.selectAndFocusChip()</code> function has been removed.
<code>MdChipsCtrl.selectAndFocusChipSafe()</code> should be used instead.</li>
<li><strong>dialog:</strong> Removed support for the deprecated <code>class="md-actions"</code> inside of an <code>md-dialog</code> template. This was deprecated in favor of using the <code>&lt;md-dialog-actions&gt;</code> element.</li>
<li><strong>dialog:</strong> Removed support for the deprecated <code>.content('string')</code> methods and options. These were deprecated in favor of <code>.textContent('string')</code> and <code>.htmlContent('sanitized-string')'</code> methods and their associated options. Please note that use of <code>.htmlContent</code> requires that the <code>ngSanitize</code> module be loaded.</li>
</ul>
<p>If you have</p>
<pre><code class="js language-js">alert = $mdDialog.alert().content('This is an example.');
</code></pre>
<p>It needs to be changed to</p>
<pre><code class="js language-js">alert = $mdDialog.alert().textContent('This is an example.');
</code></pre>
<p>If you have</p>
<pre><code class="js language-js">alert = $mdDialog.alert({
  content: 'This is an example.',
});
</code></pre>
<p>It needs to be changed to</p>
<pre><code class="js language-js">alert = $mdDialog.alert({
  textContent: 'This is an example.',
});
</code></pre>
<ul>
<li><p><strong>input-container:</strong> <code>md-input</code> and <code>md-select</code> inside of <code>md-input-container</code>s have been updated to use indentation that is consistent with the spec (aligned to the left in LTR and the right in RTL). This may cause some minor layout issues in apps that depended upon the previous <code>2px</code> padding inside of <code>md-input-container</code>.</p></li>
<li><p><strong>layout:</strong> The way that margins are applied to <code>md-checkbox</code>, <code>md-input-container</code>, <code>md-radio-group</code>, and <code>md-select</code> has been changed. You can now use the <code>$default-horizontal-margin</code> Sass variable to override the default <code>16px</code> horizontal margin size. As part of this, <code>md-radio-button</code>s inside of <code>layout="row"</code> containers are now aligned vertically with other content as they no longer have a <code>16px</code> <code>margin-bottom</code>. If you have previously added custom styles, to your components inside of a row layout, in order to give them extra <code>margin-right</code> in LTR or <code>margin-left</code> in RTL, you will need to re-evaluate those styles. In most cases, they can now be removed.</p></li>
<li><p><strong>layout:</strong> Removed the deprecated, undocumented <code>*-lt-*</code> layout attributes and classes. This includes the following attributes and their matching classes, which have been giving deprecation warnings since 2015:</p></li>
<li><p>layout-lt-md</p></li>
<li><p>layout-lt-lg</p></li>
<li><p>flex-lt-md</p></li>
<li><p>flex-lt-lg</p></li>
<li><p>layout-align-lt-md</p></li>
<li><p>layout-align-lt-lg</p></li>
<li><p>flex-order-lt-md</p></li>
<li><p>flex-order-lt-lg</p></li>
<li><p>flex-offset-lt-md</p></li>
<li><p>flex-offset-lt-lg</p></li>
<li><p>hide-lt-md</p></li>
<li><p>hide-lt-lg</p></li>
<li><p>show-lt-md</p></li>
<li><p>show-lt-lg</p></li>
<li><p><strong>list:</strong> <code>md-list</code> with the <code>md-dense</code> class has been updated to align with the Material Design specification. This means that <code>md-list-item</code>s heights have changed when using <code>md-dense</code>. The <code>md-dense-disabled</code> class is now supported on <code>md-list</code>. After updating to this version, you may need to adjust the layout of your app if you use <code>md-dense</code> with <code>md-list</code> or customize the layout of <code>md-checkbox</code>s within <code>md-list-item</code>s.</p></li>
<li><p><strong>\$mdCompilerProvider:</strong> The deprecated <code>$mdCompilerProvider.respectPreAssignBindingsEnabled()</code> API has been removed.
We no longer respect AngularJS's <code>$compileProvider.preAssignBindingsEnabled()</code> value as this API was removed
in AngularJS <code>1.7.0</code>.</p></li>
</ul>
<p>If you had the recommended configuration for AngularJS 1.6.x:</p>
<pre><code class="js language-js">$compileProvider.preAssignBindingsEnabled(false);
$mdCompilerProvider.respectPreAssignBindingsEnabled(true);
</code></pre>
<p>Then you should remove both of these calls as they are now the defaults in AngularJS <code>1.7.0</code>
and AngularJS Material <code>1.2.0</code>.</p>
<p>If you had the recommended configuration for AngularJS 1.7+:</p>
<pre><code class="js language-js">$mdCompilerProvider.respectPreAssignBindingsEnabled(true);
</code></pre>
<p>Then you should remove this call as it is now the default in AngularJS Material <code>1.2.0</code>.</p>
<p>If you were using a backwards-compatible configuration for AngularJS 1.6+:</p>
<pre><code class="js language-js">$mdCompilerProvider.respectPreAssignBindingsEnabled(false);
</code></pre>
<p>Then you will need to remove this call and may need to refactor your Controllers for
AngularJS Material components like <code>$mdDialog</code>, <code>$mdPanel</code>, <code>$mdToast</code>, or <code>$mdBottomSheet</code>.</p>
<p>For example:</p>
<pre><code class="js language-js"> $mdDialog.show({
   locals: {
     myVar: true
   },
   controller: MyController,
   bindToController: true
 }
  function MyController() {
   // No locals from Angular Material are available. e.g myVar is undefined.
   // You would need to move anything accessing locals in here to $onInit().
 }
  MyController.prototype.$onInit = function() {
   // Bindings are now available in the $onInit lifecycle hook.
 }
</code></pre>
<ul>
<li><strong>menu:</strong> Removed the deprecated <code>$mdOpenMenu</code> API. It was deprecated in favor of <code>$mdMenu.open</code>.</li>
<li><strong>panel:</strong> The deprecated <code>MdPanelRef.addClass()</code>, <code>MdPanelRef.removeClass()</code>, and <code>MdPanelRef.toggleClass()</code> functions have been removed. These were deprecated in 2016 in favor of using the <code>panelContainer</code> or <code>panelEl</code> JQLite elements that are referenced in the <a href="https://material.angularjs.org/latest/api/type/MdPanelRef">MdPanelRef</a> object.</li>
<li><strong>select:</strong> <code>ngMultiple</code> has been renamed to <code>mdMultiple</code> to make it clear that this
API is provided by AngularJS Material and not by AngularJS.</li>
</ul>
<p>If you had:</p>
<pre><code class="html language-html">&lt;md-select ng-multiple="expression"&gt;...&lt;/md-select&gt;
</code></pre>
<p>You need to change to:</p>
<pre><code class="html language-html">&lt;md-select md-multiple="expression"&gt;...&lt;/md-select&gt;
</code></pre>
<ul>
<li><strong>sidenav:</strong> Removed access for the deprecated <code>$media</code> service in <code>md-is-locked-open</code>. This was deprecated in favor of the <code>$mdMedia</code> service. The functionality is the same and only a rename to the current name of the service is required.</li>
<li><strong>sidenav:</strong> Removed the <code>md-sidenav-focus</code> directive. It was deprecated in favor of <code>md-autofocus</code>. Please see the <a href="https://material.angularjs.org/latest/api/directive/mdAutofocus">md-autofocus Docs</a> and <a href="https://material.angularjs.org/latest/demo/sidenav#basic-usage">md-sidenav Basic Usage Demo</a> for examples.</li>
<li><strong>tabs:</strong> Tab items now have a <code>min-width</code> and <code>padding</code> which matches the Material Design specification. For width, this is <code>72px</code> on <code>xs</code> screens and <code>160px</code> on all other screens. For left and right <code>padding</code>, this is now <code>12px</code> instead of <code>24px</code>. If your app needs to have tabs which are smaller than the spec, you will need to override <code>md-tab-item</code>'s <code>min-width</code> and <code>md-tab</code>'s <code>padding</code> styles.</li>
<li><strong>theming:</strong> Removed support for the deprecated <code>$mdThemingProviderTheme.primaryColor()</code> and the related accent/warn/background APIs. These were deprecated in favor of <code>$mdThemingProviderTheme.primaryPalette()</code> (and accent/warn/background) in 2015 and they have been logging warnings when used since then.</li>
<li><strong>theming, toolbar, subheader, input:</strong> The contrast colors (the text or icon color, for example on a raised button) of many of our default palettes have been updated to meet the <a href="https://www.w3.org/TR/WCAG21/#contrast-minimum">AA level of the contrast guidelines</a> for web accessibility. If you are using our default palettes directly, the accessibility of your application should be improved. However, we recommend that you evaluate this after updating to <code>1.2.0</code>. There may be edge cases in your app or custom styles that need to be updated to meet accessibility guidelines.</li>
</ul>
<p>If you find significant accessibility issues after updating, please report them to us. In <code>1.2.x</code>, we have a lot more control over our component theming in regards to hues and opacities.</p>
<p>If your app is using a custom palette, whether based on a copy of default palette or not, we encourage you to evaluate that your contrast configuration meets the WebAIM guidelines. Please review our guide on <a href="https://material.angularjs.org/latest/Theming/03_configuring_a_theme#defining-custom-palettes">Defining Custom Palettes</a> for details.</p>
<ul>
<li><strong>toast:</strong> <code>$mdToast.show()</code>'s position behavior has been updated to be consistent with the documentation. If you relied on the previously undocumented behavior where it defaulted to <code>top left</code> instead of <code>bottom left</code>, you will need to update your app.</li>
</ul>
<p>Change your code from this:</p>
<pre><code class="js language-js">    $mdToast.show(
      $mdToast.simple()
      .textContent('Simple Toast!'))
    .then(...
</code></pre>
<p>To this:</p>
<pre><code class="js language-js">    $mdToast.show(
      $mdToast.simple()
      .textContent('Simple Toast!')
      .position('top left'))
    .then(...
</code></pre>
<ul>
<li><strong>toast:</strong> The deprecated <code>content()</code> and <code>updateContent()</code> methods have been removed.</li>
</ul>
<p>If you had:</p>
<pre><code class="js language-js">$mdToast.show($mdToast.simple().content('This no longer works.'));
</code></pre>
<p>You will need to change to:</p>
<pre><code class="js language-js">$mdToast.show($mdToast.simple().textContent('This works.'));
</code></pre>
<p>If you had:</p>
<pre><code class="js language-js">$mdToast.updateContent('This no longer works.');
</code></pre>
<p>You will need to change to:</p>
<pre><code class="js language-js">$mdToast.updateTextContent('This works.');
</code></pre>
<p>If you had:</p>
<pre><code class="js language-js">$mdToast.show($mdToast.simple({ parent: parent, content: 'This no longer works.', theme: 'some-theme', capsule: true }));
</code></pre>
<p>You will need to change to:</p>
<pre><code class="js language-js">$mdToast.show($mdToast.simple({ parent: parent, textContent: 'This works.', theme: 'some-theme', capsule: true }));
</code></pre>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.2.0 release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/jelbourn"><img alt="jelbourn" src="https://avatars3.githubusercontent.com/u/838736?v=4&s=117" width="117"></a> | <a href="https://github.com/clshortfuse"><img alt="clshortfuse" src="https://avatars3.githubusercontent.com/u/9271155?v=4&s=117" width="117"></a> | <a href="https://github.com/oliversalzburg"><img alt="oliversalzburg" src="https://avatars2.githubusercontent.com/u/1658949?v=4&s=117" width="117"></a> | <a href="https://github.com/batsauto"><img alt="batsauto" src="https://avatars3.githubusercontent.com/u/17678174?v=4&s=117" width="117"></a> | <a href="https://github.com/wagnermaciel"><img alt="wagnermaciel" src="https://avatars1.githubusercontent.com/u/25158423?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                             <a href="https://github.com/jelbourn">jelbourn</a>                                             |                                             <a href="https://github.com/clshortfuse">clshortfuse</a>                                              |                                             <a href="https://github.com/oliversalzburg">oliversalzburg</a>                                              |                                              <a href="https://github.com/batsauto">batsauto</a>                                              |                                              <a href="https://github.com/wagnermaciel">wagnermaciel</a>                                              |</p>
<p>| <a href="https://github.com/tomaszgrabowski"><img alt="tomaszgrabowski" src="https://avatars0.githubusercontent.com/u/6688790?v=4&s=117" width="117"></a> |
| :--------------------------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/tomaszgrabowski">tomaszgrabowski</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.24 Release]]></title>
            <link>https://devintent.com/blog/2020-06-29-announcing-the-angularjs-material-v1-1-24-release.md</link>
            <guid isPermaLink="false">blog/2020-06-29-announcing-the-angularjs-material-v1-1-24-release.md</guid>
            <pubDate>Mon, 29 Jun 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.24 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.24/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.24/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>Fixes <code>$mdPanel</code> animation bugs</li>
<li>Datepicker now passes <code>ng-model-options</code> on to calendar so that they both use the same timezone settings</li>
<li>Fixes <code>md-datepicker</code> to work with a custom config via <code>$mdDateLocaleProvider</code>, including MomentJS</li>
</ul>
<h3 id="knownissues">Known Issues</h3>
<ul>
<li><code>min-date</code> validation in <code>md-datepicker</code> is broken for GMT+T timezones
<a href="https://github.com/angular/material/issues/11963">#11963</a>. Planned for in <code>1.1.25</code>.</li>
<li><code>md-select</code> using <code>md-select-header</code> closes on mouse click when not using multiple
<a href="https://github.com/angular/material/issues/11969">#11969</a>. Will be fixed in <code>1.1.25</code>.</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>datepicker:</strong> support <code>ng-model-options</code> timezone w/ MomentJS and datepicker now passes <code>ng-model-options</code> on to calendar (<a href="https://github.com/angular/material/commit/12562b0e0c47472477729ed54b9aa30bfc4110e3">12562b0</a>), closes <a href="https://github.com/angular/material/issues/11945">#11945</a> <a href="https://github.com/angular/material/issues/10598">#10598</a></li>
<li><strong>panel:</strong> animated panels never appear on the screen (<a href="https://github.com/angular/material/commit/e81e2e33cccd414310f47ef9cec22aa54dd604a7">e81e2e3</a>), closes <a href="https://github.com/angular/material/issues/11946">#11946</a></li>
<li><strong>panel:</strong> inline transforms accumulate after each time the close animation runs (<a href="https://github.com/angular/material/commit/6322e982db2ebe5bc99bddcf1e6ffde4c5041305">6322e98</a>), closes <a href="https://github.com/angular/material/issues/11946">#11946</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.1.24 release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/mmalerba"><img alt="mmalerba" src="https://avatars1.githubusercontent.com/u/14793288?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                              <a href="https://github.com/mmalerba">mmalerba</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.23 Release]]></title>
            <link>https://devintent.com/blog/2020-06-18-announcing-the-angularjs-material-v1-1-23-release.md</link>
            <guid isPermaLink="false">blog/2020-06-18-announcing-the-angularjs-material-v1-1-23-release.md</guid>
            <pubDate>Thu, 18 Jun 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.23 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.23/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.23/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>Adds a <code>md-month-filter</code> API to <code>md-datepicker</code> and <code>md-calendar</code></li>
<li>Fixes issue with the <code>md-date-filter</code> API</li>
<li>Adds support for the <code>$onDestroy</code> hook in <code>$mdCompiler</code></li>
<li>Fixes a number of issues with <code>$mdPanel</code> animations</li>
<li>Many fixes for <code>md-select</code> including bringing back support for <code>ng-selected</code> on <code>md-option</code></li>
<li>Adds <code>md-calendar</code> support for specifying timezone in <code>ng-model-options</code></li>
</ul>
<h3 id="knownissues">Known Issues</h3>
<ul>
<li><code>md-datepicker</code> throws exceptions if you specify a custom config via <code>$mdDateLocaleProvider</code>
<a href="https://github.com/angular/material/issues/11945">#11945</a>. Fixed in <code>1.1.24</code>.</li>
<li><code>min-date</code> validation in <code>md-datepicker</code> is broken for GMT+T timezones
<a href="https://github.com/angular/material/issues/11963">#11963</a></li>
<li>Panels sometimes don't appear <a href="https://github.com/angular/material/issues/11946">11946</a>.
Fixed in <code>1.1.24</code>.</li>
<li><code>md-select</code> using <code>md-select-header</code> closes on mouse click when not using multiple
<a href="https://github.com/angular/material/issues/11969">#11969</a>. Will be fixed in <code>1.1.25</code>.</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>calendar, datepicker:</strong> in year view, <code>md-date-filter</code> only evaluates first day of month (<a href="https://github.com/angular/material/commit/3d5ff5db56d3b84b2c7d813886d13ef831b7a295">3d5ff5d</a>), closes <a href="https://github.com/angular/material/issues/11703">#11703</a></li>
<li><strong>compiler:</strong> <code>$onDestroy</code> hook not called (<a href="https://github.com/angular/material/commit/8bb1d9811e39ae26e79f629902c3be619eba8b30">8bb1d98</a>), closes <a href="https://github.com/angular/material/issues/11847">#11847</a></li>
<li><strong>datepicker:</strong> update error state only after <code>$validate</code> has run (<a href="https://github.com/angular/material/commit/11f65e3371eb5fcffba0c1194ef3f9b022d0cf87">11f65e3</a>), closes <a href="https://github.com/angular/material/issues/10360">#10360</a></li>
<li><strong>layout:</strong> Syntax Error: Token <code>'&amp;&amp;'</code> not a primary expression (<a href="https://github.com/angular/material/pull/11940">#11940</a>) (<a href="https://github.com/angular/material/commit/1bd1a97d7d22921e2cfb1fcb940f485a095130f8">1bd1a97</a>), closes <a href="https://github.com/angular/material/issues/10935">#10935</a></li>
<li><strong>list:</strong> allow overriding <code>md-list-item</code> padding for clickable items (<a href="https://github.com/angular/material/commit/f7d9027e9b0a91050213372cc0dfa52230d528d1">f7d9027</a>), closes <a href="https://github.com/angular/material/issues/10384">#10384</a></li>
<li><strong>menuBar:</strong> close top nested menu when escape key is pressed (<a href="https://github.com/angular/material/commit/98e259bec4dc026fa38fb1a5c16a6c4f37722e7a">98e259b</a>), closes <a href="https://github.com/angular/material/issues/11678">#11678</a></li>
<li><strong>navBar:</strong> update inkbar on screen resize (<a href="https://github.com/angular/material/commit/c1e2b1277e59fd802e0e1e2da7eee492d39b84b0">c1e2b12</a>), closes <a href="https://github.com/angular/material/issues/10121">#10121</a></li>
<li><strong>panel:</strong> allow transform to be animated on an offset panel (<a href="https://github.com/angular/material/commit/269b68e8540062e2a0e195edb54a75903b17fdd0">269b68e</a>), closes <a href="https://github.com/angular/material/issues/9641">#9641</a> <a href="https://github.com/angular/material/issues/9905">#9905</a></li>
<li><strong>panel:</strong> consolidate redundant validations (<a href="https://github.com/angular/material/issues/9631">#9631</a>) (<a href="https://github.com/angular/material/commit/a3341349631e5a2df4d4a6e0b9a527206f1b7686">a334134</a>)</li>
<li><strong>panel:</strong> invisible after hide/show cycle (<a href="https://github.com/angular/material/commit/a3c533f1c657588d4625c2b26c7b59ba7eeefb25">a3c533f</a>), closes <a href="https://github.com/angular/material/issues/11291">#11291</a></li>
<li><strong>progress-circular:</strong> correct rendering for diameter bigger than 60 (<a href="https://github.com/angular/material/issues/11896">#11896</a>) (<a href="https://github.com/angular/material/commit/0cca317c3dfb6455609c840d2b03bb575a4cc35b">0cca317</a>), closes <a href="https://github.com/angular/material/issues/10376">#10376</a></li>
<li><strong>progress-linear, progress-circular:</strong> mirror indicator when rtl is on (<a href="https://github.com/angular/material/pull/11895">#11895</a>) (<a href="https://github.com/angular/material/commit/9fc2f3fbb9d61fcdcbd32bdbdedca0d2cc9d4664">9fc2f3f</a>), closes <a href="https://github.com/angular/material/issues/10814">#10814</a></li>
<li><strong>select:</strong> height changes when disabled (<a href="https://github.com/angular/material/commit/e2af2a3f7fa05de81729d976512304c0f90f2891">e2af2a3</a>), closes <a href="https://github.com/angular/material/issues/11812">#11812</a></li>
<li><strong>select:</strong> <code>md-focused</code> not removed from options on panel close (<a href="https://github.com/angular/material/commit/5a7e967d9f2a7d568d6b9ede7a8e6a47d9270265">5a7e967</a>), closes <a href="https://github.com/angular/material/issues/11927">#11927</a></li>
<li><strong>select:</strong> optgroups are not visible to screen readers (<a href="https://github.com/angular/material/commit/5fbabe7e107a623303bcbcfed5c6d9e194f417e2">5fbabe7</a>), closes <a href="https://github.com/angular/material/issues/11240">#11240</a></li>
<li><strong>select:</strong> perform correct position calculation in rtl for long labels (<a href="https://github.com/angular/material/pull/11894">#11894</a>) (<a href="https://github.com/angular/material/commit/9f49e1043b98977ab4e7e1053d0f4ea5ee978df5">9f49e10</a>), closes <a href="https://github.com/angular/material/issues/10395">#10395</a></li>
<li><strong>select:</strong> revert removal of support for <code>ng-selected</code> on <code>md-options</code> (<a href="https://github.com/angular/material/commit/546bd84b6c8e784aa43e88b926a117f077e1200c">546bd84</a>), closes <a href="https://github.com/angular/material/issues/11914">#11914</a></li>
<li><strong>slider:</strong> vertical slider in a scrolled container sets value to zero on all clicks (<a href="https://github.com/angular/material/issues/11801">#11801</a>) (<a href="https://github.com/angular/material/commit/79bf96b64e992a99a10145ee6b5a2479afaa5d21">79bf96b</a>), closes <a href="https://github.com/angular/material/issues/11800">#11800</a></li>
<li><strong>toast:</strong> <code>onRemove</code> doesn't return a <code>Promise</code> in some cases (<a href="https://github.com/angular/material/commit/e625a9ce108722a061bf087ee3b1a600ceee3fb9">e625a9c</a>), closes <a href="https://github.com/angular/material/issues/10379">#10379</a></li>
<li><strong>toolbar:</strong> <code>md-scroll-shrink</code> conflicts with <code>md-select</code> in toolbar (<a href="https://github.com/angular/material/commit/1ed54bb90bc9c71cce4575e325250606d97fa867">1ed54bb</a>), closes <a href="https://github.com/angular/material/issues/10413">#10413</a> <a href="https://github.com/angular/material/issues/9871">#9871</a></li>
<li><strong>tooltip:</strong> change from <code>inline</code> to <code>inline-block</code> to account for <code>md-panel</code> change (<a href="https://github.com/angular/material/commit/20194ba2f11227f0e3965089af598e9c89ce71a6">20194ba</a>)</li>
<li><strong>util:</strong> sanitize function used by select and autocomplete throws "Invalid regular expression" when typing "<code>(</code>" (<a href="https://github.com/angular/material/commit/bc71d0b0b6dd58a3025d8d65a309841783ebb0a9">bc71d0b</a>), closes <a href="https://github.com/angular/material/issues/11908">#11908</a></li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li><strong>calendar:</strong> support specifying timezone in <code>ng-model-options</code> (<a href="https://github.com/angular/material/commit/2a01746c4fbea1bbd2ca82808a6e9f0f979a2968">2a01746</a>), closes <a href="https://github.com/angular/material/issues/10431">#10431</a></li>
<li><strong>input:</strong> add animation to color change (<a href="https://github.com/angular/material/issues/10079">#10079</a>) (<a href="https://github.com/angular/material/commit/b486a4104e2fdfdac8563b0c301fb3bfaf060142">b486a41</a>)</li>
<li><strong>select:</strong> add the ability to pre-select the only option in the list (<a href="https://github.com/angular/material/issues/9940">#9940</a>) (<a href="https://github.com/angular/material/commit/6372027e8c042845c302dfd52d8cd490faf1f43e">6372027</a>), closes <a href="https://github.com/angular/material/issues/9626">#9626</a></li>
</ul>
<h3 id="documentation">Documentation</h3>
<ul>
<li><strong>codepen:</strong> update for AngularJS <code>1.8.0</code></li>
<li><strong>security:</strong> added <a href="https://github.com/angular/material/blob/master/SECURITY.md">Security Policy</a></li>
<li><strong>tabs:</strong> improve correctness of API docs and types <a href="https://github.com/angular/material/commit/a17ef4fa9f7fe0ca812364fb9256f75c17d99442">a17ef4f</a>, closes <a href="https://github.com/angular/material/issues/10407">#10407</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the v1.1.23 release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/crisbeto"><img alt="crisbeto" src="https://avatars0.githubusercontent.com/u/4450522?v=4&s=117" width="117"></a> | <a href="https://github.com/marosoft"><img alt="marosoft" src="https://avatars0.githubusercontent.com/u/3945455?v=4&s=117" width="117"></a> | <a href="https://github.com/nnmrts"><img alt="nnmrts" src="https://avatars0.githubusercontent.com/u/20396367?v=4&s=117" width="117"></a> | <a href="https://github.com/Thaina"><img alt="Thaina" src="https://avatars1.githubusercontent.com/u/1042507?v=4&s=117" width="117"></a> | <a href="https://github.com/chmelevskij"><img alt="chmelevskij" src="https://avatars1.githubusercontent.com/u/7774918?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                             <a href="https://github.com/crisbeto">crisbeto</a>                                              |                                             <a href="https://github.com/marosoft">marosoft</a>                                              |                                              <a href="https://github.com/nnmrts">nnmrts</a>                                              |                                             <a href="https://github.com/Thaina">Thaina</a>                                              |                                             <a href="https://github.com/chmelevskij">chmelevskij</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.22 Release]]></title>
            <link>https://devintent.com/blog/2020-05-04-announcing-the-angularjs-material-v1-1-22-release.md</link>
            <guid isPermaLink="false">blog/2020-05-04-announcing-the-angularjs-material-v1-1-22-release.md</guid>
            <pubDate>Mon, 04 May 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.22 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.22/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.22/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>A number of significant fixes for <code>md-select</code> including an a11y overhaul</li>
<li>Lots of important fixes for <code>md-list</code></li>
<li>Fixes for <code>md-autocomplete</code> including a regression fix for <code>md-not-found</code> and some usability improvements</li>
</ul>
<h3 id="knownissues">Known Issues</h3>
<ul>
<li><code>md-select</code> using <code>md-select-header</code> closes on mouse click when not using multiple
<a href="https://github.com/angular/material/issues/11969">#11969</a>. Will be fixed in <code>1.1.25</code>.</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>autocomplete:</strong> loop options list when moving past first/last option with arrow keys (<a href="https://github.com/angular/material/commit/5228f23b963b8d3811c916c2403469b92b2cca7e">5228f23</a>), closes <a href="https://github.com/angular/material/issues/11766">#11766</a></li>
<li><strong>autocomplete:</strong> <code>md-not-found</code> template is not styled properly (<a href="https://github.com/angular/material/commit/ce6e2ff13702cd462a1b45c06753d16278270ba1">ce6e2ff</a>), closes <a href="https://github.com/angular/material/issues/11852">#11852</a></li>
<li><strong>autocomplete:</strong> Move mouse enter and leave events to container (<a href="https://github.com/angular/material/commit/5b0c9ba9e0e5313925f6a27390559f32028fd95b">5b0c9ba</a>), closes <a href="https://github.com/angular/material/issues/11776">#11776</a></li>
<li><strong>autocomplete:</strong> scroll to top of the list each time dropdown open (<a href="https://github.com/angular/material/commit/498c9edd26e878d53e8f1b02a86380fe1b9895b1">498c9ed</a>), closes <a href="https://github.com/angular/material/issues/10479">#10479</a></li>
<li><strong>contact-chips:</strong> don't rely on debug info to get access to controller scope (<a href="https://github.com/angular/material/commit/2f770957f7d38d9c1386767b82bd662c07af9787">2f77095</a>), closes <a href="https://github.com/angular/material/issues/11699">#11699</a></li>
<li><strong>datepicker:</strong> <code>md-open-on-focus</code> fails when switching tabs with open datepicker (<a href="https://github.com/angular/material/commit/7a16778ecc08593463c361b33b4fe17154b8cb75">7a16778</a>)</li>
<li><strong>gesture:</strong> 'drag' gestures don't clean up touch action styles on parent (<a href="https://github.com/angular/material/commit/deb3dfc11e76ea38c2ec65a2a9b4d68560d0c181">deb3dfc</a>), closes <a href="https://github.com/angular/material/issues/11147">#11147</a></li>
<li><strong>list:</strong> dense lists cut off descenders of letters like gjqpy (<a href="https://github.com/angular/material/commit/0ab73bd86ab3f5e564ef73663e3f70e2404b2538">0ab73bd</a>), closes <a href="https://github.com/angular/material/issues/8890">#8890</a></li>
<li><strong>list:</strong> <code>isEventFromControl()</code> works on all browsers now (<a href="https://github.com/angular/material/commit/d537d251d7281ed446ce5b5502a123884e1af9f4">d537d25</a>), closes <a href="https://github.com/angular/material/issues/7937">#7937</a></li>
<li><strong>list:</strong> primary action is fired twice on space/enter keydown (<a href="https://github.com/angular/material/commit/920018efbd51ed4f164db3fa02da721d3148da43">920018e</a>), closes <a href="https://github.com/angular/material/issues/11756">#11756</a></li>
<li><strong>list:</strong> secondary actions give aria warning if text is in a span (<a href="https://github.com/angular/material/commit/90c8b8d6f6265b3c5b71f38fa847dc5c6bb9ce04">90c8b8d</a>), closes <a href="https://github.com/angular/material/issues/6152">#6152</a></li>
<li><strong>menu-bar:</strong> <code>z-index</code> not restored on menu close (<a href="https://github.com/angular/material/commit/4a4dde489835dd1c2ef221563bb5f2fd9fc9bddf">4a4dde4</a>), closes <a href="https://github.com/angular/material/issues/11235">#11235</a></li>
<li><strong>nav-bar:</strong> clicked nav item not focused or selected in some cases (<a href="https://github.com/angular/material/commit/4d4e0ac9487c9a632447fa5ecf38941934c3cf2c">4d4e0ac</a>), closes <a href="https://github.com/angular/material/issues/11747">#11747</a></li>
<li><strong>select:</strong> overhaul screen reader support (<a href="https://github.com/angular/material/commit/928c71d6ee87bc03ce383bfa555f67e1d373fe13">928c71d</a>), closes <a href="https://github.com/angular/material/issues/10748">#10748</a> <a href="https://github.com/angular/material/issues/10967">#10967</a></li>
<li><strong>select:</strong> sanitize user input before searching options (<a href="https://github.com/angular/material/issues/11855">#11855</a>) (<a href="https://github.com/angular/material/commit/0ec0cc5ee8aac0db6103ae4c1ee1fc30620247b2">0ec0cc5</a>), closes <a href="https://github.com/angular/material/issues/11854">#11854</a></li>
<li><strong>select:</strong> when using <code>trackBy</code>, trigger <code>ng-change</code> only when tracked property is different (<a href="https://github.com/angular/material/commit/ecd55d0dd2d52c746e4aa907bfd3712f6c03a68a">ecd55d0</a>), closes <a href="https://github.com/angular/material/issues/11108">#11108</a></li>
<li><strong>select:</strong> <code>menuController</code> not defined edge case in <code>focusOptionNode()</code> (<a href="https://github.com/angular/material/commit/b9d832209f8b9e25b4bc5dc2654bf18421144816">b9d8322</a>), closes <a href="https://github.com/angular/material/issues/11885">#11885</a></li>
</ul>
<h3 id="documentation">Documentation</h3>
<ul>
<li><strong>vscode:</strong> add VSCode configuration and guide (<a href="https://github.com/angular/material/pull/11879">#11879</a>) (<a href="https://github.com/angular/material/commit/a8954dfaded6b5ae36aa35eaba3f33602f1e9da3">a8954df</a>)</li>
<li><strong>dialog:</strong> clarify promise rejection behavior in descriptions (<a href="https://github.com/angular/material/pull/11889">#11889</a>) (<a href="https://github.com/angular/material/commit/939f6c9f8ef16326b6cd15b0164afb69ae0c72fc">939f6c9</a>), closes (<a href="https://github.com/angular/material/issues/10130">#10130</a>)</li>
<li><strong>docs, README:</strong> remove Bower references, update GitHub and NPM icons. fix 'View Demo' button appearing for directives w/o demos (<a href="https://github.com/angular/material/pull/11888">#11888</a>) (<a href="https://github.com/angular/material/commit/5c75b121920243410c164df7ec33558087cccf1f">5c75b12</a>)</li>
<li><strong>getting-started, home:</strong> updates to landing page and getting started. add Blank StackBlitz Demo starter (<a href="https://github.com/angular/material/pull/11890">#11890</a>) (<a href="https://github.com/angular/material/commit/d1a9976cad047288262d904460e7be6089de8128">d1a9976</a>)</li>
<li><strong>COMMIT_LEVELS:</strong> update guide to better describe the process and responsibilities (<a href="https://github.com/angular/material/pull/11862">#11862</a>) (<a href="https://github.com/angular/material/commit/38fe9560e23467cabe18a8653849238946f2afa5">38fe956</a>)</li>
<li><strong>BUILD:</strong> rewrote most of the guide (<a href="https://github.com/angular/material/pull/11880">#11880</a>) (<a href="https://github.com/angular/material/commit/40939534460f175543a0261c3b232d71e2a2884b">4093953</a>)</li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the <code>v1.1.22</code> release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/marosoft"><img alt="marosoft" src="https://avatars0.githubusercontent.com/u/3945455?v=4&s=117" width="117"></a> | <a href="https://github.com/oliversalzburg"><img alt="oliversalzburg" src="https://avatars2.githubusercontent.com/u/1658949?v=4&s=117" width="117"></a> | <a href="https://github.com/andrewseguin"><img alt="andrewseguin" src="https://avatars3.githubusercontent.com/u/22898577?v=4&s=117" width="117"></a> | <a href="https://github.com/free-easy"><img alt="free-easy" src="https://avatars2.githubusercontent.com/u/20483759?v=4&s=117" width="117"></a> | <a href="https://github.com/nathanael-bice"><img alt="nathanael-bice" src="https://avatars2.githubusercontent.com/u/6155868?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                             <a href="https://github.com/marosoft">marosoft</a>                                              |                                             <a href="https://github.com/oliversalzburg">oliversalzburg</a>                                              |                                              <a href="https://github.com/andrewseguin">andrewseguin</a>                                              |                                              <a href="https://github.com/free-easy">free-easy</a>                                              |                                             <a href="https://github.com/nathanael-bice">nathanael-bice</a>                                              |</p>
<p>| <a href="https://github.com/psamim"><img alt="psamim" src="https://avatars3.githubusercontent.com/u/1868679?v=4&s=117" width="117"></a> | <a href="https://github.com/qubiack"><img alt="qubiack" src="https://avatars1.githubusercontent.com/u/19862364?v=4&s=117" width="117"></a> |
| :--------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/psamim">psamim</a>                                              |                                              <a href="https://github.com/qubiack">qubiack</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.21 Release]]></title>
            <link>https://devintent.com/blog/2020-05-03-announcing-the-angularjs-material-v1-1-21-release.md</link>
            <guid isPermaLink="false">blog/2020-05-03-announcing-the-angularjs-material-v1-1-21-release.md</guid>
            <pubDate>Sun, 03 May 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.21 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.21/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.21/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>Accessibility and touch improvements for <code>md-autocomplete</code></li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>autocomplete:</strong> improve handling of touch pads and touchscreens (<a href="https://github.com/angular/material/issues/11782">#11782</a>) (<a href="https://github.com/angular/material/commit/20c4d3f">20c4d3f</a>), closes <a href="https://github.com/angular/material/issues/11778">#11778</a></li>
<li><strong>autocomplete:</strong> improve implementation of <code>aria-activedescendant</code> (<a href="https://github.com/angular/material/issues/11743">#11743</a>) (<a href="https://github.com/angular/material/commit/8c159aa">8c159aa</a>), closes <a href="https://github.com/angular/material/issues/11742">#11742</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the <code>v1.1.21</code> release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/neilsh"><img alt="neilsh" src="https://avatars3.githubusercontent.com/u/49814?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                            <a href="https://github.com/neilsh">neilsh</a>                                             |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.20 Release]]></title>
            <link>https://devintent.com/blog/2019-09-27-announcing-the-angularjs-material-v1-1-20-release.md</link>
            <guid isPermaLink="false">blog/2019-09-27-announcing-the-angularjs-material-v1-1-20-release.md</guid>
            <pubDate>Fri, 27 Sep 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.20 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.20/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.20/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes.</p>
<ul>
<li>A number of fixes for iOS, Android, and IE11</li>
<li>Fixes for a number of accessibility issues</li>
<li>Improvements to internationalization through support for specifying <code>dir="rtl"</code> on any DOM
element</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>autocomplete:</strong> options panel flickers on hover after clicking input (<a href="https://github.com/angular/material/issues/11757">#11757</a>) (<a href="https://github.com/angular/material/commit/8f14afd">8f14afd</a>), closes <a href="https://github.com/angular/material/issues/11625">#11625</a></li>
<li><strong>autocomplete:</strong> support <code>ng-click</code> on <code>md-autocomplete</code> (<a href="https://github.com/angular/material/issues/11758">#11758</a>) (<a href="https://github.com/angular/material/commit/313e5e6">313e5e6</a>), closes <a href="https://github.com/angular/material/issues/11625">#11625</a></li>
<li><strong>autocomplete:</strong> tap outside options panel on iOS does not close panel (<a href="https://github.com/angular/material/issues/11625">#11625</a>) (<a href="https://github.com/angular/material/commit/f81349a">f81349a</a>), closes <a href="https://github.com/angular/material/issues/9581">#9581</a></li>
<li><strong>datepicker:</strong> remove invalid <code>aria-expanded</code> (<a href="https://github.com/angular/material/issues/11740">#11740</a>) (<a href="https://github.com/angular/material/commit/197d197">197d197</a>), closes <a href="https://github.com/angular/material/issues/11475">#11475</a></li>
<li><strong>gesture:</strong> check if <code>navigator</code> is defined before accessing <code>userAgent</code> (<a href="https://github.com/angular/material/issues/11755">#11755</a>) (<a href="https://github.com/angular/material/commit/0077d3e">0077d3e</a>), closes <a href="https://github.com/angular/material/issues/11751">#11751</a></li>
<li><strong>gesture:</strong> maximum call stack size exceeded exception on click when using TalkBack screen reader on Android (<a href="https://github.com/angular/material/issues/11774">#11774</a>) (<a href="https://github.com/angular/material/commit/4acef53">4acef53</a>), closes <a href="https://github.com/angular/material/issues/11768">#11768</a></li>
<li><strong>input:</strong> floating label text fails a11y contrast audit (<a href="https://github.com/angular/material/issues/11497">#11497</a>) (<a href="https://github.com/angular/material/commit/b5de054">b5de054</a>), closes <a href="https://github.com/angular/material/issues/11475">#11475</a></li>
<li><strong>panel:</strong> append panel animation transforms after existing transforms (<a href="https://github.com/angular/material/issues/11681">#11681</a>) (<a href="https://github.com/angular/material/commit/ffe9349">ffe9349</a>)</li>
<li><strong>rtl:</strong> support applying <code>dir="rtl"</code> on DOM elements other than the body (<a href="https://github.com/angular/material/issues/11579">#11579</a>) (<a href="https://github.com/angular/material/commit/bc7833b">bc7833b</a>), closes <a href="https://github.com/angular/material/issues/11016">#11016</a> <a href="https://github.com/angular/material/issues/9754">#9754</a></li>
<li><strong>select:</strong> improve focus/blur handling on iOS (<a href="https://github.com/angular/material/issues/11739">#11739</a>) (<a href="https://github.com/angular/material/commit/0284b13">0284b13</a>), closes <a href="https://github.com/angular/material/issues/11345">#11345</a></li>
<li><strong>tooltip:</strong> move <code>document.contains</code> polyfill for IE11 into <code>$mdUtil</code> (<a href="https://github.com/angular/material/issues/11749">#11749</a>) (<a href="https://github.com/angular/material/commit/f5535f8">f5535f8</a>), closes <a href="https://github.com/angular/material/issues/11745">#11745</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the <code>v1.1.20</code> release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/marosoft"><img alt="marosoft" src="https://avatars0.githubusercontent.com/u/3945455?v=4&s=117" width="117"></a> | <a href="https://github.com/Noglen"><img alt="Noglen" src="https://avatars0.githubusercontent.com/u/38341522?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                             <a href="https://github.com/marosoft">marosoft</a>                                              |                                              <a href="https://github.com/Noglen">Noglen</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[¡Es hora de la vista previa compatibilidad de Ivy!]]></title>
            <link>https://devintent.com/blog/2019-06-08-es-hora-de-la-vista-previa-compatibilidad-de-ivy.md</link>
            <guid isPermaLink="false">blog/2019-06-08-es-hora-de-la-vista-previa-compatibilidad-de-ivy.md</guid>
            <pubDate>Sat, 08 Jun 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Detalles sobre la vista previa opcional de Ivy en Angular v8.1.0-next.1.]]></description>
            <content:encoded><![CDATA[<blockquote>
  <p><a href="https://blog.angular.io/its-time-for-the-compatibility-opt-in-preview-of-ivy-38f3542a282f">Original in English</a> by <a href="https://blog.angular.io/@stephenfluin">Stephen Fluin</a></p>
</blockquote>
<p>Estamos buscando desarrolladores que deseen probar cosas nuevas (con algunas limitaciones) y que deseen
compartir tus experiencias con nosotros. Si estás interesado, siga los pasos a
continuación y háganos saber en qué problemas se encuentra.</p>
<p><a href="/angular/angularCompilerOptions-enableIvy.png"><img src="/angular/angularCompilerOptions-enableIvy.png" alt="angularCompilerOptions: { enableIvy: true }" /></a></p>
<p>Esta vista previa se destina principalmente a validar la compatibilidad con versiones
anteriores, ya que las mejoras de rendimiento y tamaño del paquete aún están en curso.</p>
<p>El plan es asegurarse de que la mayoría de las aplicaciones de Angular sigan
funcionando sin cambios significativos, y luego enfocarse en aprovechar las mejoras al
framework subyacente.</p>
<h1 id="estadoactual">Estado Actual</h1>
<p>Hemos logrado un importante hito de estabilidad con la compatibilidad con versiones
anteriores de Ivy. Basándonos en nuestras pruebas en miles de suites de prueba
dentro de Google (el 97% de las suites de prueba se pasan en Google), estamos
razonablemente seguros de que la mayoría de las aplicaciones funcionarán sin cambios
en todo el ecosistema. Tenemos varios problemas conocidos en los que estamos
trabajando, pero esperamos que haya una larga cola de problemas más pequeños que
solucionar.</p>
<p>Ahora que hemos alcanzado este hito, necesitamos tu ayuda para identificar e
informar estos problemas. Inscríbete en la vista previa, pruébelo y háganos saber
qué se rompe.</p>
<p>Hay tres cosas que vamos a hacer con los problemas que se nos informan:</p>
<ol>
<li><p><strong>Corríjalos —</strong> siempre que sea posible, queremos utilizar esta entrada para abordar los problemas de compatibilidad con versiones anteriores.</p></li>
<li><p><strong>Reconozcalas —</strong> algunos de los problemas informados serán de aplicaciones que se basan en comportamientos no especificados o que no forman parte de nuestra API pública. Es probable que no podamos revertir <a href="https://docs.google.com/document/d/1Dije0AsJ0PxL3NaeNPxpYDeapj30b_QC0xfeIvIIzgg/preview">estos cambios</a>, pero queremos entender y ayudar a los desarrolladores a identificar si se están ejecutando en alguno de estos.</p></li>
<li><p><strong>Automatizarlos —</strong> si hay problemas o patrones a gran escala que descubrimos en todo el ecosistema (como una dependencia o un código problemático escrito por un esquema popular), queremos crear esquemas y reglas de <a href="https://palantir.github.io/tslint/">TSLint</a> para automatizar las migraciones.</p></li>
</ol>
<h1 id="qupasaconelrendimientoyeltamaodelpaquete">¿Qué pasa con el rendimiento y el tamaño del paquete?</h1>
<p>Todavía estamos trabajando en mejoras para el tamaño del paquete y el rendimiento del
tiempo de ejecución. Cuando actualice hoy, todavía no verá todos estos beneficios.</p>
<p>Actualmente estamos viendo que el código generado y las aplicaciones “Hello World” son
más pequeñas, pero en algunos casos, Angular en sí es más grande. Estos son algunos de
los primeros resultados que hemos visto al actualizar las aplicaciones a Ivy:</p>
<p><a href="https://gist.github.com/StephenFluin/fffe2421fc6a8da3d245da84f0e6c20c"><strong>ng new my-app</strong></a> @ <code>8.1.0-next.1</code></p>
<p><strong>Antes de Ivy:</strong> Paquete principal (135 KiB)</p>
<p><strong>Con vista previa de Ivy:</strong> Paquete principal (122 KiB)</p>
<p><a href="https://github.com/gothinkster/angular-realworld-example-app"><strong>Real World Angular</strong></a> @ <code>8.1.0-next.1</code></p>
<p><strong>Antes de Ivy:</strong> Paquete principal (358 KiB)</p>
<ul>
<li>Lazy Chunks (7.7–34 KiB)</li>
</ul>
<p><strong>Con vista previa de Ivy:</strong> Paquete principal (400 KiB)</p>
<ul>
<li>Lazy Chunks (3.3–27 KiB)</li>
</ul>
<p>Ahora estamos trabajando para reducir el tamaño del framework, de modo que hemos
reducido el tamaño de los paquetes para aplicaciones reales en casi todos los casos
antes de que Ivy sea el valor predeterminado. También serán posibles beneficios
adicionales, ya que ofrecemos nuevas formas de arranque que van a reducir el tamaño
del framework en tu paquete principal.</p>
<p>Haremos más anuncios sobre el rendimiento y los hitos del tamaño del paquete para
las aplicaciones del mundo real en los próximos meses a medida que nos acerquemos a
activar a Ivy de forma predeterminada para todas las aplicaciones.</p>
<h1 id="qudeboesperarverhoy">¿Qué debo esperar ver hoy?</h1>
<p>Tu aplicación debe construir y funcionar como lo hace hoy. Notarás los siguientes
beneficios que se deben al nuevo compilador y conjunto de instrucciones:</p>
<ul>
<li><p>Mejoras menores en el tamaño del paquete: <code>ng new</code> es un 10% más pequeño y el código generado debería ver una reducción de ~25% en el tamaño</p></li>
<li><p>Mejor rendimiento de compilación: la compilación incremental, la reconstrucción en modo AOT es un 40% más rápida</p></li>
<li><p>Mejor rendimiento de las pruebas: en Angular, hemos visto que las pruebas de unidades de <a href="https://github.com/angular/angular">framework</a> son 1.5 veces más rápidas, las pruebas de unidades de <a href="https://github.com/angular/components">Angular Material</a> son 2.7 veces más rápidas y el uso de memoria en las pruebas de unidades de Angular Material se ha reducido en un 81%</p></li>
<li><p>Instrucciones más depurables — Agregue puntos de interrupción a HTML y pase a través de la representación de la plantilla, y depure más fácilmente la detección de cambios porque puede pasar a la función de plantilla en el traza de la pila y ver dónde se encuentra</p></li>
</ul>
<p>También hemos solucionado muchos errores de larga data, hemos mejorado el comportamiento confuso y hemos solucionado algunos problemas de rendimiento.</p>
<ul>
<li><p>Los enlaces de clase siempre anulan otras clases (<a href="https://github.com/angular/angular/issues/7289">7289</a>)</p></li>
<li><p><code>ContentChildren</code> consultas seleccionar nodo de host (<a href="https://github.com/angular/angular/issues/10098">10098</a>)</p></li>
<li><p>Las consultas tienen un tiempo de resolución inconsistente (<a href="https://github.com/angular/angular/issues/21800">21800</a>, <a href="https://github.com/angular/angular/issues/25961">25961</a>)</p></li>
<li><p>La bandera de los descendientes funciona inconsistentemente (<a href="https://github.com/angular/angular/issues/14769">14769</a>, <a href="https://github.com/angular/angular/issues/27504">27504</a>)</p></li>
<li><p>La detección de cambios aún se está ejecutando para los componentes separados que se proyectan (<a href="https://github.com/angular/angular/issues/21324">21324</a>)</p></li>
<li><p>El comportamiento de referencia de la plantilla local es inconsistente / confuso</p></li>
<li><p>Ya no es necesario agregar componentes a la lista de componentes de entrada (<a href="https://github.com/angular/angular/issues/28826">28826</a>)</p></li>
</ul>
<h1 id="cmomeinscribo">¿Cómo me inscribo?</h1>
<p>Hemos publicado una guía aquí: <a href="https://angular.io/guide/ivy">angular.io/guide/ivy</a></p>
<p>Siempre debe ejecutar la última versión de Angular desde npm (etiquetada a <code>next</code>) siempre que use Ivy.
Estaremos haciendo cambios frecuentes en los próximos meses. Puede usar <code>ng update</code>
para obtener la última versión de la siguiente manera:</p>
<pre><code class="bash language-bash">ng update —-next @angular/core
</code></pre>
<p>Una vez que estés en la última versión, actualiza tu <code>src/tsconfig.app.json</code> para
incluir <code>“enableIvy": true</code> bajo un nivel superior <code>angularCompilerOptions</code> llave.</p>
<p>Cuando ejecutas <code>ng build</code>, haremos la compilación de compatibilidad Angular (<code>ngcc</code>)
de tu carpeta <code>node_modules/</code> y actualizaremos todos tus archivos de metadatos en un
formato que podamos convertir en instrucciones Ivy.</p>
<h1 id="danostuopinin">Danos Tu Opinión</h1>
<p>Nos estamos acercando rápidamente a un futuro en el que los beneficios de Ivy son
automáticos y universales para todos los desarrolladores y el Proyecto Ivy llega a
una conclusión. Mientras tanto,
<a href="https://github.com/angular/angular/issues/new?template=1-bug-report.md">abra un problema</a>
o comuníquese con <a href="mailto:devrel@angular.io">devrel@angular.io</a> para darnos tu
opinión acerca de tus experiencias con la vista previa.</p>]]></content:encoded>
            <category>angular</category>
            <category>español</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.19 Release]]></title>
            <link>https://devintent.com/blog/2019-06-11-announcing-the-angularjs-material-v1-1-19-release.md</link>
            <guid isPermaLink="false">blog/2019-06-11-announcing-the-angularjs-material-v1-1-19-release.md</guid>
            <pubDate>Thu, 06 Jun 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.19 Release.]]></description>
            <content:encoded><![CDATA[<p>This release is now available in our <a href="https://material.angularjs.org/latest/">Online Documentation</a>,
<a href="https://www.npmjs.com/package/angular-material">NPM</a>, and Bower.
It is also available on the Google CDN
(<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.19/angular-material.min.js">JS</a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.19/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md">Change Log</a>.</p>
<h2 id="highlights">Highlights</h2>
<p>This is a patch release that includes bug fixes, enhancements, and documentation improvements.</p>
<ul>
<li>Fixed the 3 known regressions from the <code>1.1.18</code> release</li>
<li>Published a new guide for migrating your AngularJS Material app to Angular Material and the CDK</li>
<li>A number of cross browser bug fixes</li>
<li>The documentation can now be scrolled while reading it using the up/down/pageup/pagedown keys!</li>
</ul>
<h3 id="bugfixes">Bug Fixes</h3>
<ul>
<li><strong>datepicker:</strong> auto closes in Chrome when <code>md-open-on-focus</code> is used (<a href="https://github.com/angular/material/issues/11719">#11719</a>) (<a href="https://github.com/angular/material/commit/73c424d">73c424d</a>), closes <a href="https://github.com/angular/material/issues/11701">#11701</a></li>
<li><strong>gesture:</strong> tapping a submit button fires two submit events on mobile (<a href="https://github.com/angular/material/issues/11729">#11729</a>) (<a href="https://github.com/angular/material/commit/244619a">244619a</a>), closes <a href="https://github.com/angular/material/issues/10189">#10189</a> <a href="https://github.com/angular/material/issues/11725">#11725</a></li>
<li><strong>icon:</strong> symbol icons not working on browsers other than IE11 (<a href="https://github.com/angular/material/issues/11706">#11706</a>) (<a href="https://github.com/angular/material/commit/a62d160">a62d160</a>), closes <a href="https://github.com/angular/material/issues/11705">#11705</a></li>
<li><strong>select:</strong> edge case where the model value is unset w/ AngularJS 1.7.8 (<a href="https://github.com/angular/material/issues/11724">#11724</a>) (<a href="https://github.com/angular/material/commit/952a035">952a035</a>), closes <a href="https://github.com/angular/material/issues/11679">#11679</a></li>
<li><strong>tabs:</strong> new tab animation broken by code to support IE11 (<a href="https://github.com/angular/material/issues/11711">#11711</a>) (<a href="https://github.com/angular/material/commit/1063a92">1063a92</a>), closes <a href="https://github.com/angular/material/issues/11689">#11689</a></li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li><strong>menu-bar:</strong> support <code>md-prevent-menu-close</code> on checkbox/radio items (<a href="https://github.com/angular/material/issues/11710">#11710</a>) (<a href="https://github.com/angular/material/commit/d577afd">d577afd</a>), closes <a href="https://github.com/angular/material/issues/11707">#11707</a></li>
</ul>
<h3 id="documentation">Documentation</h3>
<ul>
<li><strong>migration:</strong> Add a guide for migration to Angular Material and the CDK (<a href="https://github.com/angular/material/pull/11706">#11706</a>) (<a href="https://github.com/angular/material/commit/16cea88">16cea88</a>)</li>
<li><strong>docs:</strong> Added support for Sass and TypeScript in code samples (<a href="https://github.com/angular/material/pull/11706">#11706</a>) (<a href="https://github.com/angular/material/commit/16cea88">16cea88</a>)</li>
<li><strong>docs:</strong> Allow up/down/page up/page down to scroll content (<a href="https://github.com/angular/material/pull/11712">#11712</a>) (<a href="https://github.com/angular/material/commit/67826f5">67826f5</a>), closes <a href="https://github.com/angular/material/issues/2961">#2961</a></li>
</ul>
<h3 id="contributors">Contributors</h3>
<p>Thank you to the contributors who helped with the <code>v1.1.19</code> release:</p>
<p>| <a href="https://github.com/Splaktar"><img alt="Splaktar" src="https://avatars1.githubusercontent.com/u/3506071?v=4&s=117" width="117"></a> | <a href="https://github.com/codymikol"><img alt="codymikol" src="https://avatars1.githubusercontent.com/u/13606342?v=4&s=117" width="117"></a> |
| :------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: |
|                                             <a href="https://github.com/Splaktar">Splaktar</a>                                              |                                              <a href="https://github.com/codymikol">codymikol</a>                                              |</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.18 Release]]></title>
            <link>https://devintent.com/blog/2019-05-09-announcing-the-angularjs-material-v1-1-18-release.md</link>
            <guid isPermaLink="false">blog/2019-05-09-announcing-the-angularjs-material-v1-1-18-release.md</guid>
            <pubDate>Thu, 09 May 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.18 Release.]]></description>
            <content:encoded><![CDATA[<p>We have released AngularJS Material <code>v1.1.18</code>.</p>
<p>This release is now available in our
<a href="https://material.angularjs.org/latest/"><strong>Online Documentation</strong></a>,
<a href="https://www.npmjs.com/package/angular-material"><strong>NPM</strong></a>, and Bower. It is also
available on the Google CDN (<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.18/angular-material.min.js"><strong>JS</strong></a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.18/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our
<a href="https://github.com/angular/material/blob/master/CHANGELOG.md"><strong>Change Log</strong></a>.</p>
<h1 id="highlights">Highlights</h1>
<p>This is a patch release that includes bug fixes, infrastructure, and documentation improvements.</p>
<ul>
<li>Fixed an a11y issue where <code>md-svg-icon</code> could cause pages to have multiple SVGs with duplicate <code>id</code> values.</li>
</ul>
<h4 id="knownissues">Known Issues</h4>
<ul>
<li><p>Symbol SVG icons are not displayed when using <code>md-svg-icon</code> in <code>1.1.11+</code>(<a href="https://github.com/angular/material/issues/11705">#11705</a>). This will be fixed in <code>1.1.19</code> via PR <a href="https://github.com/angular/material/pull/11706">#11706</a>.</p></li>
<li><p>Creating a new tab with pagination enabled does not animate correctly (<a href="https://github.com/angular/material/issues/11689">#11689</a>). This will be fixed in <code>1.1.19</code> via PR <a href="https://github.com/angular/material/pull/11711">#11711</a>.</p></li>
<li><p>AngularJS <code>1.7.8</code> causes an issue with <code>md-select</code> where using <code>required</code>will unset the value of the model. This is being tracked in <a href="https://github.com/angular/material/issues/11679">#11679</a> and is fixed in <code>1.1.19</code> via PR <a href="https://github.com/angular/material/pull/11724">#11724</a>.</p></li>
</ul>
<h1 id="bugfixes">Bug Fixes</h1>
<ul>
<li><strong>icon:</strong> stop breaking SVGs that have id references</li>
</ul>
<h1 id="infrastructure">Infrastructure</h1>
<ul>
<li><strong>release:</strong> workaround NPM bug that publishes <code>.git/</code> directory</li>
</ul>
<h1 id="documentation">Documentation</h1>
<ul>
<li><strong>docs:</strong> fix demos not loading in CodePen</li>
</ul>
<h1 id="contributors">Contributors</h1>
<p>Thank you to the contributors who helped with the <code>v1.1.18</code> release:</p>
<p><a href="/angularjs-material/1-1-18-contributors.png"><img src="/angularjs-material/1-1-18-contributors.png" alt="AngularJS Material 1.1.18 Contributors" /></a></p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.17 Release]]></title>
            <link>https://devintent.com/blog/2019-03-31-announcing-the-angularjs-material-v1-1-17-release.md</link>
            <guid isPermaLink="false">blog/2019-03-31-announcing-the-angularjs-material-v1-1-17-release.md</guid>
            <pubDate>Sun, 31 Mar 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.17 Release.]]></description>
            <content:encoded><![CDATA[<p>We have released AngularJS Material <code>v1.1.17</code>.</p>
<p>This release is now available in our
<a href="https://material.angularjs.org/latest/"><strong>Online Documentation</strong></a>,
<a href="https://www.npmjs.com/package/angular-material"><strong>NPM</strong></a>, and Bower. It will be
available early next week on the Google CDN (<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.17/angular-material.min.js"><strong>JS</strong></a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.17/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our
<a href="https://github.com/angular/material/blob/master/CHANGELOG.md"><strong>Change Log</strong></a>.</p>
<h1 id="highlights">Highlights</h1>
<p>This is a patch release that includes bug fixes and documentation improvements.</p>
<ul>
<li><p>In <code>1.1.13</code>, we fixed an issue where the <code>md-autocomplete</code> would sometimes position the options panel on <code>top</code> even when there was no room in the viewport. Unfortunately, this meant that the options panel often defaulted to <code>top</code> position. This was tracked in <a href="https://github.com/angular/material/issues/11656">#11656</a> and fixed in PR <a href="https://github.com/angular/material/pull/11670">#11670</a>.</p></li>
<li><p>The <code>1.1.14</code> release was deployed to NPM with a <code>.git</code> directory included in the published package due to a bug in <code>npm publish</code>. This caused NPM to refuse to uninstall or update the package. We’ve fixed this in <code>1.1.17</code> and we’re using <a href="https://github.com/angular/material/issues/11684">#11684</a> to implement a long term fix.</p></li>
<li><p>In addition to fixing the two regressions above, this release fixes an a11y regression with <code>md-slider</code> and tab scrolling with wheel devices in Firefox.</p></li>
</ul>
<h4 id="knownissues">Known Issues</h4>
<ul>
<li>AngularJS <code>1.7.8</code> causes an issue with <code>md-select</code> where using <code>required</code>will unset the value of the model. This is being tracked in <a href="https://github.com/angular/material/issues/11679">#11679</a>.</li>
</ul>
<h1 id="bugfixes">Bug Fixes</h1>
<ul>
<li><p><strong>autocomplete</strong>: default dropdown position to the bottom again.</p></li>
<li><p><strong>slider</strong>: aria attributes are not announced when tabbing in JAWS or VoiceOver. A previous fix for ChromeVox broke this for JAWS and VoiceOver. This new fix has been verified in all 3 of these screen readers.</p></li>
<li><p><strong>tabs</strong>: use the standard <code>wheel</code> event instead of the non-standard<code>mousewheel</code> event to fix tab scrolling in Firefox.</p></li>
<li><p><strong>npm</strong>: deploy new release early to fix issue of <code>1.1.14</code> including a <code>.git/</code> dir for NPM installs.</p></li>
</ul>
<h1 id="documentation">Documentation</h1>
<ul>
<li><strong>docs</strong>: scroll position improvements for navigation. Using the back button should bring you back to the same scroll position instead of somewhere else. Opening a new page in the docs should take you to the top of the page instead of somewhere in the middle.</li>
</ul>
<h1 id="contributors">Contributors</h1>
<p>Thank you to the contributors who helped with the <code>v1.1.17</code> release:</p>
<p><a href="/angularjs-material/1-1-17-contributors.png"><img src="/angularjs-material/1-1-17-contributors.png" alt="AngularJS Material 1.1.17 Contributors" /></a></p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.14 Release]]></title>
            <link>https://devintent.com/blog/2019-03-18-announcing-the-angularjs-material-v1-1-14-release.md</link>
            <guid isPermaLink="false">blog/2019-03-18-announcing-the-angularjs-material-v1-1-14-release.md</guid>
            <pubDate>Mon, 18 Mar 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.14 Release.]]></description>
            <content:encoded><![CDATA[<p>We have released AngularJS Material <code>v1.1.14</code>.</p>
<p>This release is now available in our
<a href="https://material.angularjs.org/latest/"><strong>Online Documentation</strong></a>,
<a href="https://www.npmjs.com/package/angular-material"><strong>NPM</strong></a>, and Bower. It is also
available on the Google CDN (<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.14/angular-material.min.js"><strong>JS</strong></a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.14/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our
<a href="https://github.com/angular/material/blob/master/CHANGELOG.md"><strong>Change Log</strong></a>.</p>
<h1 id="highlights">Highlights</h1>
<p>This is a patch release that includes bug fixes and documentation improvements.</p>
<ul>
<li><p>1 memory leak, 2 regressions, and 5 other bugs fixed</p></li>
<li><p>Fixed an accessibility issue with <code>md-nav-bar</code></p></li>
<li><p>Fixed linking to specific sections of the documentation site and specific demos</p></li>
<li><p>Build output (JS and CSS files) will be easier to compare from <code>1.1.14</code> onward</p></li>
</ul>
<h4 id="knownissues">Known Issues</h4>
<ul>
<li><p>Somehow this release was deployed to NPM with a <code>.git</code> directory included in the published package. This can cause NPM to refuse to uninstall or update the package. We’re investigating and tracking this in <a href="https://github.com/angular/material/issues/11684">#11684</a>.</p></li>
<li><p>AngularJS <code>1.7.8</code> causes an issue with <code>md-select</code> where using <code>required</code> will unset the value of the model. This is being tracked in <a href="https://github.com/angular/material/issues/11679">#11679</a>.</p></li>
<li><p>In <code>1.1.13</code>, we fixed an issue where the <code>md-autocomplete</code> would sometimes position the options panel on <code>top</code> even when there was no room in the viewport. Unfortunately, this meant that the options panel often defaulted to <code>top</code> position. We’re tracking this in <a href="https://github.com/angular/material/issues/11656">#11656</a> and have merged a fix in PR <a href="https://github.com/angular/material/pull/11670">#11670</a>. This will be fixed in <code>1.1.15</code>. In the meantime, you can use <code>md-dropdown-position="bottom"</code> as a workaround.</p></li>
</ul>
<h1 id="bugfixes">Bug Fixes</h1>
<ul>
<li><p><strong>\$mdInteraction</strong>: clean up events on <code>$rootScope</code> destroy. This fixes a memory leak when <code>$mdDialog</code> needed to be injected multiple times. This occurred most often in testing, but also effected certain apps that were creating/tearing down the app repeatedly.</p></li>
<li><p><strong>icon</strong>: large SVG files can cause icon caching to hang. This fixes a regression where sites that use many, rich SVG icons could hang. This is part of an ongoing effort to provide more robust support for SVG icons.</p></li>
<li><p><strong>input</strong>: <code>placeholder</code> hidden when there is also a label on IE11. This fixes a regression caused by a previous fix for placeholders in <code>md-datepicker</code> on IE and Firefox.</p></li>
<li><p><strong>interimElement</strong>: don’t track elements that fail compilation. This fixes an issue with <code>$mdDialog</code>, and other <code>interimElement</code>s, where an exception during to runtime compilation of the element could cause dialogs to stop responding. This occurred most commonly in apps that used nested or multiple dialogs.</p></li>
<li><p><strong>nav-bar</strong>: non-selected tabs with anchors have invalid <code>tabindex</code> value. This fixes an accessibility issue where it is not possible to tab out of certain tabs using the keyboard.</p></li>
<li><p><strong>panel</strong>: caching of panels by id is not working. This fixes an issue where our <code>trackedPanels</code> caching was working for <code>md-tooltip</code>, but not for <code>md-panel</code>.</p></li>
<li><p><strong>progress-circular</strong>: show correct circle arc when changing from <code>indeterminate</code> to <code>determinate</code> mode. This fixes an issue where changing the <code>md-mode</code> at runtime could cause the arc to be off by about 90 degrees.</p></li>
<li><p><strong>virtual-repeat-container</strong>: support horizontal scrollbar in vertical orientation. This fixes an issue where a horizontal scrollbar in a vertical list could cover up some of the final items in the list.</p></li>
</ul>
<h1 id="documentation">Documentation</h1>
<ul>
<li><p><strong>docs</strong>: properly format anchor names and hrefs. You should now be able to link to a specific demo (I.e. the new <a href="https://material.angularjs.org/latest/demo/autocomplete#repeat-mode">Autocomplete Repeat Mode Demo</a>) or documentation section (I.e. <a href="https://material.angularjs.org/latest/#browser-support">AngularJS Material Browser Support</a>). Previously these anchors just took you to the top of the page (prior to <code>1.1.13</code>) or gave you a <code>404</code> (in <code>1.1.13</code>).</p></li>
<li><p><strong>radio-button</strong>: correct two misspellings of Latin names in the demo</p></li>
<li><p><strong>colors</strong>: clean up Closure / JSDoc comments and types</p></li>
</ul>
<h1 id="infrastructure">Infrastructure</h1>
<ul>
<li><p><strong>build</strong>: make the build output deterministic and reproducible. Previously the ordering of content within our JS and CSS files changed each build. With this change, comparing the build output between releases will be a lot easier.</p></li>
<li><p><strong>ci</strong>: we moved over to CircleCI from TravisCI in the previous <code>1.1.13</code> release</p></li>
</ul>
<h1 id="contributors">Contributors</h1>
<p>Thank you to the contributors who helped with the <code>v1.1.14</code> release:</p>
<p><a href="/angularjs-material/1-1-14-contributors.png"><img src="/angularjs-material/1-1-14-contributors.png" alt="AngularJS Material 1.1.14 Contributors" /></a></p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.13 Release]]></title>
            <link>https://devintent.com/blog/2019-02-28-announcing-the-angularjs-material-v1-1-13-release.md</link>
            <guid isPermaLink="false">blog/2019-02-28-announcing-the-angularjs-material-v1-1-13-release.md</guid>
            <pubDate>Thu, 28 Feb 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.13 Release.]]></description>
            <content:encoded><![CDATA[<p>We have released AngularJS Material <code>v1.1.13</code>.</p>
<p>This release is now available in our
<a href="https://material.angularjs.org/latest/"><strong>Online Documentation</strong></a>,
<a href="https://www.npmjs.com/package/angular-material"><strong>NPM</strong></a>, and Bower.
It is also available on the Google CDN (<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.13/angular-material.min.js"><strong>JS</strong></a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.13/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md"><strong>Change Log</strong></a>.</p>
<h1 id="highlights">Highlights</h1>
<p>This is a patch release that includes a couple enhancements in addition to bug fixes and documentation improvements.</p>
<ul>
<li><p><code>md-autocomplete</code> now supports variable-height autocomplete list items when using <code>md-mode="standard"</code>. Find out more in the <a href="https://material.angularjs.org/HEAD/api/directive/mdAutocomplete#specifying-repeat-mode">updated docs</a> and the new <a href="https://material.angularjs.org/HEAD/demo/autocomplete#repeat-mode">Repeat Mode demo</a>.</p></li>
<li><p>The <code>md-date-filter</code> API will now disable months when looking at the month picker in the <code>md-datepicker</code> and <code>md-calendar</code>. Note that only the first day of the month is checked.</p></li>
<li><p>A number of issues specific to IE11 and Firefox were resolved.</p></li>
<li><p><code>md-radio-button</code> styles were updated to better align with the Material Design 2017 spec. This changes the style of focused, unchecked and checked, disabled radio buttons.</p></li>
</ul>
<h4 id="knownissues">Known Issues</h4>
<ul>
<li><p>The fix for copying links to example/demo anchor headers didn’t quite work as expected in production. It’s been fixed in <code>master</code> via <a href="https://github.com/angular/material/commit/163b7627f27229a31c53c28a0399c9ed1366ff70">163b762</a>.</p></li>
<li><p>Large SVGs used with <code>md-icon</code> can cause applications to hang since <code>v1.1.11</code>. This is being tracked in <a href="https://github.com/angular/material/issues/11651">#11651</a> and is being worked on in PR <a href="https://github.com/angular/material/pull/11653">#11653</a>.</p></li>
<li><p>We fixed an issue where the <code>md-autocomplete</code> would sometimes position the dropdown on <code>top</code> even when there was no room in the viewport. The improved calculation means that there are more opportunities for the dropdown to show in the default <code>top</code> position where it would have used the <code>bottom</code> position previously. We’re considering changing this to make <code>bottom</code> the first choice again. Please leave us feedback on this in <a href="https://github.com/angular/material/issues/11656">#11656</a>. In the meantime, you can use <code>md-dropdown-position="bottom"</code> as a workaround.</p></li>
</ul>
<h1 id="bugfixes">Bug Fixes</h1>
<ul>
<li><p><strong>autocomplete</strong>: show dropdown on top only when there is room (<a href="https://github.com/angular/material/issues/11629">#11629</a>) (<a href="https://github.com/angular/material/commit/38fb991">38fb991</a>), closes <a href="https://github.com/angular/material/issues/10859">#10859</a></p></li>
<li><p><strong>autocomplete</strong>: suggestions can be highlighted incorrectly (<a href="https://github.com/angular/material/issues/11529">#11529</a>) (<a href="https://github.com/angular/material/commit/320511c">320511c</a>), closes <a href="https://github.com/angular/material/issues/10573">#10573</a></p></li>
<li><p><strong>autocomplete</strong>: two chips added on enter w/ IE11 (<a href="https://github.com/angular/material/issues/11528">#11528</a>) (<a href="https://github.com/angular/material/commit/705c54e">705c54e</a>), closes <a href="https://github.com/angular/material/issues/10640">#10640</a> <a href="https://github.com/angular/material/issues/10667">#10667</a></p></li>
<li><p><strong>checkbox</strong>: submit on enter rather than toggle (<a href="https://github.com/angular/material/issues/11584">#11584</a>) (<a href="https://github.com/angular/material/commit/a191a8e">a191a8e</a>) (<a href="https://github.com/angular/material/pull/11640">#11640</a>) (<a href="https://github.com/angular/material/commit/251cfed8">251cfed8</a>), closes <a href="https://github.com/angular/material/issues/11583">#11583</a> <a href="https://github.com/angular/material/issues/11639">#11639</a></p></li>
<li><p><strong>datepicker</strong>: does not open on focus in Firefox (<a href="https://github.com/angular/material/issues/11521">#11521</a>) (<a href="https://github.com/angular/material/commit/251cfed82837270c29e1099b34f5e85874a7bcad">45e92ea</a>), closes <a href="https://github.com/angular/material/issues/10619">#10619</a></p></li>
<li><p><strong>datepicker</strong>: validation error when adding text after date (<a href="https://github.com/angular/material/issues/11110">#11110</a>) (<a href="https://github.com/angular/material/commit/57c81c8">57c81c8</a>), closes <a href="https://github.com/angular/material/issues/9994">#9994</a> <a href="https://github.com/angular/material/issues/10520">#10520</a> <a href="https://github.com/angular/material/issues/10015">#10015</a></p></li>
<li><p><strong>icon</strong>: SVG elements are not loaded from the cache properly on IE11 (<a href="https://github.com/angular/material/issues/11635">#11635</a>) (<a href="https://github.com/angular/material/commit/7cde443">7cde443</a>), closes <a href="https://github.com/angular/material/issues/11603">#11603</a> <a href="https://github.com/angular/material/issues/11545">#11545</a><a href="https://github.com/angular/material/issues/11604">#11604</a></p></li>
<li><p><strong>layout</strong>: remove some duplicate layout &gt; flex styles (<a href="https://github.com/angular/material/issues/11613">#11613</a>) (<a href="https://github.com/angular/material/commit/6515e6c">6515e6c</a>), closes <a href="https://github.com/angular/material/issues/11609">#11609</a></p></li>
<li><p><strong>list</strong>: case where user is unable to interact w/ secondary actions (<a href="https://github.com/angular/material/issues/11539">#11539</a>) (<a href="https://github.com/angular/material/commit/708fff9">708fff9</a>), closes <a href="https://github.com/angular/material/issues/9676">#9676</a></p></li>
<li><p><strong>menu</strong>: fix min-height when scrollable (<a href="https://github.com/angular/material/pull/11602">#11602</a>)</p></li>
<li><p><strong>nav-bar</strong>: improve focus behavior for click events (<a href="https://github.com/angular/material/issues/11600">#11600</a>) (<a href="https://github.com/angular/material/commit/e64875d">e64875d</a>), closes <a href="https://github.com/angular/material/issues/11591">#11591</a> <a href="https://github.com/angular/material/issues/11494">#11494</a> <a href="https://github.com/angular/material/issues/11598">#11598</a></p></li>
<li><p><strong>radio-group</strong>: style focused but unchecked radio buttons (<a href="https://github.com/angular/material/issues/11564">#11564</a>) (<a href="https://github.com/angular/material/commit/8a4105c">8a4105c</a>), closes <a href="https://github.com/angular/material/issues/11563">#11563</a> <a href="https://github.com/angular/material/issues/8339">#8339</a> <a href="https://github.com/angular/material/issues/3643">#3643</a></p></li>
<li><p><strong>select</strong>: carrot not aligned to end in IE11 (<a href="https://github.com/angular/material/issues/11544">#11544</a>) (<a href="https://github.com/angular/material/commit/bf5bbfc">bf5bbfc</a>), closes <a href="https://github.com/angular/material/issues/10714">#10714</a> <a href="https://github.com/angular/material/issues/3840">#3840</a> <a href="https://github.com/angular/material/issues/3840">#3840</a></p></li>
<li><p><strong>tabs</strong>: exception when no selection and header clicked (<a href="https://github.com/angular/material/issues/11520">#11520</a>) (<a href="https://github.com/angular/material/commit/9c079aa">9c079aa</a>), closes <a href="https://github.com/angular/material/issues/10042">#10042</a></p></li>
</ul>
<h1 id="features">Features</h1>
<ul>
<li><p><strong>autocomplete</strong>: support variable-height autocomplete list items (<a href="https://github.com/angular/material/pull/11516">#11516</a>) (<a href="https://github.com/angular/material/commit/562e0c7">562e0c7</a>)</p></li>
<li><p><strong>datepicker, calendar</strong>: <code>md-date-filter</code> disables months in month mode (<a href="https://github.com/angular/material/issues/11526">#11526</a>) (<a href="https://github.com/angular/material/commit/8aa5d58">8aa5d58</a>), closes <a href="https://github.com/angular/material/issues/11525">#11525</a></p></li>
</ul>
<h1 id="documentation">Documentation</h1>
<ul>
<li><p><strong>checkbox</strong>: clarify description of <code>md-no-ink</code> (<a href="https://github.com/angular/material/pull/11605">#11605</a>)</p></li>
<li><p><strong>docs</strong>: copying links to example/demo anchor headers gives a bad URL (<a href="https://github.com/angular/material/pull/11634">#11634</a>), closes <a href="https://github.com/angular/material/issues/11285">#11285</a></p></li>
<li><p><strong>menu</strong>: add demo and docs for dense menus. (<a href="https://github.com/angular/material/pull/11602">#11602</a>)</p></li>
<li><p><strong>ripple</strong>: break out docs for <code>$mdInkRippleProvider</code> from <code>$mdInkRipple</code> (<a href="https://github.com/angular/material/pull/11606">#11606</a>)</p></li>
</ul>
<h1 id="contributors">Contributors</h1>
<p>Thank you to the contributors who helped with the <code>v1.1.13</code> release:</p>
<p><a href="/angularjs-material/1-1-13-contributors.png"><img src="/angularjs-material/1-1-13-contributors.png" alt="AngularJS Material 1.1.13 Contributors" /></a></p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.12 Release]]></title>
            <link>https://devintent.com/blog/2019-01-04-announcing-the-angularjs-material-v1-1-12-release.md</link>
            <guid isPermaLink="false">blog/2019-01-04-announcing-the-angularjs-material-v1-1-12-release.md</guid>
            <pubDate>Fri, 04 Jan 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.12 Release.]]></description>
            <content:encoded><![CDATA[<p>We have released AngularJS Material <code>v1.1.12</code>.</p>
<p>This release is now available in our
<a href="https://material.angularjs.org/latest/"><strong>Online Documentation</strong></a>,
<a href="https://www.npmjs.com/package/angular-material"><strong>NPM</strong></a>, and Bower. It is also
available on the Google CDN (<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.12/angular-material.min.js"><strong>JS</strong></a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.12/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our <a href="https://github.com/angular/material/blob/master/CHANGELOG.md"><strong>Change Log</strong></a>.</p>
<h1 id="highlights">Highlights</h1>
<p>This is a patch release that fixes two regressions found in the <a href="https://blog.devintent.com/announcing-the-angularjs-material-v1-1-11-release-fbdcb67930cc">previous <code>v1.1.11</code> release</a>.</p>
<h1 id="bugfixes">Bug Fixes</h1>
<ul>
<li><p>select: multiple with initial value causes label to overlap with value (<a href="https://github.com/angular/material/issues/11572">#11572</a>) (<a href="https://github.com/angular/material/commit/a4507d6">a4507d6</a>), closes <a href="https://github.com/angular/material/issues/11571">#11571</a> <a href="https://github.com/angular/material/issues/11571">#11571</a></p></li>
<li><p>tabs: md-center-tabs causes tabs to not render (<a href="https://github.com/angular/material/issues/11567">#11567</a>) (<a href="https://github.com/angular/material/commit/a49043d">a49043d</a>), closes <a href="https://github.com/angular/material/issues/11566">#11566</a> <a href="https://github.com/angular/material/issues/11432">#11432</a></p></li>
</ul>
<h1 id="contributors">Contributors</h1>
<p>Thank you to the contributors who helped with the <code>v1.1.12</code> release over the holiday break:</p>
<p><a href="/angularjs-material/1-1-12-contributors.png"><img src="/angularjs-material/1-1-12-contributors.png" alt="AngularJS Material 1.1.12 Contributors" /></a></p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.11 Release]]></title>
            <link>https://devintent.com/blog/2018-12-31-announcing-the-angularjs-material-v1-1-11-release.md</link>
            <guid isPermaLink="false">blog/2018-12-31-announcing-the-angularjs-material-v1-1-11-release.md</guid>
            <pubDate>Mon, 31 Dec 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.11 Release.]]></description>
            <content:encoded><![CDATA[<p>We have released AngularJS Material <code>v1.1.11</code>.</p>
<p>This release is now available in our
<a href="https://material.angularjs.org/latest/"><strong>Online Documentation</strong></a>,
<a href="https://www.npmjs.com/package/angular-material"><strong>NPM</strong></a>, and Bower. It is also
available on the Google CDN (<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.11/angular-material.min.js"><strong>JS</strong></a>,
<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.11/angular-material.min.css">CSS</a>).</p>
<p>You can find the details for all releases in our
<a href="https://github.com/angular/material/blob/master/CHANGELOG.md"><strong>Change Log</strong></a>.</p>
<h1 id="highlights">Highlights</h1>
<p><code>v1.1.11</code> is our largest release of 2018. This release focused on fixing a lot of high priority issues related to accessibility, performance, and cross browser compatibility.</p>
<p>Here are the highlights:</p>
<ul>
<li><p>Our primary focus this release was on high priority <a href="https://github.com/angular/material/issues?q=is%3Aissue+milestone%3A1.1.11+is%3Aclosed+label%3A%22severity%3A+regression%22">regressions</a> and <a href="https://github.com/angular/material/issues?q=is%3Aissue+milestone%3A1.1.11+is%3Aclosed+label%3Aa11y">accessibility issues</a>. We’ll continue with this same focus in <code>v1.1.12</code>.</p></li>
<li><p>With the <a href="https://www.youtube.com/playlist?list=PLJ21zHI2TNh-rX-Xr_xi9KIEcbdee_1Ah">announcement of major changes</a> to <a href="https://material.io/design">Material Design</a> in the <a href="https://design.google/library/io-2018-our-definitive-guide-design/">2018 update to the specification</a>, we’ve clarified that AngularJS Material will continue to focus on aligning with the <a href="https://material.io/archive/guidelines/">Material Design Spec for 2014–2017</a>. The <a href="https://github.com/angular/material2">Angular Material</a> project will be the place to find the latest Material Design 2018+ features.</p></li>
<li><p>We fixed <a href="https://github.com/angular/material/issues?q=is%3Aissue+milestone%3A1.1.11+is%3Aclosed+label%3A%22P1%3A+urgent%22">21 P1</a>, <a href="https://github.com/angular/material/issues?q=is%3Aissue+milestone%3A1.1.11+is%3Aclosed+label%3A%22P2%3A+required%22">21 P2</a>, and <a href="https://github.com/angular/material/issues?q=is%3Aissue+milestone%3A1.1.11+is%3Aclosed+label%3A%22P3%3A+important%22">14 P3</a> issues.</p></li>
<li><p>We reduced the minified CSS bundle size by 76KB as compared to <code>v1.1.10</code>. Also note that this is 93KB smaller than the minified CSS bundle from <code>v1.1.9</code>.</p></li>
<li><p>IE11 support was significantly improved with <a href="https://github.com/angular/material/issues?q=is%3Aissue+milestone%3A1.1.11+is%3Aclosed+label%3A%22browser%3A+IE%22">7 bug fixes</a>. There were also fixes for issues specific to Firefox and Edge.</p></li>
</ul>
<h4 id="advisories">Advisories</h4>
<p>Tabs received a number of accessibility, cross browser support, and performance fixes. As part of this, there was <a href="https://github.com/angular/material/issues/11566">a regression</a> to <code>md-center-tabs</code> which can cause the tabs to not appear or to appear shifted to the right. This is <a href="https://github.com/angular/material/pull/11567">being addressed</a> and will be fixed in <code>v1.1.12</code>.</p>
<p>Also related to the above change to Tabs, if you use Tabs inside of a non-AngularJS Material dialog, you may see issues with the width of the tab content. You can resolve this by overriding the width of the <code>md-pagination-wrapper</code>. In <code>v1.1.12</code>, you will only need this override if using Tabs with pagination in a non-AngularJS Material dialog.</p>
<p>There also appears to be <a href="https://github.com/angular/material/issues/11571">a regression</a> to <code>md-select</code> when it is used with the <code>multiple</code> option and assigned an initial value. This can cause the label to not float, leaving it overlapping with the values. A <a href="https://github.com/angular/material/pull/11572">fix is being worked on</a> and will be included in <code>v1.1.12</code>.</p>
<p>We hope to have a <code>v1.1.12</code> release out in mid-January.</p>
<h1 id="bugfixes">Bug Fixes</h1>
<ul>
<li><p><strong>autocomplete</strong>: screen readers now announce when an item is selected from the dropdown (<a href="https://github.com/angular/material/issues/11403">#11403</a>) (<a href="https://github.com/angular/material/commit/e56424e">e56424e</a>), closes <a href="https://github.com/angular/material/issues/10837">#10837</a></p></li>
<li><p><strong>autocomplete</strong>: apply theme to <code>mdProgressLinear</code> and input (<a href="https://github.com/angular/material/issues/9698">#9698</a>) (<a href="https://github.com/angular/material/commit/affe84b">affe84b</a>)</p></li>
<li><p><strong>autocomplete</strong>: ChromeVox indicates selected option on focus (<a href="https://github.com/angular/material/issues/11441">#11441</a>) (<a href="https://github.com/angular/material/commit/ca10bd0">ca10bd0</a>), closes <a href="https://github.com/angular/material/issues/10838">#10838</a> <a href="https://github.com/angular/material/issues/10970">#10970</a></p></li>
<li><p><strong>autocomplete</strong>: updateSize incorrectly sets the size to zero (<a href="https://github.com/angular/material/issues/11500">#11500</a>) (<a href="https://github.com/angular/material/commit/d343363">d343363</a>), closes <a href="https://github.com/angular/material/issues/10834">#10834</a></p></li>
<li><p><strong>bottom-sheet</strong>: theme now supports dark mode (<a href="https://github.com/angular/material/issues/11380">#11380</a>) (<a href="https://github.com/angular/material/commit/4cecebb">4cecebb</a>)</p></li>
<li><p><strong>chips</strong>: editing chips works again (<a href="https://github.com/angular/material/issues/11364">#11364</a>) (<a href="https://github.com/angular/material/commit/97455f5">97455f5</a>), closes <a href="https://github.com/angular/material/issues/11322">#11322</a> <a href="https://github.com/angular/material/issues/11323">#11323</a></p></li>
<li><p><strong>chips</strong>: improve screen reader support (<a href="https://github.com/angular/material/issues/11422">#11422</a>) (<a href="https://github.com/angular/material/commit/2268c24">2268c24</a>), closes <a href="https://github.com/angular/material/issues/2618">#2618</a></p></li>
<li><p><strong>chips</strong>: set dirty when a chip is removed (<a href="https://github.com/angular/material/issues/11363">#11363</a>) (<a href="https://github.com/angular/material/commit/0dd688c">0dd688c</a>), closes <a href="https://github.com/angular/material/issues/11356">#11356</a></p></li>
<li><p><strong>datepicker</strong>: <code>md-open-on-focus</code> constantly re-opens on close w/ IE11 (<a href="https://github.com/angular/material/issues/11440">#11440</a>) (<a href="https://github.com/angular/material/commit/6596cc7">6596cc7</a>), closes <a href="https://github.com/angular/material/issues/10999">#10999</a></p></li>
<li><p><strong>icon</strong>: stop breaking SVG id references when caching icon ids (<a href="https://github.com/angular/material/issues/11342">#11342</a>) (<a href="https://github.com/angular/material/commit/841e8b2">841e8b2</a>), closes <a href="https://github.com/angular/material/issues/8689">#8689</a></p></li>
<li><p><strong>icon</strong>: regression causing exceptions to be thrown on IE11 (<a href="https://github.com/angular/material/issues/11545">#11545</a>) (<a href="https://github.com/angular/material/commit/47527f2">47527f2</a>), closes <a href="https://github.com/angular/material/issues/11543">#11543</a> <a href="https://github.com/angular/material/issues/11342">#11342</a> <a href="https://github.com/angular/material/issues/11162">#11162</a></p></li>
<li><p><strong>input</strong>: make <code>md-maxlength</code> validation happen on initialization with interpolated value (<a href="https://github.com/angular/material/issues/11338">#11338</a>) (<a href="https://github.com/angular/material/commit/0cb4af1">0cb4af1</a>), closes <a href="https://github.com/angular/material/issues/11329">#11329</a> <a href="https://github.com/angular/material/issues/11329">#11329</a></p></li>
<li><p><strong>input</strong>: placeholder and datepicker value displayed overlapping on Firefox (<a href="https://github.com/angular/material/issues/11538">#11538</a>) (<a href="https://github.com/angular/material/commit/44a6946">44a6946</a>), closes <a href="https://github.com/angular/material/issues/10440">#10440</a></p></li>
<li><p><strong>input</strong>: remove placeholder from button accessibility tree (<a href="https://github.com/angular/material/issues/11404">#11404</a>) (<a href="https://github.com/angular/material/commit/2203eec">2203eec</a>), closes <a href="https://github.com/angular/material/issues/11293">#11293</a></p></li>
<li><p><strong>input</strong>: remove unnecessary warnings when <code>ng-messages</code> not provided (<a href="https://github.com/angular/material/issues/11352">#11352</a>) (<a href="https://github.com/angular/material/commit/d48c5b8">d48c5b8</a>), closes <a href="https://github.com/angular/material/issues/10461">#10461</a></p></li>
<li><p><strong>input-container</strong>: handle initialization of <code>md-icon</code> with <code>ng-if</code> (<a href="https://github.com/angular/material/issues/11437">#11437</a>) (<a href="https://github.com/angular/material/commit/4493389">4493389</a>), closes <a href="https://github.com/angular/material/issues/9529">#9529</a></p></li>
<li><p><strong>interim</strong>: validate the interim element while closing it (<a href="https://github.com/angular/material/issues/11509">#11509</a>) (<a href="https://github.com/angular/material/commit/6815faf">6815faf</a>), closes <a href="https://github.com/angular/material/issues/11507">#11507</a> <a href="https://github.com/angular/material/issues/10715">#10715</a></p></li>
<li><p><strong>list</strong>: account for IE11 bug with Flexbox and <code>min-height</code> (<a href="https://github.com/angular/material/issues/11393">#11393</a>) (<a href="https://github.com/angular/material/commit/e3c1a5c">e3c1a5c</a>)</p></li>
<li><p><strong>nav-bar</strong>: improve screen reader support (<a href="https://github.com/angular/material/issues/11486">#11486</a>) (<a href="https://github.com/angular/material/commit/6b29548">6b29548</a>), closes <a href="https://github.com/angular/material/issues/11485">#11485</a> <a href="https://github.com/angular/material/issues/11485">#11485</a></p></li>
<li><p><strong>nav-bar</strong>: set <code>ng-href</code> on nav-item even if <code>md-nav-href</code> is empty (<a href="https://github.com/angular/material/issues/11488">#11488</a>) (<a href="https://github.com/angular/material/commit/e876eec">e876eec</a>), closes <a href="https://github.com/angular/material/issues/11487">#11487</a></p></li>
<li><p><strong>nav-bar:</strong> update keyboard navigation to WAI-ARIA guidelines (<a href="https://github.com/angular/material/issues/11494">#11494</a>) (<a href="https://github.com/angular/material/commit/4d29450">4d29450</a>), closes <a href="https://github.com/angular/material/issues/10419">#10419</a> <a href="https://github.com/angular/material/issues/11489">#11489</a></p></li>
<li><p><strong>select</strong>: display asterisk on label only if empty (<a href="https://github.com/angular/material/issues/11355">#11355</a>) (<a href="https://github.com/angular/material/commit/f7b7f10">f7b7f10</a>), closes <a href="https://github.com/angular/material/issues/11312">#11312</a></p></li>
<li><p><strong>select</strong>: give focus to the first option when loaded asynchronously (<a href="https://github.com/angular/material/issues/11372">#11372</a>) (<a href="https://github.com/angular/material/commit/998199f">998199f</a>), closes <a href="https://github.com/angular/material/issues/11357">#11357</a></p></li>
<li><p><strong>select</strong>: perform full cleanup of the select drop-down after the close (<a href="https://github.com/angular/material/issues/11448">#11448</a>) (<a href="https://github.com/angular/material/commit/dfba062">dfba062</a>), closes <a href="https://github.com/angular/material/issues/11447">#11447</a></p></li>
<li><p><strong>select</strong>: theming issues with <code>md-select-value</code> (<a href="https://github.com/angular/material/issues/11373">#11373</a>) (<a href="https://github.com/angular/material/commit/9852ff7">9852ff7</a>), closes <a href="https://github.com/angular/material/issues/9592">#9592</a></p></li>
<li><p><strong>select</strong>: extra scrollbar when select dropdown is open (<a href="https://github.com/angular/material/issues/11453">#11453</a>) (<a href="https://github.com/angular/material/commit/20fc2d8">20fc2d8</a>)</p></li>
<li><p><strong>select</strong>(multiple): Remove side-effects to forms when adding <code>md-select</code> elements (<a href="https://github.com/angular/material/issues/11491">#11491</a>) (<a href="https://github.com/angular/material/commit/97e2d00">97e2d00</a>), closes <a href="https://github.com/angular/material/issues/11490">#11490</a></p></li>
<li><p><strong>sidenav</strong>: refactor syntax to work around issue in babel-minify (<a href="https://github.com/angular/material/issues/11351">#11351</a>) (<a href="https://github.com/angular/material/commit/0ed110b">0ed110b</a>)</p></li>
<li><p><strong>switch</strong>: theming issues with focus in dark theme (<a href="https://github.com/angular/material/issues/11459">#11459</a>) (<a href="https://github.com/angular/material/commit/71e0411">71e0411</a>), closes <a href="https://github.com/angular/material/issues/8518">#8518</a> <a href="https://github.com/angular/material/issues/11417">#11417</a></p></li>
<li><p><strong>tabs</strong>: provide guidance on how to navigate between tabs (<a href="https://github.com/angular/material/issues/11402">#11402</a>) (<a href="https://github.com/angular/material/commit/4b1b729">4b1b729</a>), closes <a href="https://github.com/angular/material/issues/10895">#10895</a></p></li>
<li><p><strong>tabs</strong>: show a visual indication of tab focus (<a href="https://github.com/angular/material/issues/11392">#11392</a>) (<a href="https://github.com/angular/material/commit/1d73d81">1d73d81</a>)</p></li>
<li><p><strong>tabs</strong>: tab labels overly truncated on IE11 when pagination active (<a href="https://github.com/angular/material/issues/11432">#11432</a>) (<a href="https://github.com/angular/material/commit/2b2f441">2b2f441</a>), closes <a href="https://github.com/angular/material/issues/10406">#10406</a></p></li>
<li><p><strong>theme</strong>: prepend # to hex codes for <code>enableBrowserColor</code> (<a href="https://github.com/angular/material/issues/11492">#11492</a>) (<a href="https://github.com/angular/material/commit/0306ac0">0306ac0</a>), closes <a href="https://github.com/angular/material/issues/11259">#11259</a></p></li>
<li><p><strong>toast</strong>: improve a11y support for <code>$mdToast.simple()</code>. improve docs (<a href="https://github.com/angular/material/issues/11424">#11424</a>) (<a href="https://github.com/angular/material/commit/fedb9a3">fedb9a3</a>), closes <a href="https://github.com/angular/material/issues/349">#349</a></p></li>
<li><p><strong>toast</strong>: remove the interim element from the list before closing element (<a href="https://github.com/angular/material/issues/11427">#11427</a>) (<a href="https://github.com/angular/material/commit/f616b25">f616b25</a>)</p></li>
</ul>
<h1 id="features">Features</h1>
<ul>
<li><p><strong>autocomplete</strong>: add <code>input-aria-label</code> and <code>input-aria-labelledby</code> (<a href="https://github.com/angular/material/issues/11412">#11412</a>) (<a href="https://github.com/angular/material/commit/534beea">534beea</a>), closes <a href="https://github.com/angular/material/issues/10815">#10815</a></p></li>
<li><p><strong>autocomplete</strong>: add support for <code>input-aria-describedby</code> (<a href="https://github.com/angular/material/issues/11405">#11405</a>) (<a href="https://github.com/angular/material/commit/a25a7df">a25a7df</a>), closes <a href="https://github.com/angular/material/issues/11004">#11004</a></p></li>
<li><p><strong>contactChips</strong>: add basic support for <code>md-separator-keys</code> (<a href="https://github.com/angular/material/issues/8142">#8142</a>) (<a href="https://github.com/angular/material/commit/eb10b56">eb10b56</a>)</p></li>
<li><p><strong>slider</strong>: enable page up/down and home/end keyboard actions (<a href="https://github.com/angular/material/issues/11517">#11517</a>) (<a href="https://github.com/angular/material/commit/70654c3">70654c3</a>), closes <a href="https://github.com/angular/material/issues/11515">#11515</a></p></li>
<li><p><strong>tabs</strong>: allow specifying custom class names for tabs (<a href="https://github.com/angular/material/issues/11332">#11332</a>) (<a href="https://github.com/angular/material/commit/aa30ada">aa30ada</a>)</p></li>
<li><p><strong>theming</strong>: add ability to specify hues as options to <code>defineTheme</code> (<a href="https://github.com/angular/material/issues/11428">#11428</a>) (<a href="https://github.com/angular/material/commit/f776bf7">f776bf7</a>)</p></li>
</ul>
<h1 id="performanceimprovements">Performance Improvements</h1>
<ul>
<li><p><strong>tabs</strong>: <code>md-center-tabs</code> causes in high CPU usage (<a href="https://github.com/angular/material/issues/11375">#11375</a>) (<a href="https://github.com/angular/material/commit/7fdf9da">7fdf9da</a>), closes <a href="https://github.com/angular/material/issues/9690">#9690</a> <a href="https://github.com/angular/material/issues/6375">#6375</a></p></li>
<li><p><strong>tabs</strong>: remove unreferenced elements variable from TabsController (<a href="https://github.com/angular/material/issues/11379">#11379</a>) (<a href="https://github.com/angular/material/commit/33652b4">33652b4</a>), closes <a href="https://github.com/angular/material/issues/11377">#11377</a></p></li>
<li><p><strong>css</strong>: remove bloat from auto prefixing of unsupported browsers (<a href="https://github.com/angular/material/issues/11340">#11340</a>) (<a href="https://github.com/angular/material/commit/3660a32">3660a32</a>)</p></li>
</ul>
<p>This auto prefixing change reduced the minified CSS bundle size by 76 KB. You can find the breakdown of supported browsers <a href="https://material.angularjs.org/HEAD/#browser-support">here</a>.</p>
<h1 id="documentation">Documentation</h1>
<ul>
<li><p>We’ve updated <a href="https://material.angularjs.org/latest/#browser-support">our home page</a> to include more details about the <a href="http://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+not+ie+%3C%3D+10%2C+not+ie_mob+%3C%3D+10%2C+not+bb+%3C%3D+10%2C+not+op_mob+%3C%3D+12.1">browsers and versions</a> that AngularJS Material supports.</p></li>
<li><p>We made many small tweaks to the docs to fix broken links, update URLs to the <a href="https://material.io/archive/guidelines/">Material Design 2014–2017 Spec</a>, and fix syntax and formatting.</p></li>
<li><p>We also made changes across the docs and demos to properly support dark mode themes.</p></li>
<li><p><strong>a11y:</strong> audit of our entire docs and demos site to resolve most all of our accessibility issues identified by Lighthouse</p></li>
<li><p><strong>icon:</strong> update our guidance for using SVGs and provided details about the new <a href="https://material.io/tools/icons/">Material Design Icons tool</a></p></li>
<li><p><strong>contact-chips:</strong> add docs for <code>md-highlight-flags</code></p></li>
<li><p><strong>highlight-text:</strong> add <code>md-highlight-flags</code> example</p></li>
<li><p><strong>list:</strong> clarify the docs around <code>md-avatar-icon</code></p></li>
<li><p><strong>slider:</strong> add missing docs for APIs like <code>md-vertical</code>. Fix demos in IE11</p></li>
<li><p><strong>input:</strong> fix issues with displaying the types in the docs. Add docs for <code>md-select</code> inside of <code>md-input-container</code></p></li>
<li><p><strong>select:</strong> add missing docs for <code>md-option</code> and <code>md-optgroup</code></p></li>
<li><p><strong>toast:</strong> add example of using <code>locals</code> to the custom toast demo</p></li>
<li><p><strong>typography:</strong> fix URL for Roboto font and general cleanup of the guide</p></li>
</ul>
<h1 id="contributors">Contributors</h1>
<p>Thank you to the <a href="https://github.com/angular/material/blob/master/CHANGELOG.md#contributors">contributors</a>,
especially the first timers, who helped with the v1.1.11 release:</p>
<p><a href="/angularjs-material/1-1-11-contributors.png"><img src="/angularjs-material/1-1-11-contributors.png" alt="AngularJS Material v1.1.11 Contributors" /></a></p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[My Experience with the MacBook Pro 2018 w/ Vega graphics]]></title>
            <link>https://devintent.com/blog/2018-12-07-my-experience-with-the-macbook-pro-2018-w-vega-graphics.md</link>
            <guid isPermaLink="false">blog/2018-12-07-my-experience-with-the-macbook-pro-2018-w-vega-graphics.md</guid>
            <pubDate>Fri, 07 Dec 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Description of migrating to and configuring a new MacBook Pro 2018 w/ Vega graphics from a web developer.]]></description>
            <content:encoded><![CDATA[<p>After exploring the
<a href="https://www.devintent.com/blog/2018-11-25-my-pixelbook-dev-experience">Pixelbook as a development platform</a>,
I decided that I need to replace my mid-2014 MBP w/ 16 GB RAM 256 GB SSD and Intel graphics with the new
2018 MBP w/ Touch Bar 32 GB RAM 512 GB SSD and Vega 20 graphics.</p>
<p>I am going to use this post to chronicle the first days of using this machine. I hope that it will help other
developers and professionals who may also be looking at the latest MacBook Pro line up. Oh and I’m sure
there will be some gaming content in here as well 😁</p>
<h1 id="day0">Day 0</h1>
<p>When I purchased my 2014 MBP, I opted to pass on the Nvidia discrete graphics card. This was based on two
primary drivers: heat and usage.</p>
<p>At the time, I had a Dell XPS desktop for gaming. So I didn’t intend to do any graphics heavy tasks on the
MBP. I was also upgrading from a Chromebook Pixel 2013 which had a very hot i5 CPU. Thus, I wanted to get a
device that I could use on my lap while doing basic web browsing or writing.</p>
<p>Fast forward to 2018, my 2014 MBP is 4.5 years old and well outside of the extended warranty plus my gaming
desktop is about to be retired. I’m also in a situation where I anticipate needing to be able to do all of my
professional work on a mobile platform for the next few years. This means that something like the attractive
2018 Mac mini won’t work for me.</p>
<p>I watched the early 2018 MBP i9 thermal drama unfold from a distance. I was happy to see that Apple quickly
released a patch for this. The resulting benchmarks were acceptable to me. Additionally, as a developer, the
burst speed of the i9 processor is valuable to me as it helps to eliminate micro interruptions in my workflow.
I don’t really need to run the CPU at max for extended periods of time as is needed for video processing.</p>
<p>I was convinced to go with the Vega 20 after watching a number of videos that covered the benchmarks,
thermals, and real world performance. For reference, some of those include:</p>
<ul>
<li><p><a href="https://www.youtube.com/watch?v=cw1daSLJ-rc">Vega 20 MacBook Pro Benchmarks vs 560X!</a></p></li>
<li><p><a href="https://www.youtube.com/watch?v=OEgl4B8A_qw">Gaming on the VEGA 20 MacBook Pro — 2018</a></p></li>
<li><p><a href="https://www.youtube.com/watch?v=kJVciTqsUAo&t=3s">Is Vega 20 Worth it for 15" MacBook Pro? Benchmarks & Thermals</a></p></li>
<li><p><a href="https://www.youtube.com/watch?v=YVTjbo3Z66k">Vega 20 MacBook Pro Gaming — Battlefield 5, Black OPS 4, and Fortnite!</a></p></li>
<li><p><a href="https://www.youtube.com/watch?v=2zWSNHuqtPA">Best MacBook Pro? (Radeon Vega 20) — Unboxing + Benchmarks</a></p></li>
<li><p><a href="https://www.youtube.com/watch?v=neRjnJ4SWMk&t=1s">Gaming on the Vega 20 MacBook Pro!?</a></p></li>
</ul>
<p>A brief summary of those videos</p>
<ul>
<li><p>The thermals of the i9 w/ Vega 20 seem to be improved over those of the i9 w/ 560X even in pure CPU tasks.</p></li>
<li><p>The Vega 20 was able to get 60+ FPS in modern games at medium settings and in slightly older games at high settings.</p></li>
<li><p>The previous issues of throttling and stuttering during game play have been resolved (I believe as part of the thermal patch).</p></li>
<li><p>The i9 w/ Vega 20 graphics provided a ~20–60+% increase to graphics performance for ~10% increase in cost.</p></li>
<li><p>Gaming on Windows 10 in Boot Camp provided an increase of about 10–25 FPS over the same in macOS.</p></li>
</ul>
<p>Additionally, I researched peripherals and adapters so that I could work with USB-C effectively. I
picked up a <a href="https://smile.amazon.com/gp/product/B07B9PJ7FQ/">USB-C card reader</a> and
<a href="https://smile.amazon.com/gp/product/B07BT11PTP/">two Thunderbolt 3 to HDMI adapters</a>. These were used to
hook up my two external monitors and, since the MBP has 4 USB-C ports, I’ll also be able to
plug in power and a dongle for my external mouse and keyboard. The adapters also came with a discount for a
<a href="https://smile.amazon.com/gp/product/B07F7HY6VW">Thunderbolt 3 to VGA adapter</a> which will be useful when
presenting at some schools and meetups. I decided to wait on ordering a dock until I was confident the
laptop was going to be a keeper. The dock that I have my eye on is the
<a href="http://shop.caldigit.com/us/Docking%20Stations/Thunderbolt%20Station%203?product_id=171">CalDigit Thunderbolt 3 dock w/ 85 W charging</a>.</p>
<p>My new MBP shipped straight from Shanghai. There was a delay of 2 days in Japan and that triggered UPS to
push my expected delivery date by 4 days. Thankfully, soon after that it started moving again and was quickly
back on track for on time delivery.</p>
<h1 id="day1">Day 1</h1>
<p>When FedEx delivered my new MBP, it was a familiar unboxing experience. I went with silver, partially since
I didn’t want a darker color that might absorb more external heat. It’s probably only the smallest possible
difference, but it was enough for me 😉</p>
<p>The feel and build was similar to by 2014 MBP, but there were some differences. It felt slightly thinner
overall and instead of a light up apple on the top, it’s just a shiny silver apple. 👍🏼</p>
<p>When I opened it up, the giant touchpad really stood out and worried me that it might cause issues
while typing. The Touch Bar was there too… and the keyboard…</p>
<p>Thankfully it arrived with macOS Mojave already installed.</p>
<h4 id="migration">Migration</h4>
<p>I booted it up and wasn’t sure what to expect of the Migration Assistant. The first attempt was with Wi-Fi,
but I saw a message that connecting to my old MBP via USB would be faster. So I got the USB-A to USB-C data
cable that came with my Pixel XL and plugged that in to each laptop. My old MBP detected it and switched to
Peer-to-Peer networking, but the new MBP got stuck at “Switching”.</p>
<p>I had to cancel and restart the process. This time connected via USB from the start. I also had to make sure
to overwrite and not duplicate any of the users, or the files (uncheck a box in the Migration Assistant wizard).
The migration went smoothly this time. It originally estimated around 3 hours and 45 minutes to complete, but
it was done within a couple of hours.</p>
<p>I knew that it was going to try to migrate some apps and settings, but I didn’t have high hopes and expected
to install a bunch of apps and tweak a lot of settings after it was done. To my surprise, it basically copied
over my entire device to the new device with almost nothing missing other than re-granting security and
accessibility permissions! <strong>This was really the experience that I was hoping for!</strong></p>
<p>This gives me a lot of confidence that should I have a MBP fail, I can restore to another MBP device from a
Time Machine backup and be productive again in just a couple of hours. This is critical to me and my
consulting business.</p>
<h4 id="bootcamp">Boot Camp</h4>
<p>I read a number of articles about installing Windows 10 via Boot Camp and it seemed somewhat straight forward.
It was my first time working with Boot Camp though.</p>
<p>I downloaded the 5.08 GB Windows ISO from October 2018. I picked 150 GB for my Windows 10 partition and started
it up. After about 30 minutes, it failed to copy the Windows files and started trying to back out the
partitions that it had created. This seemed to get stuck, so I had to cancel it and manually clean up the
partitions as detailed <a href="https://twocanoes.com/using-larger-windows-10-isos-with-boot-camp-assistant/">here</a>.</p>
<p>That <a href="https://twocanoes.com/using-larger-windows-10-isos-with-boot-camp-assistant/">same article</a> explained
that the issue was Boot Camp’s partitions being FAT32 which support file sizes up to 4 GB. Then it provided a
Boot Camp ISO Converter tool to split the ISO into smaller chunks in Boot Camp. I also disabled Time Machine
and installed an update to Mojave just to be safe. This worked like a charm for me!</p>
<p>Windows 10 on a Mac was quite disorientating to me initially. Dragging windows with the touchpad didn’t seem
to work and tap to click wasn’t enabled. Thankfully I found options in the Boot Camp settings to enable tap
to click. It also had an option to change how window dragging worked, but that didn’t seem to help. I just
had to figure out that I had to click and drag all with one finger instead of holding a click with one
finger and dragging with another finger.</p>
<p>There were some prompts to install drivers, Windows updates that needed to install, virus scanning, and the
usual range of other Windows tasks that had to be sorted out. I also went and cleaned up most of the privacy
settings, disabled Cortana, and uninstalled as many Windows store apps as possible. Oh but I did install
Slack from the Windows store. Then I downloaded and installed Chrome, Firefox, NVDA, Guild Wars 2, and
Star Wars, The Old Republic.</p>
<p>Downloading, installing, and patching these games really gave the machine a workout. It flew through most
tasks, but this got the fans going and got the CPU load up to around 18% while the Wi-Fi was going as fast as
possible (unfortunately, we don’t have Fiber here). Even with all of this load, the palm rest remained a
comfortable ~45C while the CPU ramped up to around ~80C. It certainly created a hot spot on my desk and
would not have been comfortable on my lap under this kind of load.</p>
<p>That said, while sitting here in macOS with a 30+ open Chrome tabs, Slack open, numerous menu add-ons
running, lots of Chrome extensions enabled, and writing this post, the palm rest is at a cool 30C, the GPU
is only 35–40C, and the CPU is 38–45C. These temperatures are perfectly comfortable to use on your lap.</p>
<p>The MBP handled this load just fine over a period of about 3–4 hours while ~80GBs of game assets and patches
were downloaded. After one of the games finished, and the other was playable, but downloading background
updates, I decided to walk away for a bit and shut the lid. Doh! I hadn’t changed the Windows 10 settings
for this, and it went to sleep right away. I could tell when the fans cut off about 20 seconds after closing
the lid.</p>
<p>I opened it back up and went to change the setting when <strong>BSOD</strong>! Windows crashed, and the Event Viewer
didn’t have much useful information for me. I didn’t see anything related to bridges or T2 chips… After
rebooting, I was able to change the setting and get it to keep running after closing the lid.</p>
<p>About 5 hours later, after all the updates and downloads finished, I was installing NVDA when
Windows 10 prompted me with a popup about sound issues. Then another <strong>BSOD</strong>! After rebooting, I was
able to install NVDA without any problems. I tested using it for a bit and verified that sound was
working in Google Play Music.</p>
<p>Using a <a href="https://smile.amazon.com/nonda-Adapter-Thunderbolt-Aluminum-Indicator/dp/B015Z7XB30/">Nonda USB-A to USB-C adapter</a>,
I was able to work with my U2F security key just fine. This adapter is Thunderbolt 3 compatible and passes
data just fine while I have another adapter that only handles charging and doesn’t work with data. Keep
this in mind if you are looking into USB-C adapters. I had picked up this attractive Nonda adapter at
<a href="https://devfestflorida.org/">DevFest Florida</a> 2016 as a speaker’s gift.</p>
<h1 id="day2">Day 2</h1>
<h4 id="backtomacos">Back to macOS</h4>
<p>I decided to head back to macOS in order to write up the first day of experiences and to start testing
peripherals like my external keyboard, mouse, monitors, and backup drive.</p>
<h4 id="keyboard">Keyboard</h4>
<p>Now I’ve been typing on this keyboard for a few hours now… It’s certainly worse than my 2014 MBP, and
it’s much worse than the Pixelbook’s keyboard. Even with the minimal typing required for installing
software and entering basic details, it caused me to make a lot more mistakes than usual. I figured that
this might just take some getting used to, so I waited until day 2, after writing this post, to provide
feedback on the typing.</p>
<p>So the verdict after writing up this post with the MBP 2018 keyboard? I can certainly still type fast!
But there are a lot missed keystrokes and mistyped keys, much more than any other typing experience that
I’ve had in years. The “new, softer sounding keys” are too loud for my tastes and the “new, softer feel”
is also not something that I am happy with.</p>
<p>The arrangement of the up and down arrow keys on the MBP is not something that I like compared to the 2014
model. That said, it hasn’t caused me too much pain, yet.</p>
<p>I don’t know if there is a setting for this or not, but the <code>caps lock</code> key’s light only seems to work about
20% of the time. I don’t know how, why, or when it decides to work, but I’ve seen it come on. If I click
it a bunch of times here in Medium, the light stays off, but the caps lock mode does enable and disable.
<strong>Solved:</strong> this turned out to be a <a href="https://github.com/tekezo/Karabiner-Elements/issues/1502">bug in Karabiner</a>
that was fixed in their beta a couple months ago and just got fixed in their stable release in February 2019.</p>
<p>In my home office, these keyboard issues won’t be a problem since I’ll be using a trackball and external
keyboard. However, I’ve never been a person to carry an external keyboard to co-working spaces. That may
need to change. I wonder if there is already a keyboard on Kickstarter that fits over the top of the
MBP’s keyboard 🤔</p>
<p>Now before we get into the Touch Bar, I just wanted to be clear, the MBP 2018 keyboard is by far the
most underwhelming and disappointing feature of the device.</p>
<h4 id="touch">Touch</h4>
<p>I am generally happy with the touchpad so far. I’m also happy with the Touch ID sensor. However, I wish that
I could use my fingerprint for even more of the admin password prompts.</p>
<p>The Touch Bar experience in Windows 10 was a little confusing. Sometimes the volume up and down virtual
keys would work, sometimes they would not. The <code>esc</code> key seemed to work.</p>
<p>The Touch Bar experience is unsurprisingly better in macOS. I have enjoyed being able to tap the volume or
brightness buttons and then use the slider to find a setting that I was happy with. Some shortcuts
in Finder and Chrome are useful, but I haven’t used them much yet.</p>
<p>Slack doesn’t offer anything but the default <code>esc</code> and brightness / volume / mute / Siri virtual buttons.</p>
<p>The Touch Bar in JetBrains’ WebStorm and IntelliJ IDEA seems quite useful! Here’s what I see when I open a project:</p>
<p><a href="/large-images/touch-bar-webstorm.jpeg"><img src="/large-images/touch-bar-webstorm.jpeg" alt="Touch Bar with a project open in WebStorm" /></a></p>
<p>You can see that it offers me a menu to pick from the Run Configurations, then buttons to run, debug, or
stop a Configuration. Additionally, it offers to the Git Update and Git Commit buttons.</p>
<p>If you open the Run Configurations menu, you can scroll through the options in the Touch Bar:</p>
<p><a href="/large-images/touch-bar-run-configs.jpeg"><img src="/large-images/touch-bar-run-configs.jpeg" alt="Scrolling through Run Configurations in the Touch Bar" /></a></p>
<p>In this case, there is a green dot on “Watch Site” because it is currently running. If I exit the menu,
I can see that the Run button has changed to Re-run, and the Stop button is enabled:</p>
<p><a href="/large-images/touch-bar-re-run-stop.jpeg"><img src="/large-images/touch-bar-re-run-stop.jpeg" alt="Run button becomes Re-run and the Stop button is enabled" /></a></p>
<p>Even the Git Commit dialog has Touch Bar support. In this case it saves me an extra click by showing
“Commit and Push…” in the Touch Bar:</p>
<p><a href="/large-images/touch-bar-commit-and-push.jpeg"><img src="/large-images/touch-bar-commit-and-push.jpeg" alt="Picture of Commit and Push option in Touch Bar" /></a></p>
<p>Since I use a Logitech K800 Wireless, back-lit keyboard with a Windows layout for most of my work, I have
the F1-FX keys mapped to actions like volume up/down, mute, etc. Thus, I don’t really make use of these
Function keys when doing development. My primary shortcuts in WebStorm are all configured to use
<code>control</code> , <code>shift</code> , <code>option</code> , combinations instead.</p>
<p>That means that I’m not really sad to be “missing” the F keys. I also haven’t hit a situation yet where
I needed the <code>esc</code> key, and it wasn’t there. I’ll certainly be keeping my eye open for that though.</p>
<p>Verdict after 2 days: I’m learning to live happily with the new Touch Bar. Hopefully I don’t like it too
much though. There are no external keyboards with Touch Bars yet and getting used to this 2018 MBP
keyboard isn’t proving to be easy.</p>
<h4 id="peripherals">Peripherals</h4>
<p>Everything went super smoothly with hooking up two 27" AOC 1080p HDMI monitors, an Anker 10 port
USB 3.x Hub, and power. The time it takes to wake and sync the monitors seems to be cut in half
compared to my 2014 MBP w/ Intel graphics.</p>
<p>I was a little worried that, with all 4 USB-C ports in use, I would have a problem with using my
Titan U2F Security key. That was solved easily by just plugging it into my Anker Hub.</p>
<p>I haven’t had time, or a need to test out my Uni Thunderbolt 3 to VGA Adapter or
Anker Thunderbolt 3 SD Card Reader yet.</p>
<p>It’s certainly a pleasure to be using this high speed laptop with my beloved Logitech K800 keyboard and
M570 Trackball!</p>
<h4 id="additionalperipheralresearch">Additional Peripheral Research</h4>
<p>I noticed that Logitech released the new <a href="https://smile.amazon.com/gp/product/B0753P1GTS">MX Ergo Trackball</a>
last year. So I put in an order immediately since it was at its lowest price in 4+ months (it’s now about \$6
higher than yesterday). I can’t wait to try it out after 5 solid years with two of the M570s.</p>
<p>I also did a lot of research on keyboards in the last 2 weeks. I got some great recommendations for things
like the Code keyboard, and the Apple Magic keyboard, however I’m looking for a wireless, back-lit keyboard
with a Mac keyboard layout. The Code isn’t wireless. The Magic isn’t back-lit. The K800 has a Windows layout.</p>
<p>I looked at the Macally keyboards, but wasn’t able to find a good fit. However, it sounds like they may be
launching something that meets my needs in the next few months.</p>
<p>I got a suggestion for Matias keyboards as well, but there are too many reviews that are very negative on
the typing experience.</p>
<p>The best match that I can find seems to be the new <a href="https://smile.amazon.com/dp/B0768LTVCQ">Logitech Craft keyboard</a>.
However, it’s $199 MSRP (twice that of the K800) stopped me in my tracks. It’s currently $169 on Amazon, but
I’m going to try waiting a few more months to see if there are any price dips. One of the biggest complaints
with the Craft is the Logitech software support. Hopefully over the next few months, they can squash a few
more bugs.</p>
<h1 id="day3">Day 3</h1>
<p>I spent a good deal of time cleaning up my machine today. This meant removing old VirtualBox VMs and
uninstalling VirtualBox since I have VMWare Fusion now. While doing that I noticed some old multi-GB
docker images, Android Virtual Devices, and some other cached files from NVM, Gradle, Maven, etc that
could be cleaned up.</p>
<p>I also noticed that some programs weren’t compatible with Mojave. This wasn’t an issue with the new MBP,
as the same needed to be done on my old laptop as well. This just meant downloading and installing updates
to things like KeyCastr, Robo 3T, Android File Transfer, Postman, Logitech Camera Settings, Logitech
Control Center, etc.</p>
<p>While Git, SSH, GPG, and many other CLI tools were working fine after the migration, there were still
some issues with MacPorts giving some <code>plist</code> warnings when running <code>sudo port selfupdate</code>. I followed
the steps in the <a href="https://www.macports.org/install.php">Install Guide</a> and I was back up and running
(without needing to do the steps in the <a href="https://trac.macports.org/wiki/Migration">Migration Guide</a>).</p>
<p>I also spent some time customizing the key mappings when using my external keyboard via
<a href="https://pqrs.org/osx/karabiner/">Karabiner Elements</a>. While doing this, I noticed that my volume up,
volume down, and mute keyboard buttons were working w/o the need to map them to a Function key.
Some time ago, this wasn’t working on my 2014 MBP, but I didn’t go back to verify if this still an
issue on that device.</p>
<p>Just like I saw with the built-in keyboard, the <code>caps lock</code> light not coming on while using my
Logitech K800. I tried to enable Karabiner’s option to “manipulate” the Caps Lock LED, but it didn’t help.
**Solved: **this turned out to be a <a href="https://github.com/tekezo/Karabiner-Elements/issues/1502">bug in Karabiner</a>
that was fixed in their beta a couple months ago and just got fixed in their stable release in February 2019.</p>
<p>I ran into some confusing behavior in Chrome that seems to be related to the Migration. I went into Sharing
Settings to give this new Mac an updated Name. This didn’t seem to help though. Whenever I go into Chrome’s
History and look at “tabs from other devices”, I can’t see tabs from my 2014 MBP. It’s like Chrome somehow
thinks that the two devices are a single device. I disabled and re-enabled sync on both devices without any
luck. I stopped short of completely clearing my sync data, which the forums mentioned may be required.</p>
<p>I also setup Chrome Remote Desktop. After the migration, this meant disabling remote desktop on both MBPs
and then re-enabling it with updated names and PINs.</p>
<p>Overall, things are feeling clean and fast now. This “Spring cleaning” cleared up around 20 GB of disk space.</p>
<p>I also watched a nice summary video on this machine from AppleInsider</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=0zmxkmDDpAM">Vega 20 MacBook Pro Review — The Dream is Finally Complete!</a></li>
</ul>
<p>It looks like some of my keyboard settings didn’t make the migration. I noticed that I wasn’t able to hold
a key to have it repeat. This is especially important with <code>delete</code>. I found that the “Delay Until Repeat”
setting in Keyboard settings was set too long. I moved it to the second shortest value. Then <code>delete</code>
started working as expected. So of course I tried it with some other keys like <code>aaaaaa</code>, but that didn’t
work! Instead, it opened up an accent picker.</p>
<p>This was new to me. <a href="https://appleinsider.com/articles/18/03/16/how-to-type-accented-letters-in-macos-three-different-ways">An AppleInisider article</a>
helped me understand what was going on. I am happy with the <code>option</code> shortcut method:</p>
<p><a href="/large-images/keyboard-viewer-option-key-pressed.png"><img src="/large-images/keyboard-viewer-option-key-pressed.png" alt="Keyboard Viewer with option key pressed" /></a></p>
<p>This screenshot is showing that if you want to type <code>ü</code> then you need to press <code>option+u</code> and then <code>u</code> again.
Using this same approach but typing <code>option+u</code> and then <code>e</code> will give you <code>ë</code>. Great! This will work
perfectly for me when I need to use different accents (something that I am trying to get better with in
Spanish).</p>
<p>However, I want to repeat keys on long press. To do that, I found
<a href="https://apple.stackexchange.com/a/167834/87494">this answer</a> which advised running the following in the
Terminal to disable the accent picker on long press:</p>
<pre><code class="bash language-bash">defaults write -g ApplePressAndHoldEnabled -bool false
</code></pre>
<p>Then you need to reboot for it to take effect.</p>
<h1 id="day4">Day 4</h1>
<p>I went back to work with a full focus on productivity. This machine blew my mind with its speed 🚀 and
general productivity boosts ❤️. I haven’t taken measurements yet (planning on it), but there is a very
noticeable improvement in the speed in my every day development and testing tasks.</p>
<h1 id="day5">Day 5</h1>
<p>I decided to dig into the media aspect of this device. I used an Anker USB-C SD Card Reader to pull 25 GB of
photos off of my DSLR. Then I proceeded to copy and organize those files before batching uploads to both
Google Photos and a Synology NAS. This resulted in driving the network card and CPU quite heavily for many
hours in a row. Everything went extremely smoothly.</p>
<p>I’m not an experienced video editor, but I did some work on some small video editing in iMovie. I’ve
identified a 2.75 GB video that I plan to do some additional testing with. Other than my own issues
learning to use the iMovie user interface, everything here went smoothly as well.</p>
<p>The Logitech MX Ergo Trackball arrived. Pairing it up with the Logitech receiver and installing Logitech
Options was simple. The transition from the Logitech M570 Trackball was pretty smooth. After a few hours,
most all the minor differences faded away. This even included using the Ergo at the 20 degree tilt.
I appreciate the minor amount of extra friction / stepping in both the trackball, and the mouse wheel.
The precision mode is very handy, but I forgot to use it earlier when I was editing images in GIMP.</p>]]></content:encoded>
            <category>mac</category>
            <category>webstorm</category>
            <category>chrome</category>
            <category>git</category>
        </item>
        <item>
            <title><![CDATA[My Pixelbook Developer Experience]]></title>
            <link>https://devintent.com/blog/2018-11-25-my-pixelbook-dev-experience.md</link>
            <guid isPermaLink="false">blog/2018-11-25-my-pixelbook-dev-experience.md</guid>
            <pubDate>Sun, 25 Nov 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Head-to-head comparison of the development experiences on the Google Pixelbook and Apple MacBook Pro.]]></description>
            <content:encoded><![CDATA[<p>I ordered the <code>i7 16GB RAM 512GB SSD</code> Pixelbook with the Black Friday deal that started on
November 22nd.</p>
<h1 id="day1">Day 1</h1>
<p>My Pixelbook arrived this afternoon. Within a few hours, I’ve already got my
<a href="https://www.devintent.com/blog/2018-11-24-using-a-pixelbook-for-angular-development">primary dev tooling installed and working</a>!
There were only a few minor bumps in the road, and they were quickly resolved with a quick Google search.</p>
<p>I’m curious how things will play out over the next week as I try to push it for productivity tasks.</p>
<p>I’ll also be monitoring the thermal performance since I don’t want to be working at some point in
the future with burning finger tips. So far today, I felt some heat when I reached up above the
keyboard and below the screen. However, when I checked
<a href="https://chrome.google.com/webstore/detail/cog-system-info-viewer/difcjdggkffcfgcfconafogflmmaadco?utm_source=chrome-app-launcher-search">Cog</a>,
the temps were actually not bad at all (160 F / 71 C or less).</p>
<p>With the machine mostly idle, 4–5 tabs open, while I wrap up this post, the CPU is barely over body
temperature at 104–109 F.</p>
<p><a href="/large-images/pixelbook-cog-monitoring.png"><img src="/large-images/pixelbook-cog-monitoring.png" alt="Screenshot of Cog system monitoring app" /></a></p>
<p>The battery life is very impressive so far. I’ve been off of power most all day, and I’ve still got
over 30% power remaining and almost 3 hours of estimated run time.</p>
<p>I’ll also be doing a good deal of testing with Bluetooth. I was able to use an LG Tone 700 headset
for over an hour today without any disconnections or issues.</p>
<p>There has been one minor usability glitch that has bothered me a few times today. On about 5–10
different occasions, the machine seemed to lag or freeze up. Sometimes this was only affecting the
scroll of the touch pad, or the responsiveness of the touch screen. Other times the entire UI was
frozen and there was no way to interact with the device. This generally only lasted 1–20 seconds…
until just about 5 minutes ago.</p>
<p>I wrote 99% of this post on the Pixelbook, but I’m finishing up the first draft here on my mid-2014
MacBook Pro. With 30% battery left and low heat (as seen above), I closed all of my Linux and
Android apps. I also closed a few open tabs to get down to only 4 tabs open. Then while making
minor edits to this post in the Medium web app, everything froze.</p>
<p>It never came back. After about 5 minutes, the machine rebooted itself to this:</p>
<p><a href="/large-images/chrome-os-damaged.jpg"><img src="/large-images/chrome-os-damaged.jpg" alt="Picture of Chrome OS missing or damaged screen" /></a></p>
<p>I pressed the power button and tried to reboot it, but it just turned off. There were no connected
devices. Nothing I did was able to wake it back up, even holding the power button for 30+ seconds,
until I plugged it into power. It then booted up pretty quickly and still had 29% battery left.</p>
<p>That was… a little scary. When I first unboxed the device, I had a similar experience. I couldn’t
get the power button to do anything. Only when I connected my Pixel XL via USB-C did it power on
and start responding.</p>
<h1 id="day2">Day 2</h1>
<p>I found out that the Chrome OS missing or damaged screen
<a href="https://www.digitaltrends.com/computing/most-common-pixelbook-problems/">isn’t new and isn’t that uncommon</a>.</p>
<p>I didn’t have a lot of time today for development tasks, but I did get a good deal of web browsing,
and a little Android gaming done. I found that using the device on the lap in either tablet or
laptop mode did not generate enough heat to bother me. This was after about an hour of web browsing
and some <a href="https://play.google.com/store/apps/details?id=com.ea.game.starwarscapital_row">Star Wars Galaxy of Heroes</a>.</p>
<p>On the gaming side, I’m still getting a feel for the touch screen as there are quite a few occasions
where I don’t touch it with enough force to register and need to tap again. Gaming performance-wise,
I’m seeing a significant improvement over my Nexus 9, but I feel like my Pixel XL may outperform the
Pixelbook in the GPU category.</p>
<p>I was able to get the Google Cloud SDK (gcloud) installed using their
<a href="https://cloud.google.com/sdk/docs/downloads-apt-get">instructions for Debian</a>.</p>
<p>I was able to get IntelliJ IDEA installed and running with almost the same instructions that I used
for WebStorm. I ran into an issue with the Google Cloud Tools plugin and
<a href="https://github.com/GoogleCloudPlatform/google-cloud-intellij/issues/2295">opened a bug</a>.</p>
<p>I was also able to get Android Studio installed and running. I am generally able to install the
SDKs and libraries and get my Gradle builds to succeed. However, there are a number of other minor
issues like not being able to sign in to Google due to the callback going over a port that isn’t
forwarded to Crostini and resolution of secondary SSH keys when using Git. Android Studio suggested
that I install <code>libsecret-1-0</code> and <code>gnome-keyring</code> so that it could preserve access to my keys, but
it doesn’t appear to be working.</p>
<p>I’m also seeing an issue where I need to re-authenticate with GitHub either after rebooting or
re-launching of WebStorm. It says “missing access token” as if the previous token has been lost. I’m
seeing similar issues using a secondary SSH key in WebStorm as well.</p>
<p>I’m getting the feeling Crostini and Chrome OS are on the edge of being a real development platform.
However, the concern that Crostini (beta) may have too many productivity-draining issues with edge
cases is getting more real.</p>
<h1 id="day3">Day 3</h1>
<p>I spent many more hours trying to get a second SSH key to work in IntelliJ IDEA and WebStorm. I
tried both the Built-In and Native SSH, but had no luck. Then I learned about, and setup, a
<a href="https://www.reddit.com/r/Crostini/comments/8rt9gq/sshagent/">ssh-agent service with systemctl</a>.
Additionally, I tried <code>keychain</code> and <code>gnome-keyring</code>some more. Even though everything appeared to be
set up properly and worked from the Terminal, it would never work from the IDE.</p>
<p>I finally just gave up and decided to use the key for associated with my BitBucket account for
accessing both GitHub and BitBucket. I was able to add that email address to my GitHub account.
I’ll have to wait and see if this causes me problems with some PR review bots, commit
verification, or CLA checks in GitHub.</p>
<p>I found out today the issue I reported about the Google Cloud Tools plugin for IntelliJ IDEA wasn’t
specific to Chrome OS. It was just an issue that they hadn’t added support for the latest version of
IntelliJ (2018.3). They released that fix today, and it resolved the issue.</p>
<p>I did however run into another problem with that plugin. It uses a strategy where it logs you in
via OAuth redirects. However, when it tries to send the confirmation back to the IDE, the browser
shows a Not Found page. This is because they use a random high level port (40–60K) each time, and
those ports are not forwarded between Crostini and Chrome OS. Only some well-known ports
are forwarded. For now, being logged into the Google Cloud Tools plugin is not critical for my work,
so I am going to ignore this issue.</p>
<p>That said, Firebase is critical for my work, and they use a similar model for authenticating with
their <code>firebase-tools</code> CLI. I’ll have to give that a shot soon to see if it will be a problem.</p>
<p>Another important activity that I did today was hosting a two-hour Hangouts Meet video call. I did
the whole call connected to my LG HBS 700 Bluetooth headset without any issues. I did some screen
sharing and navigated through a few tabs while on the call. Everything was smooth for about 99% of
the call. I didn’t notice any excess heat being generated and the keyboard and palm rests were still
comfortable to use.</p>
<p>The other person on the call was also using a Pixelbook. While the video quality on both sides was
acceptable, I wasn’t really impressed. The Pixelbook has a 720p 60 FPS webcam which should be
similar in quality to my MacBook Pro mid-2014’s 720p webcam. However, in this small sample, I felt
that it wasn’t really up to par with my MacBook Pro. There was a bit of graininess and as it got
dark, the low light performance didn’t seem to be very good.</p>
<p><em>Note that this is just anecdotal evidence based on a general feel and not head-to-head comparison.</em></p>
<p>I also have some feedback on the keyboard, palm rests, and track pad. In general, the keys have a
really nice feel and are a pleasure to press. I do still get a little disoriented at times and end
up pressing keys 1 column to the right, but I don’t see that being a long term issue.</p>
<p>I <strong>VERY</strong> frequently press the Assistant key when I do not desire to speak with the Assistant. I
really wish that it was up near the function keys, perhaps replacing the hamburger/settings key.
However, I haven’t taken the step to disable it yet, but it’s certainly under consideration.</p>
<p>The palm rests are excellent! They are very comfortable and keep quite cool! Similarly, the track
pad is really a pleasure to use! Sometimes Chrome OS doesn’t scroll quite as smoothly or
responsively as I would like, but that isn’t an issue with the track pad itself.</p>
<p>I did some interesting reading today over at the
<a href="https://old.reddit.com/r/Crostini/wiki/index">Crostini Wiki</a> and
<a href="https://blog.simos.info/a-closer-look-at-chrome-os-using-lxd-to-run-linux-gui-apps-project-crostini/">Simos Xenitellis’ Blog</a>.
The wiki has some great resources and guides for installing and configuring different tools. The
blog post covers some internals of how Crostini is built.</p>
<p>Oh! Finally, I learned
<a href="https://9to5google.com/2018/02/12/how-to-use-emoji-chrome-os-android-basics/">how to insert emojis</a> 🌟!
This is also helpful for adding in some special characters like jalepe<strong>ñ</strong>o. Unfortunately, the
emoji picker doesn’t have text search (like macOS or Slack) 😞 and there are no tooltips on hover
to help you differentiate similar emojis. Additionally, there appears to be a bug where I’m not
able to use the trackpad to scroll through all the emojis (the touch screen does allow you to
do this though).</p>
<h1 id="day4">Day 4</h1>
<p>While I have not run into Bluetooth issues with my Pixelbook, there are a lot of other reports out
there. It looks like a firmware fix from Intel will help mitigate some of these issues in
Chrome 71 (beta). Stay up to date by starring this
<a href="https://bugs.chromium.org/p/chromium/issues/detail?id=904571">bug</a>.</p>
<hr />
<p>I’m finally running into random Bluetooth disconnections. I had 3 of these today in about 30 minutes
of SWGOH with my LG HBS 700 connected. One note on the positive side, this is certainly the best
sound I’ve ever had on SWGOH. On some Android devices (like the Nexus 9), I can sometimes get poor,
crackling audio. On the Pixelbook, it was so crisp and deep! I heard sounds that I had never been
able to discern before!</p>
<p>It looks like there is some bad news for Pixelbook Bluetooth users in the above bug. Today, the
Chromium team responded that while things have been improved with the firmware update in Chrome 71,
there is still an underlying hardware issue that won’t be able to be resolved in existing hardware
(Pixelbooks included).</p>
<p>If you need a device with solid Bluetooth performance, it doesn’t look like the Pixelbook will work
out for you. The bug mentions that the Pixel Slate and
<a href="https://chromeunboxed.com/news/3-new-kaby-lake-chromebooks-in-the-works">‘Nami’ devices</a>, including
the Acer Chromebook 13 and Spin 13, should have the hardware capability to have Bluetooth that
auto-recovers (without a reboot) when it has issues.</p>
<hr />
<p>I spent a couple of hours coding while streaming Google Play Music over Bluetooth via the web
(not the Android app). I wanted to try this to see if my earlier disconnects were related to
actively using an Android app. It wasn’t related. I had about 6 more disconnects (with no auto
reconnection) over this time. Again, the sound seemed very clear, but the disconnections make it
problematic to use the Pixelbook with any Bluetooth accessories 😞</p>
<h1 id="day5betachannel">Day 5 — Beta Channel</h1>
<p>Today I decided that it was time to try the Beta Channel of Chrome OS. The main reason was to try
out the Intel firmware update for the Bluetooth/Wi-Fi chip. It took about 15 minutes to download,
install the updates, and reboot.</p>
<p>This evening I streamed music while coding for about 5 hours with numerous breaks, disconnections
due to going out of range, turning my headset on/off, etc. I also got in about 30 minutes of SWGOH
with BT. Thankfully, I can report that I did not have a single bogus disconnection, and the system’s
BT did not disable itself.</p>
<p>I didn’t do any coding or fiddling with configuration today. I needed to get my productivity up, so
I stuck with my MacBook Pro for dev today.</p>
<h1 id="day6">Day 6</h1>
<p>I was busy working on my MacBook Pro for most of the day, but I streamed Google Play music for at least 3–4
hours on BT without any disconnections or issues.</p>
<p>I also ordered a set of USB-C to HDMI adapters so that I could do some testing with dual external
monitors. I didn’t want to spend the money on a whole
<a href="https://www.devintent.com/blog/2018-11-18-using-a-pixelbook-with-a-docking-station-and-extended-monitors">USB-C Hub with video out yet</a>.</p>
<h1 id="day7">Day 7</h1>
<p>I hooked up the following today</p>
<ul>
<li><p>Uni USB-C to HDMI adapter to AOC 27" monitor</p></li>
<li><p>Anker 10 port USB-A 3.0 Hub</p></li>
<li><p>Logitech K800 Wireless Keyboard</p></li>
<li><p>Logitech M570 Trackball</p></li>
<li><p>Western Digital 1 TB My Book for Mac</p></li>
</ul>
<p>In this configuration, I was only using one of two monitors, but this allowed me to have WebStorm
running side by side: macOS vs. Chrome OS.</p>
<p>I messed with the scaling in the Chrome OS display settings a bit. However, with this configuration,
anything but 100% scaling resulted in blurry text in WebStorm. I needed to bump my font size in
WebStorm up from 9 to 12 (same as in macOS). I had previously lowered it for the Pixelbook display.
Later when I opened WebStorm settings, it appears that the font size was auto converted to 28.</p>
<p>I also had to tweak the font since the Menlo font that I use on macOS isn’t available on Chrome OS.
I settled with Fira Code Medium.</p>
<p>With the scaling and font sizes sorted out and both displays of WebStorm (macOs, Chrome OS) looking
similar, here’s what I noted</p>
<ul>
<li><p>The text in the Project panel (where your files and directories are) has a real nice contrast in
macOS, but it’s smaller and dull in Chrome OS.</p></li>
<li><p>Many parts of WebStorm on Chrome OS are smaller and need to be scaled up to match the size on
macOS. Unfortunately, I can’t do that due to the blurring.</p></li>
<li><p>Fonts and UI elements are significantly sharper on macOS. This actually used to be a weakness
when running any IntelliJ product on macOS compared to Windows. However, JetBrains solved this issue
a couple of years ago. It looks like some kind of similar fix is needed for Chrome OS’ Freon
graphics stack.</p></li>
</ul>
<p>After this, I decided that I needed to get two external monitors set up. However, this meant losing
my external mouse and keyboard since I don’t have a USB-C Hub. The good news is that the Pixelbook’s
keyboard and trackpad are excellent, so I’m using them in that configuration to write up this post.
Of course this also means that I can’t charge in this configuration due to only having 2 USB-C
ports. For any longer term use, you would certainly want a USB-C Hub to solve that.</p>
<p>So configuration #2 consisted of the following</p>
<ul>
<li><p>Uni USB-C to HDMI adapter to AOC 27" monitor</p></li>
<li><p>Uni USB-C to HDMI adapter to AOC 27" monitor</p></li>
</ul>
<p>I had to plug in the 2nd monitor twice as the first time it wasn’t recognized by Chrome OS. The
second time it worked fine and was available in the Display settings. I was able to set up the
monitor positioning (each 27" on one side of the PB’s internal display. This was quite a nice
experience.</p>
<p>The first thing I tried was to move an open Chrome window from my PB’s internal display to one of
the external monitors. This crashed Chrome OS and I lost my WebStorm instance which was hosting an
Angular CLI project and Firebase Functions.</p>
<p>I was able to open the Chrome window again and move the tab back to the external display. I have
read online this is a common issue with Chrome OS. However, I haven’t yet tracked down the related bug
on https://crbug.com.</p>
<p>The other issue that I ran into here, which I don’t think is restricted to external monitors, is
that Linux apps which are running in fully expanded windows don’t have their position remembered
when they restarted. This means that I have to use an extra click every time that I open an app to
make it take up the full screen.</p>
<p>These are software bugs which should be fixed. I’m not sure if the blurry scaling and lack of
sharpness in WebStorm is 100% a software problem, but it certainly needs to be addressed by either
the Chrome team or JetBrains. For now, these issues make the whole external monitor experience on
Chrome OS sub-par. It’s certainly workable but, much like tablet mode, there seems to be quite a
lot of space for improvement.</p>
<p>Some additional positive notes:</p>
<p>Letting the Pixelbook go to sleep connected to external monitors worked well. I was able to wake it
using a variety of options including an external mouse, external keyboard, and the Pixelbook’s
trackpad and keyboard. All the window positions and states were intact.</p>
<h4 id="issuewithmovingandroidappsbetweenmonitorssolved">Issue with moving Android apps between monitors - Solved</h4>
<p>When I open certain Android apps, like SWGOH, the app appears to open in the first monitor. This
happens even if you launched the app from the launcher on another display. In my case, it opens in
the left external monitor. However, I want it to open on the Pixelbook’s internal display so that
I can use the touch screen. There doesn’t appear to be a way to move a full screen app like this
from one display to another. It’s impossible to take the app out of full screen mode either via
the mouse cursor, or the full screen button on the Pixelbook. There are some
<a href="https://chromeunboxed.com/news/chromebook-shortcut-move-windows-between-displays/">articles about shortcuts for moving windows across displays</a>,
but they reference the out of date <code>Launcher+Alt+Arrow</code> shortcut.</p>
<p>The <a href="https://www.laptopmag.com/articles/snap-windows-chrome-os">shortcuts for snapping windows to the left/right half of the screen</a>
with <code>alt+[</code> or <code>alt+]</code> work for me, but that’s not what I want to do here, and they don’t work with
full screen Android apps like this.</p>
<p>Finally, I decided to open the Chrome OS shortcut search panel via <code>Launcher+Alt+/.</code> Then searching
for “move” immediately showed me the proper shortcut: <code>Launcher+Alt+m</code>. This works!</p>
<p>Like a number of functions in Chrome OS, a keyboard shortcut is the only way to access the
functionality, and the discoverability of this functionality is poor.</p>
<h4 id="morenotesonthegeneraldeveloperexperience">More notes on the general developer experience</h4>
<p>I mentioned in a day 3 that the Google Cloud Tools plugin login didn’t work due to the redirect not
being mapped between Crostini and Chrome OS. This wasn’t the case for logging in from the Firebase
CLI via <code>firebase login</code>. Everything worked smoothly there. I also tried the Google Cloud SDK via
the <code>gcloud auth login</code> command and that worked well.</p>
<p>On the Pixelbook, I always saw an accumulation of the same error in my browser console when I have
a site open in live reload (dev) mode:</p>
<pre><code class="js language-js">Unchecked runtime.lastError: The message port closed before a response was received.
</code></pre>
<p>I’m not sure what is causing this or how to solve it. However, it does not appear to be causing a
significant issue.</p>
<p>I did some performance tests with Angular CLI <code>v7.1.0</code>. Eventually, I decided to test against a
brand new <code>ng new</code> project. I used the existing project only for build times, but not reload times
as they were too funky due to the project using a number of different libraries. For comparison, I
included some numbers from my primary dev machine: a mid-2014 <code>i7 16GB RAM 256GB</code> SSD MacBook Pro.</p>
<h4 id="pixelbookperformanceinanewproject">Pixelbook Performance in a new project</h4>
<p>Time to run <code>ng serve</code>: <strong>~16s</strong></p>
<p>Time to refresh the browser on a page served via <code>ng serve</code>: <strong>~1s</strong></p>
<p>Round trip for making a change and seeing it live in the browser: <strong>~2–3s</strong></p>
<p>Production build time: <strong>~33s</strong></p>
<h4 id="pixelbookperformanceinanexistingproject">Pixelbook Performance in an existing project</h4>
<p>I had to throw out the browser refresh and round trip times here due to an issue with this project
that caused both platforms to run much slower than they should.</p>
<p>What about that production and dev build times though?</p>
<p>Production build: <strong>~3 minutes</strong></p>
<p>Dev Build: <strong>~29s</strong></p>
<p>For the production build, looking at the CPU cores in Cog, a few of the longer running tasks like
the <code>TerserPlugin</code> have significant portions that run on a single CPU. When this happened, the
other CPUs were hanging around 5–25% while one CPU was around 90–100%.</p>
<p>This was done on battery power and none of these tests really drove up the thermals in any
significant way. Everything continued to run around 105–140F.</p>
<h4 id="buildingsignificantangularjsproject">Building significant AngularJS project</h4>
<p>I also tried and AngularJS project that just uses Gulp and <code>gulp-connect</code>. In this case the build
took <strong>~22s</strong> and live reload did not work at all. On the MacBook Pro, this project builds in <strong>~17s</strong>.
This app also had the same console errors.</p>
<p>By default, the app used <code>http://localhost:35729/livereload.js?snipver=1</code> for live reload. I was
able to get <code>gulp-connect</code> livereload working using the following config:</p>
<pre><code class="json language-json">livereload: { hostname: ‘penguin.linux.test’ },
</code></pre>
<p>This did not fix the console errors, but it fixed live reload.</p>
<h4 id="macbookproperformanceinanewproject">MacBook Pro Performance in a new project</h4>
<p>I wanted to provide some comparable times for the above data points in the same project on
my 2014 MacBook Pro. These are numbers that I’m mostly fine with and would like to see equaled or improved
upon by a new laptop.</p>
<p>Time to run <code>ng serve</code>: <strong>~10s</strong></p>
<p>Time to refresh the browser on a page served via <code>ng serve</code>: <strong>~1.5s</strong></p>
<p>Round trip for making a change and seeing it live in the browser: <strong>~2–3s</strong></p>
<p>Production build time: <strong>~26s</strong></p>
<h4 id="macbookproperformanceinanexistingproject">MacBook Pro Performance in an existing project</h4>
<p>Production build: <strong>~2m 19s</strong></p>
<p>Dev Build: <strong>~26s</strong></p>
<h4 id="androidapplaunchperformance">Android App Launch Performance</h4>
<p>On Android, one of the slowest tasks that I do with apps is opening up SWGOH.</p>
<p><a href="/large-images/swgoh-load-time-chart.png"><img src="/large-images/swgoh-load-time-chart.png" alt="Load time for SWGOH" /></a></p>
<p>Here’s the data:</p>
<ul>
<li><strong>Nexus 9:</strong> ~70s</li>
<li><strong>Pixel XL:</strong> ~34s</li>
<li><strong>Pixel 3:</strong> ~21s</li>
<li><strong>Pixelbook:</strong> ~15s</li>
</ul>
<h4 id="performancesummary">Performance Summary</h4>
<p><a href="/large-images/pixelbook-macbook-pro-perf-compared-chart.png"><img src="/large-images/pixelbook-macbook-pro-perf-compared-chart.png" alt="Pixelbook vs MacBook Pro Performance (chart)" /></a></p>
<p>The Pixelbook was 10–40% slower for CPU intensive tasks like running builds. I was surprised that it
refreshed pages in dev mode approximately <strong>0.2–0.4s</strong> faster than the MacBook Pro. This may be explained by
the fact that the Pixelbook is running Chrome 71 while the MacBook Pro is running Chrome 70. Or the
Pixelbook is just slightly better tuned for running Chrome?</p>
<p>These results aren’t overly surprising. The Pixelbook is running a newer generation i7 processor,
but it’s also tuned for mobility and thermal performance in a laptop w/o fans. The Pixelbook is
also half of the price of this mid-2014 MacBook Pro.</p>
<p>Overall, performance-wise the <code>i7</code> Pixelbook packs enough punch to do web, backend, and Android
development, but it won’t blow you away with speed.</p>
<h1 id="day8powerwash">Day 8 - Powerwash</h1>
<p>One of my goals when picking up the Pixelbook <code>i7 16GB RAM 512 SSD</code> was to see if it could serve as
an effective backup development machine.</p>
<p>This is due to the fact that my mid-2014 MacBook Pro <code>i7 16GB 256GB SSD w/ Intel graphics</code> is well outside
of it’s extended Apple Care warranty. The MacBook Pro still works great and does most everything that I need.
I’ve found that the 256 GB SSD is a little too small for me, and I’ve run into cases where I wish that
I had more graphics power. That said, it has proven to be an incredibly reliable, performant, and
productive tool over the last 4.5 years. It was clearly one of my best tech purchases, ever.</p>
<h3 id="mytestinginthelastweekhasproventhatthepixelbookcanindeedfillinasanemergencybackupdevelopmentmachine">My testing in the last week has proven that the Pixelbook can indeed fill in as an emergency backup development machine.</h3>
<p>That said, there are still enough rough edges in Chrome OS and Crostini (beta) that getting things
set up properly and keeping things running over time will be too large of a drain on my
productivity. This is obviously a personal decision. If you don’t have kids and find that you have
a lot of spare time in your life, then you may make the opposite choice here.</p>
<p>Another aspect of this decision also relates to productivity. That is the speed and smoothness with
which I would be able to make the transition from a temporarily or permanently disabled primary
development machine (my MacBook Pro). While I use almost no macOS-specific apps, preferring mostly
Linux-based apps, it is still not a simple transition for me to switch my dev environment from
macOS to Linux. There are a number of contributing factors here:</p>
<ol>
<li><p>My MacBook Pro time machine backups are on a USB-A 3.x drive that my Chromebook cannot read due to the
Mac OS Extended Volume Hard Drive Format (HFS+).</p></li>
<li><p>The Pixelbook does not support Thunderbolt 2 or Thunderbolt 3. So peripherals for my MacBook Pro need
extra adapters and if I upgrade to a new MacBook Pro there will be peripherals that may not work with the
Pixelbook. This problem is especially painful when it comes to \$300+ docking stations to support
dual external monitors.</p></li>
<li><p>There are minor differences between the two systems which would cost me a good deal of time to
mitigate. These include font and resolution settings in IDEs, differences in window management
behaviors and shortcuts, differences in keyboard layouts, etc.</p></li>
</ol>
<p>I’ve seen some reviews out there about Chrome OS and the Pixel Slate. They mention the idea of a
thousand little cuts. Each one may have a work around or mitigation, but taken on a whole there
are enough of them that the total impact is significant.</p>
<p>Thankfully, most of these issues are on the software side and will be improved or resolved over
time! I feel strongly that Chrome OS has a strong future in most all markets (even development).</p>
<p>The Pixelbook is an amazing device for so many people today. It’s going to keep improving over time,
especially since it will get updates for 7 years after its launch date instead of 5 like many other
Chromebooks.</p>
<h4 id="nowthepixelbookhardware">Now the Pixelbook hardware</h4>
<p>Most of it is amazing. The keyboard and trackpad are superstars. The overall feel is very solid and
premium. I was happy with the thermal performance and quiet fan-free usage.</p>
<p>The hinge worked great for me in most all cases. It has a little more movement than I’d like when
touched in non-tablet and tent modes. Plus you need to hold down the keyboard when opening the
screen. This is a hard problem. In one case I want the hinge to be more stable and in another I
want it to open more easily.</p>
<p>I have very positive and negative opinions on the Pixelbook’s screen. The bezels are indeed
enormous, but it’s not a deal breaker for me. I much prefer the 3:2 aspect ratio over the wide
screens seen on many of laptops (Dell, etc.). This gives more vertical space for productivity
tasks like reading, writing, or coding. The screen is impressively thin. The webcam worked well
enough, but did not impress me.</p>
<blockquote>
  <p>The Pixelbook has 235 pixels per inch, and my MacBook Pro has 220 pixels per inch. The Pixelbook’s
  display has 400 nits of brightness which makes it usable outdoors. My MacBook Pro only has 320 nits of
  brightness, and it doesn’t excel outdoors. That said, new MacBook Pros have 500 nits of brightness.</p>
</blockquote>
<p>On paper, the Pixelbook’s screen is very solid. However, in practice I found that changing
resolution or scaling display output resulted in blurry or pixelated images and text. This was
likely due to Chrome OS’ Freon graphics stack, Linux apps being in beta, and Android apps not
being fully tuned to Chrome OS yet. This resulted in a display experience that I wasn’t completely
satisfied with.</p>
<h4 id="stonepeak2byintel">Stone Peak 2 by Intel</h4>
<p>The Intel Bluetooth/Wi-Fi combo chip is the primary reason that I am returning the Pixelbook. I had
many occurrences in Chrome OS 70 (Stable) of Bluetooth disconnecting and not auto reconnecting on me.</p>
<p>This device has been on the market for a year now. Lately, I’ve been waiting to buy a number of
tech products until they have been in the market for a few months. This gives me the chance to see
which products have serious flaws and which have flaws that can be addressed via software updates.
This strategy has saved me a lot of wasted time, frustration, and money in the last 4 years.</p>
<p>That said, the Pixelbook still having serious feature-breaking problems in the Stable channel after
a year is too much for me to ignore. Yes, I had better luck with Chrome 71 (Beta), but there are
numerous users who are still reporting Bluetooth issues with that build. I don’t have the luxury
of waiting to see since the return period is only 15 days. Plus I’ve already spent as much time
testing this device as I can afford.</p>
<p>Additionally, comments in the various Bluetooth
<a href="https://bugs.chromium.org/p/chromium/issues/detail?id=904571">bugs</a> in the Chrome OS issue tracker
seem to indicate that there is a hardware flaw or missing feature with the Pixelbook’s Intel Stone
Peak 2 Bluetooth/Wi-Fi chip. There is some additional discussion of this issue on
<a href="https://www.reddit.com/r/PixelBook/comments/a0om0y/progress_in_m72_for_bluetooth_issues/">Reddit</a>.</p>
<h4 id="finaldecision">Final Decision</h4>
<p>It doesn’t seem wise for me to spend \$1,700+ on a device that has an issue like this that may never
be fully fixed. Bluetooth is something that I make heavy use of, so issues with this chip could
seriously impact productivity.</p>
<p>That combined with the many little cuts to productivity, mentioned above, resulted in me making the
decision to return the Pixelbook.</p>
<h4 id="nextsteps">Next Steps</h4>
<p>If I can pick up the cheaper model on a big discount, then I would love to have a Pixelbook, but I
can’t justify keeping the top end model.</p>
<p>I will certainly continue to keep my eye on high-end Chromebooks which can be used for development.
I’m excited by the progress and goals of Crostini. Additionally, I’m also confident Android apps on
Chrome OS will continue to improve each year. I do plan to make a Chromebook my primary development
machine at some time in the future.</p>
<p>Until then, I am planning to stick with MacBook Pro devices for my primary development platform.
I’m very happy I’m able to test my web apps on Android, macOS, iOS, Windows, and Chrome OS
using a MacBook Pro. You can find out more about running Chrome OS in a VM on a MacBook Pro in
<a href="https://twitter.com/Splaktar/status/1068329287433052161">this Twitter thread</a>.</p>
<hr />
<p>If you haven’t checked it out yet, <a href="https://devfestflorida.org/">DevFest Florida</a> is happening at
Disney World’s Contemporary Resort on January 19th. The
<a href="https://devfestflorida.org/speakers/">list of speakers</a> is really impressive. Tickets for students
and professors are only $99 (plus fees) and general tickets are $175 (plus fees).</p>
<blockquote>
  <p>If you are interested, <strong>I am happy to offer readers 25% off of general ticket prices using
<a href="https://www.eventbrite.com/e/devfest-florida-orlando-tickets-48558589047?discount=PRENTICE#tickets">this link</a></strong>!
  I hope to see some of you there.</p>
</blockquote>]]></content:encoded>
            <category>chrome</category>
            <category>mac</category>
        </item>
        <item>
            <title><![CDATA[Using a Pixelbook for Angular Development]]></title>
            <link>https://devintent.com/blog/2018-11-24-using-a-pixelbook-for-angular-development.md</link>
            <guid isPermaLink="false">blog/2018-11-24-using-a-pixelbook-for-angular-development.md</guid>
            <pubDate>Sat, 24 Nov 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Step-by-step instructions for setting up WebStorm, Git, NodeJS, NVM, and Yarn for web development with Angular.]]></description>
            <content:encoded><![CDATA[<p>If you just received a new Pixelbook, congratulations! Hopefully you have had some fun with
Infinite Painter and possibly some other Android apps from Google Play.</p>
<blockquote>
  <p>Note: <em>I wrote a
<a href="https://www.devintent.com/blog/2018-11-25-my-pixelbook-dev-experience">separate, detailed post</a>
about my initial Pixelbook Developer experience.</em></p>
</blockquote>
<p>Now let’s get down to the business of getting your machine ready for some Angular development!</p>
<p><a href="/large-images/pixelbook-angular-webstorm.png"><img src="/large-images/pixelbook-angular-webstorm.png" alt="Running WebStorm and Angular on a Pixelbook" /></a></p>
<h1 id="getupdated">Get updated</h1>
<p>First, make sure you update to the latest patch by checking for an update in your status bar
(click the clock). Select the option to reboot and install the update if one exists. Ideally you
are on Chrome OS 70 or later.</p>
<p>You can check your Chrome OS version in <code>Settings-&gt;Hamburger menu-&gt;About Chrome OS</code>.</p>
<h1 id="enablelinuxappsbeta">Enable Linux Apps (beta)</h1>
<p>Go to the <a href="https://support.google.com/pixelbook/answer/9031351?hl=en">Support Page for Linux Apps</a>
and follow the instructions. In my case, there were some upgrades available from <code>apt-get</code>.</p>
<h1 id="installjava">Install Java</h1>
<p>From your Linux terminal:</p>
<pre><code class="bash language-bash">sudo apt install openjdk-8-jdk
</code></pre>
<h1 id="installwebstorm">Install WebStorm</h1>
<p>Go to the <a href="https://www.jetbrains.com/webstorm/">JetBrains WebStorm Download</a> page and click the
Download button.</p>
<p>In your Linux terminal, create a downloads folder:</p>
<pre><code class="bash language-bash">mkdir ~/downloads
</code></pre>
<p>Open the Files app.
Copy your download from <code>My files-&gt;Downloads</code> to <code>Linux files-&gt;downloads</code> via drag and drop.</p>
<p><a href="/large-images/chrome-os-webstorm-download.png"><img src="/large-images/chrome-os-webstorm-download.png" alt="Move your WebStorm download to your Linux downloads folder" /></a></p>
<p>In your Linux Terminal, extract the WebStorm archive into <code>/opt</code>:</p>
<pre><code class="bash language-bash">sudo tar xf ~/downloads/WebStorm-2018.3.tar.gz -C /opt
</code></pre>
<p>In your Linux Terminal, launch WebStorm:</p>
<pre><code class="bash language-bash">/opt/WebStorm-183.4284.130/bin/webstorm.sh
</code></pre>
<p><em>Note that your path to the WebStorm directory will be slightly different per version.</em></p>
<p>Go through the setup steps and make sure the box to create a Desktop Entry is checked (default) but
don’t check the box for All Users. Complete the wizard, give WebStorm a minute to settle, and then
close it.</p>
<h1 id="launchwebstormfromthechromeoslauncher">Launch WebStorm from the Chrome OS Launcher</h1>
<p>That last step made WebStorm available in the Linux apps directory of the Chrome OS Launcher.</p>
<p><a href="/large-images/chrome-os-linux-apps.png"><img src="/large-images/chrome-os-linux-apps.png" alt="Linux apps directory in Chrome OS Launcher" /></a></p>
<p>Launch WebStorm from the Chrome OS Launcher and repeat the setup steps other than creating a
Desktop Entry.</p>
<h1 id="setupssh">Setup SSH</h1>
<p>Now for using GitHub, you will want to <a href="https://github.com/settings/keys">setup SSH and GPG</a>. We’ll
start with SSH.</p>
<p>Follow <a href="https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/">these steps</a>
to generate a SSH public and private key for your Pixelbook. If the part about “Adding your SSH key
to the ssh-agent” is empty, scroll to the top and make sure Linux is selected. Then follow
those steps. I reported this issue to GitHub, so manually selecting Linux for Chrome OS should not
be required once they fix their <code>user-agent</code> detection.</p>
<p>Open <a href="https://github.com/settings/keys">GitHub SSH and GPG keys</a> and create a new key with the
contents of <code>id_rsa.pub.</code> You can get the contents via</p>
<pre><code class="bash language-bash">cat ~/.ssh/id_rsa.pub
</code></pre>
<p>Now back in WebStorm, you need to set up GitHub under <code>File-&gt;Settings-&gt;Version Control-&gt;GitHub</code>.
Check the box for “Clone git repositories using ssh”. Then click “Add account”.</p>
<p>Fill in your username and password. It will prompt you for your 2FA code in the next step. If that
is successful, GitHub will be configured properly.</p>
<h1 id="additionalsshagentconfigurationoptional">Additional SSH Agent Configuration (optional)</h1>
<p>If you created your SSH key with a password (recommended), then you need to make sure the SSH
Agent prompts you for your password after a reboot. There are many options available for doing this
task. We’re going to use a simple setup that uses an open source package called
<a href="https://github.com/funtoo/keychain">keychain</a>.</p>
<p>In your Linux Terminal, install keychain:</p>
<pre><code class="bash language-bash">sudo apt-get install keychain
</code></pre>
<p>Open your <code>~/.bashrc</code> file and add the following line at the end:</p>
<pre><code class="bash language-bash">eval `keychain --eval id_rsa -q`
</code></pre>
<p>This setup will prompt you for your SSH key’s passphrase only once per reboot.</p>
<p><em>Note: You can use <code>vi</code> to make this change or install something like <code>nano</code> if you prefer.
Remove the <code>-q</code> if you want keychain to print some information every time you open a shell.
This comes from a couple different sources:
<a href="https://stackoverflow.com/a/24902046/633107">StackOverflow</a>,
<a href="https://unix.stackexchange.com/a/90869/61959">Unix StackExchange</a>.</em></p>
<h1 id="setupgpg">Setup GPG</h1>
<p>Check if you already have GPG2 via</p>
<pre><code class="bash language-bash">gpg --version
</code></pre>
<p>If not, in your Linux Terminal, install GPG2:</p>
<pre><code class="bash language-bash">sudo apt-get install gpg2
</code></pre>
<p>If you have a new Pixelbook, then you can go straight to installing GPG. If your Pixelbook is not
new, then you should
<a href="https://help.github.com/articles/checking-for-existing-gpg-keys/">check if you have any existing GPG keys</a>.</p>
<p>Follow <a href="https://help.github.com/articles/generating-a-new-gpg-key/#platform-linux">these steps</a>
to generate your GPG key and export it to a format for adding to GitHub.</p>
<p>Setting up a GPG key allows GitHub to show the green “Verified” label next to the commits in your
Pull Requests.</p>
<p><a href="/large-images/github-gpg-verified.png"><img src="/large-images/github-gpg-verified.png" alt="Example of a commit signed with a verified GPG key" /></a></p>
<h1 id="clonearepositoryinwebstorm">Clone a repository in WebStorm</h1>
<p>In WebStorm, checkout a Git repository:</p>
<p><a href="/large-images/webstorm-checkout-from-version-control.png"><img src="/large-images/webstorm-checkout-from-version-control.png" alt="Checkout from Version Control menu" /></a></p>
<p>If you successfully logged into GitHub earlier, then your repositories will be available in the URL
drop down.</p>
<p><a href="/large-images/webstorm-github-repos.png"><img src="/large-images/webstorm-github-repos.png" alt="GitHub repositories listed in the URL drop down" /></a></p>
<p><em>Note that the first time you clone, it should warn you about an unknown host and allow you to add
that host and remember it.</em></p>
<p>Also make sure that you choose a directory in your home directory and not in <code>/root/</code>. It picked
<code>~/Webstorm/Projects/</code> for me.</p>
<h1 id="configurewebstorm">Configure WebStorm</h1>
<p>If you use WebStorm on another computer, you can sync your settings there and have your Pixelbook
pick those settings up easily.</p>
<p>On your Pixelbook, in the bottom right-hand corner of the screen, click on the Gear with the
question mark. Then select “Enable Sync…”</p>
<p><a href="/large-images/webstorm-sync-settings.png"><img src="/large-images/webstorm-sync-settings.png" alt="WebStorm Sync Settings menu" /></a></p>
<p>Select the option that works best for you. Then after a minute, you should be able to click on the
Gear again and either Sync your Plugins silently (e.g. install all the plugins that are on your
other computer and disable plugins that are disabled on your other computer) or choose which plugins
should be synced and which should not.</p>
<h1 id="installnodejsandnpmvianvm">Install NodeJS and NPM via NVM</h1>
<p>As described in the <a href="https://github.com/creationix/nvm#install-script">NVM docs</a>, in the Linux
Terminal run:</p>
<pre><code class="bash language-bash">curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
</code></pre>
<p>Reload your terminal to get access to NVM by running:
<code>source ~/.bashrc</code></p>
<p>Now running <code>nvm --version</code> should output <code>0.33.11</code>.</p>
<p>Install NodeJS LTS (Long Term Support) and the matching version of NPM by running:</p>
<pre><code class="bash language-bash">nvm install 10
</code></pre>
<h1 id="setupnodejsinwebstorm">Setup NodeJS in WebStorm</h1>
<p>In WebStorm, open <code>File-&gt;Settings-&gt;Languages and Frameworks-&gt;Node.js and NPM</code>. Node and NPM should
be automatically detected. Check the box for “Coding assistance for Node.js” and press OK.</p>
<p><a href="/large-images/webstorm-nodejs-npm-config.png"><img src="/large-images/webstorm-nodejs-npm-config.png" alt="NodeJS and NPM configuration in WebStorm" /></a></p>
<p>Now restart WebStorm so that it can initialize some more NPM features. When WebStorm opens again, you should see a popup where you can have the IDE run <code>npm install</code> for you.</p>
<p><a href="/large-images/webstorm-prompt-npm-install.png"><img src="/large-images/webstorm-prompt-npm-install.png" alt="WebStorm prompt to run npm install" /></a></p>
<h1 id="runanpmscript">Run a NPM Script</h1>
<p>WebStorm makes it easy for you to open your <code>package.json</code> file and run one of the scripts provided
by the repository.</p>
<p><a href="/large-images/webstorm-run-npm-scripts.png"><img src="/large-images/webstorm-run-npm-scripts.png" alt="The green arrows next to each script can be clicked to start running or debugging" /></a></p>
<h1 id="installyarn">Install Yarn</h1>
<p>Many Angular projects now require Yarn.</p>
<p>The easy way is to do <code>npm i -g yarn</code>, but you can also use the following steps taken from the
<a href="https://yarnpkg.com/lang/en/docs/install/#debian-stable">Yarn Install docs for Debian</a>:</p>
<p>Add Yarn’s public GPG key and repository to Debian’s package manager by running the following in
your Linux Terminal:</p>
<pre><code class="bash language-bash">curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
</code></pre>
<p>In your Linux Terminal, install yarn:</p>
<pre><code class="bash language-bash">sudo apt-get update &amp;&amp; sudo apt-get install --no-install-recommends yarn
</code></pre>
<p>Check the installation was successful by running <code>yarn --version</code> which should output a version
similar to <code>1.12.3</code>.</p>
<p>Similar to above, WebStorm will prompt you to run <code>yarn install</code> when you open a new project that
uses Yarn.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Please note that the steps above for WebStorm are nearly identical if you are installing IntelliJ
IDEA or many of the other JetBrains IDEs.</p>
<p>I hope that this post is useful to some intrepid developers who are ready to get productive with
their Pixelbooks! Please leave comments if you run into any issues or if something doesn’t work,
and I will try to update this post.</p>
<hr />
<p>If you haven’t checked it out yet, <a href="https://devfestflorida.org/">DevFest Florida</a> is happening at
Disney World’s Contemporary Resort on January 19th. The
<a href="https://devfestflorida.org/speakers/">list of speakers</a> is really impressive. Tickets for students
and professors are only $99 (plus fees) and general tickets are $175 (plus fees).</p>
<blockquote>
  <p>If you are interested, <strong>I am happy to offer readers 25% off of general ticket prices using
<a href="https://www.eventbrite.com/e/devfest-florida-orlando-tickets-48558589047?discount=PRENTICE#tickets">this link</a></strong>!
  I hope to see some of you there.</p>
</blockquote>
<hr />
<h1 id="references">References</h1>
<p>Some information for this post was taken from the helpful
<a href="https://www.reddit.com/r/Crostini/">Crostini community on Reddit</a>.</p>
<p>I was also able to get Gimp 2.10.x installed thanks to the
<a href="https://www.reddit.com/r/chromeos/comments/988zw8/quick_question_how_to_add_gimp/">ChromeOS community on Reddit</a>.</p>]]></content:encoded>
            <category>chrome</category>
            <category>angular</category>
            <category>webstorm</category>
        </item>
        <item>
            <title><![CDATA[Using a Pixelbook with a docking station and extended monitors]]></title>
            <link>https://devintent.com/blog/2018-11-18-using-a-pixelbook-with-a-docking-station-and-extended-monitors.md</link>
            <guid isPermaLink="false">blog/2018-11-18-using-a-pixelbook-with-a-docking-station-and-extended-monitors.md</guid>
            <pubDate>Sun, 18 Nov 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Research and discussions of using a docking station with a Google Pixelbook.]]></description>
            <content:encoded><![CDATA[<p>I have a new <a href="https://store.google.com/product/google_pixelbook">Google Pixelbook</a> on the way, and
I’m trying to figure out my docking station solution.</p>
<p><a href="/large-images/pixelbook-usbc.jpg"><img src="/large-images/pixelbook-usbc.jpg" alt="Google Pixelbook" /></a></p>
<p><a href="https://support.google.com/pixelbook/forum/AAAASyb5yQ4JmN5Lh97N0o">This old, locked support forum post</a>
mentions the <a href="http://a.co/d/8hXVQmz">Dell D6000 dock</a> which people have had some luck with. There
appears to be an issue where the dock will lose connection with the monitors every couple of hours.
This seems to be commonly reported by users of Dell docks (across reviews of many of their existing
USB-C docks). I’m not sure if any of those posters using the D6000 were able to solve this issue
or not.</p>
<p><a href="https://kmyers.me/blog/computers/the-ultimate-chromebook-pixelbook-desk-setup/">Keith Meyers’ blog</a>
mentions successfully using the Pixelbook along with the
<a href="https://amzn.to/2GSi09X">Plugable USB 3.0 Universal Laptop Docking Station</a>. This is a dock from 2013.</p>
<p>The <a href="http://a.co/d/9DRgz6K">Plugable USB-C 4K Triple Display Docking Station with Charging Support</a>
is from 2017 and has 4K@60fps support via DisplayPort. It also supports charging the Pixelbook.</p>
<p>In the Q&amp;A, the Plugable states that the Pixelbook is fully supported. However, I’d like to hear from
the community whether you were able to get this dock working and if you ran into any
issues.</p>
<p>Another interesting option is the <a href="http://a.co/d/1mz0YaV">CalDigit USB-C Docking Station</a>. It only
supports two monitors, but that is sufficient for me. For two monitors, you need to use
<a href="https://blog.startech.com/post/connecting-multiple-monitors-multi-stream-transport-and-what-it-means-for-you/">DisplayPort Multi-Stream Transport</a>
which Chrome OS added support for in the Spring of 2018. This means that the DisplayPort port would
drive both monitors, and the HDMI port would be unused. Since my monitors are HDMI, I would need to
use a MST Hub to split the signal and then DP-&gt;HDMI adapters.</p>
<p>This CalDigit setup seems a bit involved and possibly slightly risky. I’d love to know if
anyone has gotten it to work this year.</p>
<p>Are you using another dock that you’ve found works great for you? Please let me know.</p>]]></content:encoded>
            <category>chrome</category>
        </item>
        <item>
            <title><![CDATA[Announcing the AngularJS Material v1.1.10 Release]]></title>
            <link>https://devintent.com/blog/2018-06-28-announcing-the-angularjs-material-v1-1-10-release.md</link>
            <guid isPermaLink="false">blog/2018-06-28-announcing-the-angularjs-material-v1-1-10-release.md</guid>
            <pubDate>Sat, 22 Dec 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Information about the AngularJS Material v1.1.10 Release.]]></description>
            <content:encoded><![CDATA[<p>We have released AngularJS Material <code>v1.1.10</code>.</p>
<p>This release is now available in our
<a href="https://material.angularjs.org/latest/"><strong>Online Documentation</strong></a>, <a href="https://www.npmjs.com/package/angular-material"><strong>NPM</strong></a>,
and Bower. It is also available on the Google CDN (<a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.10/angular-material.min.js"><strong>JS</strong></a>, <a href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.10/angular-material.min.css"><strong>CSS</strong></a>).</p>
<p>You can find the details for all releases in our
<a href="https://github.com/angular/material/blob/master/CHANGELOG.md"><strong>Change Log</strong></a>.</p>
<h1 id="highlights">Highlights</h1>
<p><code>v1.1.10</code> should be our most stable release in many months. Here are some highlights:</p>
<ul>
<li><p>Fixed four significant regressions to chips that were introduced in 1.1.2 and 1.1.9. Two of these were also a11y issues.</p></li>
<li><p>Fixed a memory leak when elements using <code>md-theme</code> are removed from the page</p></li>
<li><p>Fixed select to support selecting options by typing when the option contains a period (i.e. <code>255.255</code>)</p></li>
<li><p>Improved dark mode theme support for menu-bar and datepicker</p></li>
<li><p>Fixed ripple animations getting stuck on iOS in certain situations</p></li>
<li><p>Fixed a couple layout issues</p></li>
<li><p>Significant improvements to the project’s documentation including 3 new demos</p></li>
</ul>
<p><a href="/angularjs-material/md-calendar.png"><img src="/angularjs-material/md-calendar.png" alt="New Calendar Demo" /></a></p>
<p><a href="/angularjs-material/md-datepicker-moment.png"><img src="/angularjs-material/md-datepicker-moment.png" alt="Moment.js Datepicker Demo" /></a></p>
<p>This is a patch release with non-breaking changes (fixes and enhancements).</p>
<h1 id="bugfixes">Bug Fixes</h1>
<ul>
<li><p><strong>chips</strong>: editable chip gets removed after editing</p></li>
<li><p><strong>chips</strong>: improve ability to receive focus on click</p></li>
<li><p><strong>chips</strong>: regression where chips model gets out of sync with view</p></li>
<li><p><strong>chips</strong>: unwanted re-focus of last chip after blur</p></li>
<li><p><strong>compiler</strong>: remove dependency on AngularJS private API</p></li>
<li><p><strong>datepicker</strong>: calendar panel theme supports dark mode in multi theme scenario</p></li>
<li><p><strong>layout</strong>: allow flex-offset to be a child of layout-margin</p></li>
<li><p><strong>layout</strong>: reduce layout CSS size by reverting some of <a href="https://github.com/angular/material/issues/11247">#11247</a></p></li>
<li><p><strong>menu-bar</strong>: <code>md-menu-bar</code> panel theme supports dark mode themes</p></li>
<li><p><strong>nav-bar</strong>: missing <code>[disabled]</code> scss selector</p></li>
<li><p><strong>ripple</strong>: fix iOS Safari stuck ripple issue</p></li>
<li><p><strong>select</strong>: doesn’t search correctly when pressing period character</p></li>
<li><p><strong>theming</strong>: <code>md-theme</code> leaks when child elements are removed</p></li>
</ul>
<h1 id="features">Features</h1>
<ul>
<li><strong>mdMaxlength</strong>: support use with required and <code>ng-trim</code></li>
</ul>
<h1 id="documentation">Documentation</h1>
<ul>
<li><p><strong>datepicker</strong>: fix typos, general clean up, add <a href="https://material.angularjs.org/latest/demo/datepicker#calendar">calendar demo</a>, add <a href="https://material.angularjs.org/latest/demo/datepicker#moment">moment.js demos</a></p></li>
<li><p><strong>dateLocaleProvider</strong>: add missing documentation for <code>isDateComplete()</code> and <code>longDateFormatter()</code></p></li>
<li><p><strong>virtual-repeat</strong>: fix typos, clean up, and clarifications</p></li>
<li><p><strong>tabs</strong>: add link to tab docs, clarify the notes about nav-bar</p></li>
<li><p><strong>select</strong>: clarify the behavior of the multiple attribute</p></li>
</ul>
<h1 id="contributors">Contributors</h1>
<p><strong>Thank you</strong> to the
<a href="https://github.com/angular/material/blob/master/CHANGELOG.md#contributors-1">contributors</a>,
especially the first timers, who helped with the v1.1.10 release:</p>
<p><a href="/angularjs-material/1-1-10-contributors.png"><img src="/angularjs-material/1-1-10-contributors.png" alt="AngularJS Material v1.1.10 Contributors" /></a></p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Eye Tracking Study finds problems with Flat UIs]]></title>
            <link>https://devintent.com/blog/2018-03-28-eye-tracking-study-finds-problems-with-flat-uis.md</link>
            <guid isPermaLink="false">blog/2018-03-28-eye-tracking-study-finds-problems-with-flat-uis.md</guid>
            <pubDate>Wed, 28 Mar 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Discussion of how an eye tracking study's results apply to Material Design.]]></description>
            <content:encoded><![CDATA[<p>You may have read about a
<a href="https://www.nngroup.com/articles/flat-ui-less-attention-cause-uncertainty/">recent study</a>
that came out in early September 2017 by the Nielsen Norman Group. It had a headline grabbing title
about how Flat UI designs cause uncertainty in users. The headline alone had product managers
questioning their designers and developers.</p>
<p>However, if you read deeper into the article, you’ll find that the eye tracking research actually
confirmed the importance of a number of key UI design guidelines.</p>
<p>If you are building user interfaces and you haven’t embraced the acronym
<a href="https://www.dailyblogtips.com/crapthe-four-principles-of-sound-design/"><strong>CRAP</strong></a> yet, then I
highly recommend that you look into it.</p>
<p>It stands for <strong>Contrast</strong>…. your important, interactive UI elements need to stand out.</p>
<p><strong>Repetition…</strong> consistent UI patterns train user’s brains where to look.</p>
<p>Then you build a clear visual hierarchy through the use of <strong>Alignment</strong> and <strong>Proximity</strong>.
This includes intelligent use of negative space (or whitespace) along with grouping items that
belong together near each other.</p>
<p>This study hits on a key human factors issue. Complex, high density user interfaces cause users
uncertainty and delay their ability to take action.</p>
<p>Now let’s take a look at some details of the study and how Material Design is already built to address
these challenges.</p>
<h1 id="flatuivsmaterialdesign">“Flat UI” vs Material Design</h1>
<p><a href="/large-images/flat-ui-example.png"><img src="/large-images/flat-ui-example.png" alt="Example Image" /></a></p>
<p>On the left, we see a traditional link with the blue color and underline. The right side shows an
example of an ultra-flat UI where positioning is the only signifier that the element may be interactive.</p>
<p>The eye tracking results showed that users of the flat design would try to click on the header first
and often ignore the flat button completely because it’s click ability signifiers were too weak.</p>
<p><a href="/large-images/flat-button-example.png"><img src="/large-images/flat-button-example.png" alt="Example Image" /></a></p>
<p>Material Design provides a number of different button types to address this type of situation. First
there is the flat button. It stands out through the use of a contrast color in addition to
capitalization. However, these buttons are not designed to be used for your more important actions.</p>
<p><a href="/large-images/raised-button-example.png"><img src="/large-images/raised-button-example.png" alt="Example Image" /></a></p>
<p>In this case, taking the user to your pearl storefront is a primary action.</p>
<p>Material Design provides raised buttons for the cases where you want a strong click ability signifier,
and the user’s gaze to be attracted by the color and height of the button.</p>
<p>In my next post, I’ll discuss the basic concepts of Material Design and try to distill the
marketing and design language into something that a developer can make sense of.</p>
<p>If you don’t want to wait, you can start reading the
<a href="https://material.io/design">Material Design Specifications</a> now.</p>]]></content:encoded>
            <category>material-design</category>
        </item>
        <item>
            <title><![CDATA[AngularFire2 5.0.0-rc.6 Released]]></title>
            <link>https://devintent.com/blog/2018-01-28-angularfire2-5-0-0-rc-6-released.md</link>
            <guid isPermaLink="false">blog/2018-01-28-angularfire2-5-0-0-rc-6-released.md</guid>
            <pubDate>Sun, 28 Jan 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Details about the AngularFire2 5.0.0-rc.6 release.]]></description>
            <content:encoded><![CDATA[<p>AngularFire2 has released <code>5.0.0-rc.6</code> for apps built with Angular.</p>
<p>This release brings support for the typing changes in Firebase <a href="https://github.com/firebase/firebase-js-sdk">JS SDK</a> 4.8.1+ and much awaited support for Firebase <a href="https://firebase.google.com/docs/storage/">Cloud Storage</a>!</p>
<p><img src="/icons/firebase-storage-icon.png" alt="Firebase Cloud Storage Icon" /></p>
<p>Many thanks to <a href="https://twitter.com/_davideast">@_davideast</a>, <a href="https://twitter.com/jamesuriah">@jamesuriah</a>, and a number of community contributors for helping get this update out!</p>
<p><a href="/large-images/angular-fire-5-0-0-rc-6-changelog.png"><img src="/large-images/angular-fire-5-0-0-rc-6-changelog.png" alt="AngularFire2 5.0.0-rc.6 Changelog" /></a></p>
<p>Full changelog <a href="https://github.com/angular/angularfire2/blob/master/CHANGELOG.md#500-rc6-2018-01-26"><strong>here</strong></a>.</p>
<h1 id="troubleshooting">Troubleshooting</h1>
<p>If you run into an issue using Phone Auth due to the types of <code>firebase.app.App</code> and <code>FirebaseApp</code> no longer agreeing like this:</p>
<pre><code class="ts language-ts">ERROR in src/app/auth/auth.component.ts(67,5): error TS2345: Argument of type 'FirebaseApp' is not assignable to parameter of type 'App'.
  Types of property 'auth' are incompatible.
    Type '() =&gt; FirebaseAuth' is not assignable to type '() =&gt; Auth'.
      Type 'FirebaseAuth' is not assignable to type 'Auth'.
        Types of property 'app' are incompatible.
          Type 'FirebaseApp' is not assignable to type 'App'.
            Types of property 'auth' are incompatible.
              Type '() =&gt; FirebaseAuth' is not assignable to type '() =&gt; Auth'.
                Type 'FirebaseAuth' is not assignable to type 'Auth'.
</code></pre>
<h4 id="thenyoucansolvetheissuebythefollowingsteps">Then you can solve the issue by the following steps</h4>
<p>Add the new <code>@firebase</code> packages to your <code>package.json</code>:</p>
<pre><code class="json language-json">"@firebase/app": "0.1.7",
"@firebase/auth": "0.3.2",
</code></pre>
<p>Change your <code>firebase</code> import</p>
<pre><code class="ts language-ts">import * as firebase from 'firebase/app';
</code></pre>
<p>to use the new format (with the default export syntax)</p>
<pre><code class="ts language-ts">import firebase from '@firebase/app';
</code></pre>
<p>This may then spit out the following error</p>
<pre><code class="ts language-ts">error TS2503: Cannot find namespace 'firebase'.
</code></pre>
<p>For me, this was caused by setting the following type</p>
<pre><code class="ts language-ts">phoneRecaptchaVerifier: firebase.auth.RecaptchaVerifier;
</code></pre>
<p>You can solve this by using the new <code>@firebase/auth-types</code> package</p>
<pre><code class="ts language-ts">import { RecaptchaVerifier } from '@firebase/auth-types';
</code></pre>
<p>Then just remove the <code>firebase.auth.</code> so that you have the cleaner version</p>
<pre><code class="ts language-ts">phoneRecaptchaVerifier: RecaptchaVerifier;
</code></pre>
<p>Note: when calling a constructor like <code>new firebase.auth.RecaptchaVerifier</code>(), you’ll still need the
<code>firebase.auth.</code> prefix.</p>]]></content:encoded>
            <category>firebase</category>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Why are Angular Material styles duplicated in my project?]]></title>
            <link>https://devintent.com/blog/2017-10-04-why-are-angular-material-styles-duplicated-in-my-project.md</link>
            <guid isPermaLink="false">blog/2017-10-04-why-are-angular-material-styles-duplicated-in-my-project.md</guid>
            <pubDate>Wed, 04 Oct 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[Instructions for troubleshooting duplication of styles caused by theming configuration.]]></description>
            <content:encoded><![CDATA[<p>This article assumes that you are using SCSS with the <a href="https://cli.angular.io/">Angular CLI</a>.</p>
<p><a href="/large-images/material-design-layers-logo.png"><img src="/large-images/material-design-layers-logo.png" alt="Material Design logo" /></a></p>
<h4 id="whatdotheseduplicatedstyleslooklike">What do these duplicated styles look like?</h4>
<p><a href="/large-images/angular-material-duplicate-styles.png"><img src="/large-images/angular-material-duplicate-styles.png" alt="Duplicate Angular Material Styles" /></a></p>
<p>You can see the <code>.mat-toolbar.mat-primary</code> style at the top. Then you can see it down below once
more. This time with the same exact styles (<code>background</code>, <code>color</code>) and values, but all of them
overridden.</p>
<p>In this example, there is only 1 duplicate set of styles, but it is very easy to
suddenly see 3 duplicate sets or 5 or more! As you might imagine, this can significantly impact your
bundle size in addition to complicating the styling of your app.</p>
<p>Now show some examples to showcase how easy it is to get into this situation…</p>
<h4 id="fromtheangularmaterialthemingguidehttpsmaterialangularioguidetheming">From the <a href="https://material.angular.io/guide/theming">Angular Material Theming Guide</a></h4>
<p>A typical theme file will look something like this:</p>
<p><strong>styles.scss</strong>:</p>
<pre><code class="scss language-scss">@import '~@angular/material/theming';
// Plus imports for other components in your app.

// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat-core();

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue.
$candy-app-primary: mat-palette($mat-indigo);
$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);

// The warn palette is optional (defaults to red).
$candy-app-warn: mat-palette($mat-red);

// Create the theme object (a Sass map containing all of the palettes).
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include angular-material-theme($candy-app-theme);
</code></pre>
<p>Now if this is all you do, you won’t run into problems, even if you ignore most of the comments.</p>
<p>However, we all know that real production apps need to integrate this code into a much more complex
system. For instance, the full Angular Material theme may not be included in the App Shell (used to
quickly paint the screen and let users on low bandwidth devices know that your app is bootstrapping).</p>
<p>In this article, we’ll use <a href="https://angular.io">https://angular.io</a> and its code as an example since
many developers look at this <a href="https://github.com/angular/angular/tree/4.4.4/aio">AIO repo</a> and copy
the code from it into their own apps.</p>
<p><strong>ng-io-theme.scss</strong>:</p>
<pre><code class="scss language-scss">@import '~@angular/material/theming';
// Plus imports for other components in your app.

// Include the base styles for Angular Material core. We include this here so that you only
// have to load a single css file for Angular Material in your app.
@include mat-core();

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue.
$ng-io-primary: mat-palette($mat-blue, 700, 600, 800);
$ng-io-accent: mat-palette($mat-red, 700, 600, 800);

// The warn palette is optional (defaults to red).
$ng-io-warn: mat-palette($mat-red);

// Create the theme object (a Sass map containing all of the palettes).
$ng-io-theme: mat-light-theme($ng-io-primary, $ng-io-accent, $ng-io-warn);

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include angular-material-theme($ng-io-theme);
</code></pre>
<p>There’s a very important comment that has been removed from this version.
<code>// *Be sure that you only ever include this mixin once!*</code></p>
<p>Now if you miss that, and you use some other examples like the following, you may start to see
duplicate styles and even need to resort to <code>!important</code> on many of your styles that target Angular
Material classes like <code>.mat-form-field</code> or <code>.mat-raised-button</code>.</p>
<p>I have run into apps with these issues, and it has resulted in 500 kB to 1.5 MB of bloat in the
developer build of the site. In production builds the impact is smaller, but every kB counts when
shooting for great <a href="https://www.webpagetest.org/">WebPageTest</a> or
<a href="https://developers.google.com/web/tools/lighthouse/">Lighthouse</a> scores!</p>
<p><strong>main.scss</strong>:</p>
<pre><code class="scss language-scss">// import global themes
@import '~@angular/material/theming';
@import './ng-io-theme';

// import global variables
@import './constants';

// import global mixins
@import './mixins';

// import directories
@import './0-base/base-dir';
@import './1-layouts/layouts-dir';
@import './2-modules/modules-dir';
</code></pre>
<p>You can see here that <code>main.scss</code> is including <code>ng-io-theme.scss</code> which includes <code>@include mat-core();</code>.</p>
<p><strong>styles.scss</strong>:</p>
<pre><code class="scss language-scss">/* You can add global styles to this file, and also import other style files */
@import './styles/ng-io-theme';
@import './styles/main.scss';
</code></pre>
<p>You can see here that <code>styles.scss</code> is including <code>ng-io-theme.scss</code> as well. Then including
<code>main.scss</code> which also includes <code>@include mat-core();</code>. There is another include here that is
getting duplicated as well, <code>@include angular-material-theme($ng-io-theme);</code>.</p>
<p>The AIO repo uses considerably more (custom scripts, rollup, etc.) than just the Angular CLI to
bundle and deploy their application. I wasn’t able to determine exactly how they avoid duplicate
Angular Material styles with this setup, but I did verify that there are not any duplicate Angular
Material styles on the production site.</p>
<h4 id="howshouldidothisinmyapp">How should I do this in my app?</h4>
<p>You probably want to stick closer to the Angular CLI only approach for your own apps as long as you
can. So I’ll provide an example to use in that case.</p>
<p><strong>styles.scss</strong>:</p>
<pre><code class="scss language-scss">@import './styles/theme';

// Include the base styles for Angular Material core. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat-core();

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component that you are using.
@include angular-material-theme($app-theme);

html {
...
</code></pre>
<p>This is the <code>src/styles.scss</code> file found in Angular CLI projects with SCSS enabled.</p>
<ul>
<li><p>Styles in this file are applied globally without any <code>ViewEncapsulation</code>.</p></li>
<li><p>This file is included in your app only once via the <code>.angular-cli.json</code> file via
<code>“styles”: [“styles.scss”]</code>.</p></li>
<li><p>You should not import this file into any other SCSS file.</p></li>
<li><p>The Angular Material <code>@include</code> statements should be in this file.</p></li>
</ul>
<p><strong>Note:</strong> If you are using an App Shell for your app, the Angular Material <code>@include</code> statements
are probably in another file. Just make sure that it is only included once.</p>
<p>However, this file is free to include other SCSS files like your <code>src/styles/_theme.scss</code> found below</p>
<p><strong>_theme.scss</strong>:</p>
<pre><code class="scss language-scss">@import '~@angular/material/theming';

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker hue.
$app-primary: mat-palette($mat-teal, 700, 100, 900);
$app-accent: mat-palette($mat-orange);

// The warn palette is optional (defaults to red).
$app-warn: mat-palette($mat-red);

// Create the theme object (a Sass map containing all of the palettes).
$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn);
</code></pre>
<p>In this file we define the <code>$app-theme</code> variable that is later used in <code>src/styles.scss</code>.</p>
<p><strong>Note:</strong> We’re using a feature of SCSS here that is called “Partials”. You can find out more about
them in <a href="https://stackoverflow.com/a/25251042/633107">this StackOverflow answer</a> or in
<a href="http://sass-lang.com/guide">the official SASS docs</a>. Note that the <code>_</code> in the filename is very
important here and changes the behavior of SASS.</p>
<p>Now this file can be imported in many places in your app to give you access to variables like
<code>$app-accent</code> for use in a statement like the following without duplicating styles.</p>
<p><strong>app.component.scss</strong>:</p>
<pre><code class="scss language-scss">@import '../../styles/theme';

.noRecordsContainer {
  padding: 48px;
  background-color: mat-color($app-accent, 50);
  width: 100%;
}

.errorMessageContainer {
  padding: 48px;
  background-color: mat-color($app-warn, 50);
  width: 100%;
}
</code></pre>
<p>This lets you use your Material Design palette in your custom components. In this case, we’re using
the lightest accent color (<code>50</code>) as the background of the container which provides a message about
the empty search result set. We’re also using the lightest accent color of the warn palette as the
background color of our error panel.</p>
<p>These are just two very simple examples of the powerful capabilities of using SCSS along with the
Angular Material Theming system. Find our more in their
<a href="https://material.angular.io/guide/theming-your-components">guide to theming your own components</a>.</p>
<h4 id="summary">Summary</h4>
<ul>
<li><p>Be careful of how you set up SCSS in your Angular Material and Angular CLI project. It can lead to
bloat and styling complications.</p></li>
<li><p>Follow the architecture above to eliminate duplicate styles if you have them</p></li>
<li><p>Brush up on the <a href="http://sass-lang.com/guide">basics of SASS</a> and the capabilities of the
<a href="https://material.angular.io/guide/theming-your-components">Angular Material Theming system</a></p></li>
<li><p>Keep leveraging these great tools to build amazing high performance web applications with solid UX!</p></li>
</ul>
<p>I hope that you find this helpful. If you would like to see more Angular Material content, please
let me know.</p>
<p>There will be some great presentations next week (Oct 10–12th) at
<a href="https://angularmix.com">AngularMix</a> in Orlando, FL USA. I’ll be presenting
“Delight your Organization with <a href="https://material.io/guidelines/material-design/">Material Design</a>”
on 10/12. There will be many other talks including Angular’s new Component Dev Kit (CDK), which
Angular Material leverages, and Angular CLI’s new DevKit and schematics.</p>
<p>Tickets are still available, and you can get \$100 off with the code <code>MIXPRENTICE</code>! They include an
after party at the Wizarding World of Harry Potter in Universal Studios Orlando. I hope to see you
there!</p>]]></content:encoded>
            <category>angular-material</category>
            <category>material-design</category>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Angular v4 Final and Angular CLI v1 Final Released!]]></title>
            <link>https://devintent.com/blog/2017-03-24-angular-v4-final-and-angular-cli-v1-final-released.md</link>
            <guid isPermaLink="false">blog/2017-03-24-angular-v4-final-and-angular-cli-v1-final-released.md</guid>
            <pubDate>Fri, 24 Mar 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[Details about the Angular v4 and CLI v1 Final releases.]]></description>
            <content:encoded><![CDATA[<blockquote class="twitter-tweet"><p lang="en" dir="ltr"><a href="https://twitter.com/hashtag/Angular?src=hash&amp;ref_src=twsrc%5Etfw">#Angular</a> v4 upgrade in one Tweet. Only missing the updates to package.json versions. <a href="https://t.co/BlxP6VBu6B">https://t.co/BlxP6VBu6B</a></p>&mdash; Michael Prentice (@Splaktar) <a href="https://twitter.com/Splaktar/status/845156888203313152?ref_src=twsrc%5Etfw">March 24, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Update app.module.ts:<br>import {BrowserAnimationsModule} from &#39;@angular/platform-browser/animations&#39;;<br>imports: [BrowserAnimationsModule, ...]</p>&mdash; Michael Prentice (@Splaktar) <a href="https://twitter.com/Splaktar/status/845156623479824384?ref_src=twsrc%5Etfw">March 24, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>For most projects not using Angular Universal, it’s just that easy to upgrade from Angular v2 to Angular v4!</p>
<p>The <a href="http://angularjs.blogspot.com/2017/03/angular-400-now-available.html">blog post announcing the release</a> contains details on the new features, performance improvements, and the upgrade path.</p>
<h4 id="torecapthemajorfeatures">To recap the major features</h4>
<ul>
<li><p>Animations pulled out of core for performance, separation of concerns</p></li>
<li><p>*ngIf supports and else syntax</p></li>
<li><p>*ngFor supports an as syntax to assign local variables</p></li>
<li><p>Angular Universal is now officially part of Angular core</p></li>
<li><p>TypeScript 2.1+ support</p></li>
<li><p>Improved template error messages</p></li>
</ul>
<h1 id="angularcliv1">Angular CLI v1</h1>
<p>Thankfully the Angular CLI update from 1.0.0 RCs to 1.0.0 final is also quite straightforward. The <a href="https://github.com/angular/angular-cli/blob/master/CHANGELOG.md">changelog for the updates</a> is useful reading, but what you really need is their excellent <a href="https://github.com/angular/angular-cli/wiki/stories-1.0-update">migration guide</a>!</p>
<p>Obviously if you are using the CLI, then the migration guide is where you should start. It will handle everything you need regarding upgrading both the CLI and Angular.</p>
<p><a href="/large-images/angular-cli-promo.png"><img src="/large-images/angular-cli-promo.png" alt="Angular CLI Example" /></a></p>
<h1 id="troubleshooting">Troubleshooting</h1>
<p>If you do run into issues with your upgrade, then this interactive <a href="https://angular-update-guide.firebaseapp.com/">Angular Upgrade Guide</a> may help you. Note that this guide is just getting started and will improve over time.</p>
<p>If you see warnings about typing checking being required when linting via the CLI, just update your link command to the following:</p>
<pre><code class="json language-json">"lint": "ng lint --type-check"
</code></pre>
<p>I also ran into issues with the CLI’s production builds due to template validation.</p>
<ul>
<li><p>One issue was regarding static variables in my components. Using these in templates results in an error that the property does not exist. I converted those variables to nonstatic as a temporary work around.</p></li>
<li><p>The other was related to checking that a string variable in an object was defined inside of <code>*ngFor</code>. This threw a very confusing template error (with the wrong line number). I was able to work around this by moving the checks into the component and assigning the result to a <code>boolean</code> which was then used in the template.</p></li>
</ul>
<pre><code class="ts language-ts">Type 'string' is not assignable to type 'boolean'
</code></pre>
<p>I’m waiting for some feedback before opening bugs for these last two issues.</p>
<p>If you run into issues not found in these guides, please <a href="http://stackoverflow.com/questions/tagged/angular2+angular-cli">post a question to StackOverflow</a>.</p>]]></content:encoded>
            <category>angular-cli</category>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[What’s the state of Angular Universal and AOT?]]></title>
            <link>https://devintent.com/blog/2016-12-20-state-of-angular-universal-and-aot.md</link>
            <guid isPermaLink="false">blog/2016-12-20-state-of-angular-universal-and-aot.md</guid>
            <pubDate>Tue, 20 Dec 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[The state of Angular Universal and AOT as of the end of 2016.]]></description>
            <content:encoded><![CDATA[<p>I’ve spent a good deal of the last week looking at
<a href="https://github.com/angular/universal">Angular Universal</a> and Ahead of Time (AOT) compilation.
Until now, I had been waiting to dig into them because it was clear they were still in the
experimental/alpha stages.</p>
<p>However, I decided that I want to update the <a href="https://www.devintent.com">DevIntent website</a> from
Angular <code>1.5.7</code> to the latest version of Angular over the Christmas break!</p>
<p>Since this is a marketing website, I need it to be super fast, especially on mobile, and have
excellent SEO! I’m also using this as a testing ground for some work on an upcoming client project.</p>
<h1 id="currentwebsitestatus">Current website status</h1>
<p><i>Times listed for No throttling / Regular 3G.</i></p>
<ul>
<li><p>36 requests</p></li>
<li><p>1.2 MB</p></li>
<li><p>459ms / 3760ms DOMContentLoaded</p></li>
<li><p>920ms / 13850ms Load</p></li>
</ul>
<p>This is fairly typical of a smaller Angular 1.5.x application that is using a few libraries
(Angular Material, Font Awesome, etc.) and is hosted on Firebase Hosting. It’s fine on desktop with
broadband internet, but <strong>not good enough on a mobile 3G device</strong>.</p>
<h1 id="bustouttheangularcli">Bust out the Angular-CLI</h1>
<p>My first choice is generally the Angular-CLI because I believe in what they are doing to make Angular
more approachable to new users. I use it as much as I can so that I can provide feedback, open bug
reports, and even submit PRs.</p>
<p>The first step was to see if Universal and AOT was working yet in the CLI. I found that they were
both working, just not together. The Angular-CLI <a href="https://github.com/angular/angular-cli/issues/1050">does not support</a>
Angular Universal. It does support AOT, but there are around
<a href="https://github.com/angular/angular-cli/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20aot%20">63 open issues</a>
related to AOT.</p>
<p>There is a <a href="https://github.com/devCrossNet/angular-cli">separate fork</a> for a version of the CLI that
supports Universal, but it <a href="https://github.com/devCrossNet/angular-cli/issues/13">doesn’t support AOT</a>.
It appears that they created this fork because the Angular-CLI team didn’t have the resources to
support Universal.</p>
<h1 id="graboneofthehotseedprojects">Grab one of the hot seed projects</h1>
<p>From the latest presentations that I’ve seen at conferences, I knew that there were a number of great
Angular seeds out there.</p>
<p>The first one I looked at was <a href="https://github.com/mgechev/angular-seed">angular-seed</a> from
Minko Gechev. It is really well-known, has 3,344+ stars, and supports AOT, Docker, etc. Unfortunately
it doesn’t support <a href="https://github.com/mgechev/angular-seed/issues/1566">Angular Universal</a> or
<a href="https://github.com/mgechev/angular-seed/issues/1552">Webpack</a>. After using Webpack with the
Angular-CLI, I decided that I don’t want to use another bundler in my non-Angular-CLI projects.</p>
<p>I checked into <a href="https://github.com/angular/universal-starter">Universal Starter</a> from the Angular
Universal team. It uses Webpack and has basic support for AOT. But it is really minimal and doesn’t
include <a href="https://github.com/angular/universal-starter/issues/259">support for SASS/SCSS</a>. I decided
that I might come back to it.</p>
<p><a href="https://github.com/AngularClass/angular2-webpack-starter">Angular2-Webpack-Starter</a> from
AngularClass was another that caught my eye since it obviously supported Webpack, but it also had
a lot of the other stuff ready to go. This included Router, HTTP, Forms, Hot Module Reload (HMR),
Async/Lazy Routes, Material Design, and tests! It also has a great list of guides and tips like
<a href="https://github.com/AngularClass/angular2-webpack-starter/issues/136">setting up SASS/SCSS</a>.
Unfortunately, it doesn’t yet support
<a href="https://github.com/AngularClass/angular2-webpack-starter/issues/885">AOT compilation</a> or
<a href="https://github.com/AngularClass/angular2-webpack-starter/issues/576">Angular Universal</a>.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Found a number of seeds w/
<a href="https://twitter.com/hashtag/AngularUniversal?src=hash&amp;ref_src=twsrc%5Etfw">#AngularUniversal</a>
support, but they all seem to be broken (<a href="https://twitter.com/hashtag/ngMaterial2?src=hash&amp;ref_src=twsrc%5Etfw">#ngMaterial2</a> / <a href="https://twitter.com/hashtag/AOT?src=hash&amp;ref_src=twsrc%5Etfw">#AOT</a>) or stuck on <a href="https://twitter.com/hashtag/Angular?src=hash&amp;ref_src=twsrc%5Etfw">#Angular</a> 2.1.</p>&mdash; Michael Prentice (@Splaktar) <a href="https://twitter.com/Splaktar/status/809285776378839041?ref_src=twsrc%5Etfw">December 15, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h1 id="finallypickingaseed">Finally picking a seed</h1>
<p>I settled on giving Anthony’s (qdouble)
<a href="https://github.com/qdouble/angular-webpack2-starter">fork of angular2-webpack-starter</a> a shot. It
combines all the great stuff from the original angular2-webpack-starter with support for AOT and
Universal! One thing I quickly noticed was that the project is stuck on an older version (<code>v2.1</code>) of
Angular (latest is <code>v2.3</code>).</p>
<p>After a lot of research, it became obvious that changes to Angular core in v2.2 and v2.3 broke
Angular Universal. Apparently the Angular core team has realized that this is a problem.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">But I just saw this
<a href="https://t.co/eJtyJEVZrw">https://t.co/eJtyJEVZrw</a> which mentions that <a href="https://twitter.com/hashtag/Universal?src=hash&amp;ref_src=twsrc%5Etfw">#Universal</a> is moving to angular core. <a href="https://twitter.com/hashtag/ngMaterial2?src=hash&amp;ref_src=twsrc%5Etfw">#ngMaterial2</a> is waiting on the move.</p>&mdash; Michael Prentice (@Splaktar) <a href="https://twitter.com/Splaktar/status/808911047109312512?ref_src=twsrc%5Etfw">December 14, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Because of this, they decided a couple weeks ago to move key pieces of Angular Universal into the
Angular core. Unfortunately, a number of key people have been on vacation since this decision
was made. So we’re stuck in this state where using Angular Universal means staying on Angular <code>v2.1</code>.</p>
<p>This also means that support for Angular Universal in a new version of Angular will have to wait for
at least v4 which just entered <code>beta.0</code>.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Angular 4.0.0-beta.0 is out. You&#39;re
wondering why it&#39;s Angular 4? Read about the reasoning behind here:
<a href="https://t.co/9AhXTMnlXc">https://t.co/9AhXTMnlXc</a> <a href="https://twitter.com/hashtag/angular?src=hash&amp;ref_src=twsrc%5Etfw">#angular</a></p>&mdash; Juri Strumpflohner (@juristr) <a href="https://twitter.com/juristr/status/809296629530525696?ref_src=twsrc%5Etfw">December 15, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h1 id="measuringthebenefits">Measuring the benefits</h1>
<p>The main purpose of the chosen seed/starter is performance (i.e. Angular Universal, Webpack 2, and
AOT compilation). I checked the README for some stats for nerds (i.e. perf goodies) but sadly found
none. Thus, I set to gathering some performance stats on the current build of the starter.</p>
<ul>
<li>Times listed for No throttling / Regular 3G.</li>
</ul>
<h4 id="devmode">Dev Mode</h4>
<blockquote>
  <p>npm start</p>
</blockquote>
<ul>
<li>29 requests</li>
<li>5.8 MB</li>
<li>1300ms / 66000ms DOMContentLoaded</li>
<li>1350ms / 66000ms load</li>
</ul>
<h4 id="universal">Universal</h4>
<blockquote>
  <p>npm run universal</p>
</blockquote>
<ul>
<li>16 requests</li>
<li>363 KB</li>
<li>928ms / 4480ms DOMContentLoaded</li>
<li>973ms / 5020ms load</li>
</ul>
<h4 id="aotmode">AOT mode</h4>
<blockquote>
  <p>npm run compile + npm run prodserver</p>
</blockquote>
<ul>
<li>16 requests</li>
<li>301 KB</li>
<li>432ms / 3530ms DOMContentLoaded</li>
<li>495ms / 3930ms load</li>
</ul>
<h4 id="universalaot">Universal + AOT</h4>
<blockquote>
  <p>npm run universal:aot or npm run compile:universal+ npm run prodserver</p>
</blockquote>
<ul>
<li>16 requests</li>
<li>392 KB</li>
<li>494ms / 4410ms DOMContentLoaded</li>
<li>535ms / 5030ms load</li>
</ul>
<h4 id="testsranon">Tests Ran on</h4>
<ul>
<li><p>Chrome 57.0.2951.0 canary (64-bit)</p></li>
<li><p>Cache disabled</p></li>
<li><p>MacBook Pro (Retina, 15-inch, Mid 2014)</p></li>
<li><p>2.8 GHz Intel Core i7</p></li>
<li><p>16 GB 1600 MHz DDR3</p></li>
<li><p>OS X El Capitán 10.11.6 (15G1212)</p></li>
<li><p>NodeJS 6.7.0</p></li>
</ul>
<h1 id="analysis">Analysis</h1>
<p>Now I know that Universal and AOT are still undergoing a lot of breaking changes and needed
improvements, but I found it a little odd that the combination (Universal + AOT) was slower than the
build with AOT alone.</p>
<p>Since the angular-cli isn’t supporting Universal + AOT yet, I was looking to find a solid seed for
Universal, AOT, Webpack 2, Material 2, SCSS, etc. and this one seems to be the closest that I can
find which isn’t significantly broken.</p>
<p>With the numbers above, I was wondering if I should even bother with Universal at this point.
Then I thought, well Universal should help get that initial paint a lot faster. But on any network
with 3G+, the time between initial paint and interactivity is under 50ms and isn’t even noticeable.
If I drop down to Regular 2G, then I do see the initial DOM loaded for about 2s before JavaScript
takes control and the page is re-rendered and fully ready for interaction.</p>
<p>Perhaps part of this issue is that the app doesn’t have an appShell (it’s just a white “Loading…”
page), but either way I’m not sure I should go to the extra trouble of running a NodeJS server
for Universal at this point. I could just host a client-only app in Firebase Hosting using their
Edge CDN w/ AOT and maybe that would be even faster than the numbers above.</p>
<p>SEO is something that I really need, but I’m not convinced that Universal will work properly here
and deliver the desired results. There’s some
<a href="https://github.com/angular/universal-starter/issues/287">possible hacks</a> discussed in the
universal-starter project where the meta tags can be manipulated. However, Angular’s new
<a href="https://github.com/angular/angular/pull/12322">Meta Service</a> just landed in Angular <code>v4-beta.0</code>
thanks to Dzmitry Shylovich! Unfortunately Universal isn’t compatible with the latest versions of
Angular yet.</p>
<h1 id="tldr">TL;DR</h1>
<p>It appears that I should just stick with AOT compilation and wait until Universal gets better
support from the Angular core team (in progress, no ETA).</p>
<p>Thankfully the chosen <a href="https://github.com/qdouble/angular-webpack2-starter">starter</a> makes that a
well-supported option in addition to supporting these configurations used in the benchmarks above.
This is what enabled the ability to gather these numbers using different approaches, while keeping
the code-base exactly the same. Thanks to <a href="https://github.com/qdouble">Anthony</a> for the hard work
on this starter and for sharing what’s been working for him on his projects!</p>]]></content:encoded>
            <category>universal</category>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Upgrade from Angular 2.RC4 to final with Angular-CLI]]></title>
            <link>https://devintent.com/blog/2016-10-22-upgrade-from-angular-2-rc4-to-final-with-angular-cli.md</link>
            <guid isPermaLink="false">blog/2016-10-22-upgrade-from-angular-2-rc4-to-final-with-angular-cli.md</guid>
            <pubDate>Sat, 22 Oct 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Details about the Angular 2.0.0-rc.5 release.]]></description>
            <content:encoded><![CDATA[<p><em>I’ve completed the RC4 => <code>2.1.2</code> upgrade for one proprietary app and one
<a href="https://github.com/gdg-x/nexus">open source app</a>. Even with experience, this process is far from
efficient or problem-free with the various libraries, modules, and systems breaking or otherwise
affecting each other.</em></p>
<p><em>It’s clear the Angular 2 Release Candidates were actually Alphas and what we’re using now in
<code>2.1.1</code> is Beta. You could say that the Angular Core is in Release Candidate state currently, but
the ecosystem of semi-mandatory modules that make up the platform are mostly in some form of Alpha
or Beta.</em></p>
<h1 id="letsgetstarted">Let’s get started</h1>
<p>If you update your version of the CLI first from <code>beta.10</code> to <code>beta.19</code>, you may see this error message:</p>
<p><a href="/large-images/error-old-cli-version.png"><img src="/large-images/error-old-cli-version.png" alt="Error message about using an old version of the Angular CLI" /></a></p>
<p>Note that there is an updated guide here:
<a href="https://github.com/angular/angular-cli/wiki/Upgrading-from-Beta.10-to-Beta.14">https://github.com/angular/angular-cli/wiki/Upgrading-from-Beta.10-to-Beta.14</a></p>
<p><em>I also submitted a <a href="https://github.com/angular/angular-cli/pull/2765">PR</a> to improve the grammar of
this upgrade warning message.</em></p>
<p>The first step of this helpful guide is to make sure that you are up to Angular RC6 or greater. So
you would then find that you need to upgrade from Angular RC4 to the latest which includes the major
breaking change of <a href="https://angular.io/docs/ts/latest/guide/ngmodule.html">ngModules</a> announced in
<a href="http://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html">this blog post</a>.
This blog post announcing Angular RC5 includes a really helpful link to a migration guide.
Unfortunately, that migration guide
(<a href="https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html">https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html</a>)
is a <strong><code>404</code></strong> on the Angular.io docs site.</p>
<h1 id="nowthetaskistofindamigrationguidethatworksforrc4tofinal">Now the task is to find a migration guide that works for RC4 to final</h1>
<p>There was a
<a href="https://www.reddit.com/r/Angular2/comments/4x11z6/angular_2_rc4_to_rc5_migration_guide/">Reddit</a>
discussing this lost migration guide, but it doesn’t point to a new location.</p>
<p>There is
<a href="http://stackoverflow.com/questions/39559327/update-angular-2-from-rc4-to-final-release">StackOverflow question</a>
that poses this exact question, but it’s first suggested solution appears to be the most time
intensive option… review the changelogs for RC5, RC6, RC7, and final for breaking changes and
then make adjustments to your project. The second option here is one that I have been considering,
generate a new project with the latest angular-cli <code>beta.19</code> and then pull that configuration into
your existing project.</p>
<p>After quite a bit of looking, I didn’t really find something that I was happy with. A few guides hit
about 25% of what I needed, but I couldn’t find anything that was much more complete.</p>
<h1 id="getuptospeedwiththeconceptsfirst">Get up to speed with the concepts first</h1>
<p>I highly suggest reading the following before starting:</p>
<p>The first is the
<a href="http://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html">Angular team blog post</a>
that covers the reasons why ngModule exists and how it helps you.</p>
<p>Then the <a href="https://angular.io/docs/ts/latest/guide/ngmodule.html">official docs on ngModule</a>
cover some key patterns like having a
<a href="https://angular.io/docs/ts/latest/guide/ngmodule.html#core-module">Core Module</a> and
<a href="https://angular.io/docs/ts/latest/guide/ngmodule.html#shared-module">Shared Module</a>. It also covers
<a href="https://angular.io/docs/ts/latest/guide/ngmodule.html#lazy-load">lazy loading modules</a>.</p>
<h1 id="startwithasinglengmodule">Start with a single ngModule</h1>
<p>This step involves just creating a single module and adding everything to it. This makes sense for
small to medium-sized projects. If your project is already large, you’ll want to move on to the next
step.</p>
<p>Basically this step just involves using the docs links above to create your AppModule and plumb
everything together.</p>
<h4 id="awaywiththeboilerplate">Away with the boilerplate!</h4>
<p>After you’ve got an ngModule, you’ll need a lot less boilerplate. Unfortunately, you (or angular-cli)
already wrote it, so you’ll have to go and remove it now. This includes changing all of your
components by removing their directives, providers, pipes, and lots and lots of imports that aren’t
needed anymore.</p>
<h1 id="createasharedmodule">Create a Shared Module</h1>
<p>Use the <a href="https://angular.io/docs/ts/latest/guide/ngmodule.html#shared-module">docs</a> on creating a
Shared Module and move your application-wide services and common Angular modules (FormsModule,
RouterModule, etc.) into this new SharedModule.</p>
<h1 id="evaluateyourprojectformodularity">Evaluate your project for modularity</h1>
<p>Now you’ll want to think about your project and find out if it makes sense to break up specific
routes into lazily loaded modules. Ideally, your module that is bootstrapped at the root of your
app should be as lean as possible. Once you’ve identified these modules, it’s time to create them
and start setting up the
<a href="https://angular.io/docs/ts/latest/guide/ngmodule.html#lazy-load">lazy loading in the router</a>.</p>
<h1 id="migrateangularcli">Migrate Angular-CLI</h1>
<p>OK, now you’ve setup ngModules and updated your package.json to use <code>@angular/xxx: 2.1.2</code>, you
are ready to proceed with the
<a href="https://github.com/angular/angular-cli/wiki/Upgrading-from-Beta.10-to-Beta.14">angular-cli migration guide</a>.
<strong>Carefully</strong> follow the guide, and you will be about 90% of the way there.</p>
<p>Many people noticed that their favicon and 404 pages weren’t showing up in dist/ after upgrading.
The community filed numerous bugs, but in <code>beta.19</code> this was fixed. Make the changes below to take
advantage of this new feature that allows specifying an array of assets.</p>
<p><strong>angular-cli.json</strong> (old)</p>
<pre><code class="json language-json">"assets": "assets",
</code></pre>
<p><strong>angular-cli.json</strong> (new)</p>
<pre><code class="json language-json">"assets": [
  "assets",
  "elements.html",
  "404.html",
  "favicon.ico",
  "manifest.webapp",
  "icons"
],
</code></pre>
<p>Obviously the contents of this array will be specific to your application.</p>
<h1 id="migrateangularmaterial2">Migrate Angular Material2</h1>
<p>Their <a href="https://github.com/angular/material2/blob/master/GETTING_STARTED.md">getting started guide</a>
provides the minimal level of help required to get this working. This has changed quite a bit from
what was found in the RC5 blog post. There is now a single MaterialModule that you need to load.</p>
<p><strong>src/app/app.module.ts</strong></p>
<pre><code class="ts language-ts">import { MaterialModule } from '@angular/material';

@NgModule({
  imports: [MaterialModule.forRoot()],
</code></pre>
<p>If you are using any of their sliders, you’ll need to import hammer.js with the new angular-cli process.</p>
<p><strong>angular-cli.json</strong></p>
<pre><code class="json language-json">{
  "scripts": ["../node_modules/hammerjs/hammer.js"]
}
</code></pre>
<p>Additionally, material2 now has a theming system which you will need to configure for the styling
of your UI components to look good (i.e. not be mostly grey). See their theming guide
<a href="https://github.com/angular/material2/blob/master/docs/theming.md">here</a> to set this up.</p>
<h1 id="migratefirebase">Migrate Firebase</h1>
<p>If you are using the Firebase SDK (required for many features like Firebase Storage that aren’t yet
supported in AngularFire2) then the way that you load that library has changed in the angular-cli.</p>
<p><em>Make sure you don’t also include the <code>@types/firebase</code> definitions in your <strong><code>package.json</code></strong>.</em></p>
<p><strong>angular-cli.json</strong></p>
<pre><code class="json language-json">{
  "scripts": ["../node_modules/firebase/firebase.js"]
}
</code></pre>
<h1 id="upgradeangularfire2">Upgrade AngularFire2</h1>
<p>Their <a href="https://github.com/angular/angularfire2/blob/master/docs/1-install-and-setup.md#4-setup-ngmodule">docs</a>
are quite helpful, but they only covered about 95% of what I needed to do. That last 5% was pretty
painful as what I got working in angular-cli <code>beta.17</code> needed more tweaking with <code>beta.19</code>.</p>
<p>For just using AngularFire2 without Firebase Auth, you can do this:</p>
<p><strong>src/app/app.module.ts</strong></p>
<pre><code class="ts language-ts">import { AngularFireModule } from 'angularfire2';

const firebaseConfig = {
  apiKey: '&lt;your-key&gt;',
  authDomain: '&lt;your-project-authdomain&gt;',
  databaseURL: '&lt;your-database-URL&gt;',
  storageBucket: '&lt;your-storage-bucket&gt;'
};

@NgModule({
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(firebaseConfig)
  ],
</code></pre>
<p>If you’re using Firebase Auth, you’ll need a bit more. They cover this in their
<a href="https://github.com/angular/angularfire2/blob/master/docs/5-user-authentication.md#configure-application-in-bootstrap">Auth docs</a>.</p>
<p><em>I submitted a <a href="https://github.com/angular/angularfire2/pull/628">PR</a> to help make
these docs a little more straightforward.</em></p>
<p><strong>src/app/app.module.ts</strong></p>
<pre><code class="ts language-ts">import { AngularFireModule, AuthProviders, AuthMethods } from 'angularfire2';

const myFirebaseConfig = {
  apiKey: '&lt;your-key&gt;',
  authDomain: '&lt;your-project-authdomain&gt;',
  databaseURL: '&lt;your-database-URL&gt;',
  storageBucket: '&lt;your-storage-bucket&gt;',
}

const myFirebaseAuthConfig = {
  provider: AuthProviders.Google,
  method: AuthMethods.Redirect
}

@NgModule({
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(myFirebaseConfig, myFirebaseAuthConfig)
  ],
</code></pre>
<p>**Troubleshooting
**I needed to do a bit more here to deal with some TypeScript issues. Their
<a href="https://github.com/angular/angularfire2/blob/master/docs/1-install-and-setup.md#troubleshooting">existing docs</a>
here seemed to be designed for an older version of the angular-cli. I needed to remove
<code>@types/firebase</code> from my <code>package.json</code> and use the typedefs from the Firebase SDK.</p>
<p><strong>src/tsconfig.json</strong></p>
<pre><code class="json language-json">"files": [
  "../node_modules/firebase/firebase.d.ts"
]
</code></pre>
<p><em>If you are on the new AngularFire2 beta.6, this step is not needed since these typedefs are included
in AngularFire2. Adding them again here will cause many duplicate type errors.</em></p>
<h1 id="upgradeangular2googlemaps">Upgrade Angular2-Google-Maps</h1>
<p>The <a href="https://angular-maps.com/docs/getting-started.html#angular2-google-maps-setup">docs</a> here are
quite comprehensive and once I followed them, everything seemed to just work. The main change is
related to ngModule.</p>
<p><em>They also fixed some pesky bugs in the latest v0.15.0 release.</em></p>
<p><strong>src/app/app.module.ts</strong></p>
<pre><code class="ts language-ts">import { AgmCoreModule } from 'angular2-google-maps/core';

@NgModule({
  imports: [
    BrowserModule,
    AgmCoreModule.forRoot({
      apiKey: 'YOUR_KEY'
    })
  ],
</code></pre>
<h1 id="upgradeangular2polymer">Upgrade Angular2-Polymer</h1>
<p>The Vaadin team has done a lot of the tough work to streamline this process. Their documentation can
be found <a href="https://vaadin.com/docs/-/part/elements/angular2-polymer/ng-cli-webpack.html">here</a>.</p>
<p><em>As part of this process, I sent them a <a href="https://github.com/vaadin/angular2-polymer/pull/101">PR</a> to
correct their README’s link to these docs.</em></p>
<p>One of the key changes here is the way that bootstrapping the Web Components polyfill is
accomplished due to changes to the angular-cli. This includes creating a <strong>main-polymer.ts</strong> file
which kicks off the bootstrapping of your Angular application after the <strong>WebComponentsReady</strong> event
is fired.</p>
<p><strong>src/main-polymer.ts</strong></p>
<pre><code class="ts language-ts">document.addEventListener('WebComponentsReady', () =&gt; {
  // Load Angular app
  require('./main.ts');
});
</code></pre>
<p>Then you need to update angular-cli’s config to use this new main-polymer.ts as your app’s entry point.</p>
<p><strong>angular-cli.json</strong></p>
<pre><code class="json language-json">"main": "main-polymer.ts",
</code></pre>
<p>Another key change from the angular-cli is that loading the <strong>webcomponents-lite.min.js</strong> file is
now easier. I also decided to get it from NPM instead of Bower.</p>
<p><strong>angular-cli.json</strong></p>
<pre><code class="json language-json">{
  "scripts": ["../node_modules/webcomponents.js/webcomponents-lite.js"]
}
</code></pre>
<h1 id="fixissueswithbasicwebcomponents">Fix issues with Basic Web Components</h1>
<p>I found that the key here was to require the Basic Web Component scripts in the <strong>main-polymer.ts</strong>
file defined as part of the Angular2-Polymer configuration above. These web components don’t have
type definitions for TypeScript and importing their
<a href="https://github.com/basic-web-components/basic-web-components/#installing-components-via-npm">ES6 modules</a>
was a nightmare.</p>
<p><strong>src/main-polymer.ts</strong></p>
<pre><code class="ts language-ts">document.addEventListener('WebComponentsReady', () =&gt; {
  // Load basic web components
  require('../node_modules/basic-arrow-selection');
  require('../node_modules/basic-carousel');
  require('../node_modules/basic-page-dots');

  // Load Angular app
  require('./main.ts');
});
</code></pre>
<p>This worked somewhat, but still resulted in errors since the angular-cli doesn’t have an ES6 loader
configured (separate from the TypeScript loader) and they don’t allow for customization of the
Webpack configuration. This ES6 still ran OK on the latest Firefox, Chrome, and Safari, but it failed
on IE11.</p>
<p>Due to this, I ended up removing Basic Web Components from my project and using
<a href="https://ng-bootstrap.github.io/#/getting-started">ngBootstrap’s</a>
<a href="https://ng-bootstrap.github.io/#/components/carousel">Carousel</a> instead.</p>]]></content:encoded>
            <category>angular-cli</category>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[Configuring an AngularJS app for production]]></title>
            <link>https://devintent.com/blog/2016-09-14-configuring-an-angularjs-app-for-production.md</link>
            <guid isPermaLink="false">blog/2016-09-14-configuring-an-angularjs-app-for-production.md</guid>
            <pubDate>Wed, 14 Sep 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Tips for configuring AngularJS applications for production.]]></description>
            <content:encoded><![CDATA[<p>When running in production mode, your app should do the following:</p>
<pre><code class="js language-js">myApp.config([
  '$compileProvider',
  '$logProvider',
  function ($compileProvider, $logProvider) {
    $compileProvider.debugInfoEnabled(false);
    $logProvider.debugEnabled(false);
  },
]);
</code></pre>
<p>Note that this is in addition to whatever else your app needs to do in its <code>.config()</code> function.
For this to be fully effective, you should use Angular’s <code>$log</code> service instead of <code>console.log()</code>
throughout your app.</p>
<p>As Ben Nadel noted, if your app is doing element.scope() anywhere, it will no longer work after
<code>$compileProvider.debugInfoEnabled(false)</code> is called.</p>
<p><a href="/large-images/angularjs-horizontal-logo.png"><img src="/large-images/angularjs-horizontal-logo.png" alt="AngularJS Logo" /></a></p>]]></content:encoded>
            <category>angularjs</category>
        </item>
        <item>
            <title><![CDATA[Angular 2 rc.5 is out!]]></title>
            <link>https://devintent.com/blog/2016-08-10-angular-2-rc-5-is-out.md</link>
            <guid isPermaLink="false">blog/2016-08-10-angular-2-rc-5-is-out.md</guid>
            <pubDate>Wed, 10 Aug 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Details about the Angular 2.0.0-rc.5 release.]]></description>
            <content:encoded><![CDATA[<p>It contains <strong>18 breaking changes</strong>, over <strong>40 new features</strong>, and <strong>80 bug fixes</strong>.</p>
<p>RC 5 brings with it the significant new ngModule feature along with updates to forms, the router
(Lazy Loading), material design, and more!</p>
<p>This is the first RC of the new router. You can find out more about the router in Victor Savkin’s
new <a href="https://vsavkin.com/announcing-angular-2-router-book-2de3c2822f7c#.viylihqxo">e-book</a>.</p>
<p><a href="/icons/angular.svg"><img src="/icons/angular.svg" alt="Angular Icon" /></a></p>
<p>The associated Angular team blog post is located here:
<a href="http://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html">http://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html</a></p>
<p>The migration guide used to be found in the Angular 2 docs
<a href="https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html">here</a> but it has been removed.
If you need help with upgrading from the RCs, please see
<a href="https://blog.devintent.com/upgrade-from-angular-2-rc4-to-final-with-angular-cli-7ef590b2d35d">my blog post on this topic</a>.</p>
<p>The more detailed Changelog can be reviewed here:
<a href="https://github.com/angular/angular/blob/master/CHANGELOG.md#200-rc5-2016-08-09">https://github.com/angular/angular/blob/master/CHANGELOG.md#200-rc5-2016-08-09</a></p>]]></content:encoded>
            <category>angular</category>
        </item>
        <item>
            <title><![CDATA[AngularJS Material 1.1.0-RC.X Privatization of Styles Reverted]]></title>
            <link>https://devintent.com/blog/2016-07-15-angularjs-material-1-1-0-rc-x-privatization-of-styles-reverted.md</link>
            <guid isPermaLink="false">blog/2016-07-15-angularjs-material-1-1-0-rc-x-privatization-of-styles-reverted.md</guid>
            <pubDate>Fri, 15 Jul 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Discussion of the decision to revert the privatization of styles in AngularJS Material 1.1.0.]]></description>
            <content:encoded><![CDATA[<p>If you are an <a href="https://material.angularjs.org/">AngularJS Material</a> 1.x user, then you might
have noticed that, while trying out the 1.1.0 release candidates, many of your CSS fixes and
workarounds were broken.</p>
<p>You may have worked around this problem (I know I've spoken to and see many people doing this)
by changing your styles to target the new "private" styles (i.e. the <strong>_md-visually-hidden</strong>
class on <code>md-tabs</code>' <code>md-tabs-dummy-wrapper</code>) introduced in 1.1.0 RC.</p>
<p><a href="/large-images/angularjs-material-private-styles-example.png"><img src="/large-images/angularjs-material-private-styles-example.png" alt="The above mentioned md-tabs change." /></a></p>
<p>I cautioned a number of people against this, pointing out that these are meant to be private
styles which will see unannounced breaking changes.</p>
<p>Unfortunately, it turns out that these changes were far too disruptive and in some cases there
was no work around outside of using the private styles. So these private style changes have
all been reverted in master via this commit. These changes will be in the next 1.1.0-RC.6
build.</p>
<p><a href="/large-images/angularjs-material-private-styles-reverted-commit.png"><img src="/large-images/angularjs-material-private-styles-reverted-commit.png" alt="Commit that reverts these&nbsp;changes." /></a></p>
<p>If you have already updated your entire application to rely on these private styles, then
unfortunately, you will need to revert those changes as well in order to move to the final
1.1.0 release.</p>
<p>Note that this does not remove all private styles. There remain some styles, that existed
prior to 1.1.0-RC1, that are still preceded with an underscore ("_"). These styles remain
private and should not be used as breaking changes to them will not be announced.</p>
<h2 id="thegoodnbspnews">The Good&nbsp;News</h2>
<p>If your project is on the latest stable release (<a href="https://material.angularjs.org/1.0.9/">1.0.9</a>),
then your upgrade path to 1.1.0 should now be a bit smoother when 1.1.0 final lands.</p>
<p>Additionally, if you are trying out <a href="https://material.angular.io/">Angular Material</a>,
you should note that they are planning to include similarly denoted private styles.</p>
<p>Please read <a href="https://groups.google.com/forum/#!msg/ngmaterial/mLJrRW9qrLA/C_Ni3LSrBQAJ">this post</a>
for additional details and to ask questions.</p>]]></content:encoded>
            <category>angularjs-material</category>
        </item>
        <item>
            <title><![CDATA[Responsive UI with AngularJS Material 1.x]]></title>
            <link>https://devintent.com/blog/2016-06-28-responsive-ui-angularjs-material.md</link>
            <guid isPermaLink="false">blog/2016-06-28-responsive-ui-angularjs-material.md</guid>
            <pubDate>Mon, 03 Feb 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Responsive UI guidance and tooling for Material Design and AngularJS Material.]]></description>
            <content:encoded><![CDATA[<p>When I presented this material in 2015, the Google Design team was calling it Adaptive UI. It has since been renamed in the
<a href="https://material.io/design/">Material Design Specification</a> to
<a href="https://material.io/design/layout/responsive-layout-grid.html">Responsive UI</a>. Note that, while the phrase uses the word
"responsive", this is different from the Responsive Design from the recent past.</p>
<iframe src="https://docs.google.com/presentation/d/e/2PACX-1vTxCK5LgapdJIXWomiPX1taogayrq_6GU7snmHQtlISnXZX61UMpYiHMlH7AGIZVby2U2CDX_bPpC1W/embed?start=false&loop=false&delayms=60000"
        frameborder="0" width="796" height="477" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
<p><strong>Google defines Responsive UI as:</strong></p>
<blockquote>
  <p>Responsive layouts in material design adapt to any possible screen size. This UI guidance includes a flexible grid that ensures
  consistency across layouts, breakpoint details about how content reflows on different screens, and a description of how an app can
  scale from small to extra-large screens.</p>
</blockquote>
<p>Similar to Responsive Design, the system uses breakpoints which match up with the screen width of various devices.</p>
<p><a href="/large-images/responsive-breakpoints-material-design.png"><img src="/large-images/responsive-breakpoints-material-design.png" alt="Responsive Breakpoints Visualized" /></a></p>
<p>The Material Design site has some <a href="https://material.io/design/layout/responsive-layout-grid.html#grid-behavior">great examples</a> of
the UI grid. They include animated images to demonstrate how the grid reacts to changes in screen width.</p>
<p>For me, the most interesting and powerful part of Responsive UI with Material Design are the UI Patterns. They demonstrate how to
apply the breakpoints, grid, and surface behaviors to real-world UI design challenges.</p>
<p>These patterns include</p>
<ul>
<li>Reveal</li>
<li>Transform</li>
<li>Reflow</li>
<li>Expand</li>
<li>Position</li>
</ul>
<p>I've taken some time to update my slides from November to fix some of the broken links and add links to previously unavailable tools.
One of these tools, the exciting "<a href="https://material.io/resources/resizer/">Resizer</a>", was previewed at the Polymer Summit in 2015.</p>
<p>Video here:</p>
<iframe width="796" height="440" src="https://www.youtube.com/embed/YiiXKoLYLMo" frameborder="0"
        allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>Since then it has finally been made available for use. Please do <a href="https://material.io/resources/resizer/">check it out</a>!</p>
<p>For more in depth details, discussion, and links, please check out
<a href="https://docs.google.com/presentation/d/1cLYWG-_mW92kezTI1JLYfi9kNH9wu2-SIpeNqyArlQw/edit?usp=sharing">the slides</a> from this
presentation.</p>]]></content:encoded>
            <category>angularjs-material</category>
            <category>angularjs</category>
        </item>
    </channel>
</rss>