{
    "version": "https://jsonfeed.org/version/1",
    "title": "DevIntent Blog",
    "home_page_url": "https://devintent.com",
    "description": "Our blog is where our experts highlight best practices, demonstrate solutions to common problems, and communicate information about recent software releases.",
    "icon": "https://devintent.com/DevIntentLogo.png",
    "items": [
        {
            "id": "blog/2024-11-23-level-up-your-apps-speed-with-ngoptimizedimage.md",
            "content_html": "<p>If you've worked on a web app, you know that images significantly impact both design and performance. While\nthey make pages look great, they can also slow everything down. That’s where Angular’s <code>NgOptimizedImage</code>\ndirective comes in. It’s a handy tool for optimizing images, so they load faster without losing quality. Let’s\ndive into how this directive can make your Angular app snappier and improve user experience.</p>\n<hr />\n<h2 id=\"whyoptimizeimagesanyway\">Why Optimize Images Anyway?</h2>\n<p>We all want our apps to look good, but images come with costlier load times. Optimizing images can\ndramatically improve performance metrics, especially the\n<a href=\"https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint\">Largest Contentful Paint (LCP)</a>,\nwhich measures how fast the largest piece of content appears on the screen. This is huge for user experience\nand SEO. Angular’s <code>NgOptimizedImage</code> directive makes it easy to get it right without manual tweaks.</p>\n<hr />\n<h2 id=\"keyfeaturesofngoptimizedimage\">Key Features of <code>NgOptimizedImage</code></h2>\n<h3 id=\"1responsiveimageswithsrcsetandsizes\">1. Responsive Images with <code>srcSet</code> and <code>sizes</code></h3>\n<p>The <code>srcSet</code> and <code>sizes</code> attributes allow the browser to load the right image size for each device, which is\nespecially helpful for performance. The great thing about Angular’s <code>NgOptimizedImage</code> directive is that it\ngenerates the <code>srcSet</code> for you, so you don’t need to do it manually.</p>\n<p><strong>Example:</strong></p>\n<pre><code class=\"html language-html\">&lt;img\n  ngSrc=\"angular.jpg\"\n  width=\"200\"\n  height=\"200\"\n  sizes=\"80vw\"\n/&gt;\n</code></pre>\n<p>Here, <code>sizes=\"80vw\"</code> sets the image to 80% of the viewport width. Angular will handle the rest, creating a\n<code>srcSet</code> with various resolutions so that each device gets the best fit. This saves time and ensures a smooth\nload no matter the screen size.</p>\n<h3 id=\"2customizingimagebreakpoints\">2. Customizing Image Breakpoints</h3>\n<p>If you’re working with specific screen sizes, Angular lets you customize breakpoints by setting an\n<code>IMAGE_CONFIG</code> token. This way, you can pick just the breakpoints that match your app’s design.</p>\n<p><strong>Example:</strong></p>\n<pre><code class=\"typescript language-typescript\">providers: [{\n  provide: IMAGE_CONFIG,\n  useValue: {\n    breakpoints: [384, 640, 750]\n  }\n}]\n</code></pre>\n<p>Now Angular will only generate images for 384px, 640px, and 750px, which keeps your file sizes smaller and\nyour app faster.</p>\n<hr />\n<h3 id=\"3prioritizingkeyimageswithpriority\">3. Prioritizing Key Images with <code>priority</code></h3>\n<p>Ever noticed how long it can take to load a big image like a banner? The <code>priority</code> attribute tells Angular\nwhich images are critical for loading first. If you set <code>priority</code>, Angular preloads the image, making sure it\nappears quickly, improving that all-important LCP.</p>\n<p><strong>Example:</strong></p>\n<pre><code class=\"html language-html\">&lt;img\n  ngSrc=\"hero.jpg\"\n  width=\"1200\"\n  height=\"600\"\n  priority\n/&gt;\n</code></pre>\n<p>For server-side rendered apps, Angular even adds a <code>&lt;link rel=\"preload\"&gt;</code> tag for these images, so they start\nloading right away. This is perfect for hero images or banners that you want users to see immediately.</p>\n<hr />\n<h3 id=\"4fillmodeforflexiblelayouts\">4. Fill Mode for Flexible Layouts</h3>\n<p>Need an image to fill a container, like a background? <code>fill</code> mode has you covered. It lets an image scale to\nfit the container without needing fixed dimensions, which is perfect for layouts with unknown widths or\nheights.</p>\n<p><strong>Example:</strong></p>\n<pre><code class=\"html language-html\">&lt;img ngSrc=\"background.jpg\" fill/&gt;\n</code></pre>\n<p>Just make sure your container has <code>position: relative</code>, <code>absolute</code>, or <code>fixed</code>, so the image fills it\nproperly. This feature is great for responsive layouts where you want images to adapt smoothly.</p>\n<hr />\n<h3 id=\"5lazyloadingforoffscreenimages\">5. Lazy Loading for Off-Screen Images</h3>\n<p>Angular makes lazy loading effortless with <code>loading=\"lazy\"</code>, which defers loading images until they’re about\nto be visible. This reduces the initial page load and is awesome for things like image galleries.</p>\n<p><strong>Example:</strong></p>\n<pre><code class=\"html language-html\">&lt;img\n  ngSrc=\"thumbnail.jpg\"\n  width=\"200\"\n  height=\"200\"\n  loading=\"lazy\"\n/&gt;\n</code></pre>\n<p>Just be cautious with images that are crucial to the layout, like a logo. For these, skip lazy loading to\nensure they load right away.</p>\n<hr />\n<h3 id=\"6placeholdersforabetterloadingexperience\">6. Placeholders for a Better Loading Experience</h3>\n<p>Nothing kills user experience like a blank loading image. With <code>placeholder</code>, you can show a temporary low-res\nversion or even a <a href=\"https://medium.com/@shimonmoyal/a-dive-into-base64-and-its-significance-in-web-development-b6bd4427f61d\">Base64-encoded</a>\npreview while the main image loads. This provides a smoother experience as users see a preview of the\nimage right away.</p>\n<p>Here’s an example of implementing a placeholder:</p>\n<pre><code class=\"html language-html\">&lt;img\n  ngSrc=\"profile.jpg\"\n  width=\"200\"\n  height=\"200\"\n  placeholder\n/&gt;\n</code></pre>\n<p>To take it a step further, you can use a Base64-encoded image as a placeholder. For example, a blurred\nversion of the image can be used to indicate that the original is still loading.</p>\n<p><img src=\"/blog/ngoptimizedimage-1/placeholder.gif\" alt=\"A blurred circular spinner placeholder serving as a placeholder\" /></p>\n<p>The placeholder blur effect can be customized with the <a href=\"https://angular.dev/api/common/ImagePlaceholderConfig\">placeHolderConfig</a>\nobject or turned off entirely. For example:</p>\n<pre><code class=\"html language-html\">&lt;img\n  ngSrc=\"cat.jpg\"\n  width=\"400\"\n  height=\"200\"\n  placeholder\n  [placeholderConfig]=\"{blur: false}\"\n/&gt;\n</code></pre>\n<p>If you'd like to use a Base64-encoded placeholder, you can easily generate the string using:</p>\n<ul>\n<li>Online Tools: Use a free online Base64 converter like <a href=\"https://www.base64-image.de/\">Base64-Image</a>, and\nit will generate the encoded string.</li>\n<li>Command Line Tools: Open a terminal and type the following command:</li>\n</ul>\n<pre><code class=\"bash language-bash\">  base64 -i input-image.jpg\n</code></pre>\n<p>Once you have the Base64 string, you can embed it directly into your HTML as the src for the placeholder:</p>\n<pre><code class=\"html language-html\">&lt;img\n  ngSrc=\"profile.jpg\"\n  width=\"200\"\n  height=\"200\"\n  placeholder=\"data:image/jpeg;base64,/9j/4AAQSk...\"\n/&gt;\n</code></pre>\n<p>This approach makes the user experience smoother and creates a seamless visual flow.</p>\n<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>\nautomatically. Just keep them small (under 4 KB) to avoid slowing down the load. Angular will even throw\nan error if the placeholder size is too big:</p>\n<pre><code class=\"text language-text\">NG02965: The NgOptimizedImage directive (activated on an &lt;img&gt; element with the ngSrc=\"angular.jpg\") has\ndetected that the placeholder attribute is set to a data URL which is longer than 4000 characters. This\nis discouraged, as large inline placeholders directly increase the bundle size of Angular and hurt page\nload performance. For better loading performance, generate a smaller data URL placeholder.\n</code></pre>\n<hr />\n<h2 id=\"cdnintegrationforfasterimagedelivery\">CDN Integration for Faster Image Delivery</h2>\n<p>By using a Content Delivery Network (CDN) with <code>NgOptimizedImage</code>, you get faster load times because images\nare served from servers closer to your users. CDNs cache content across the globe, meaning shorter load times\nand less data travel, which makes a huge difference, especially for users far from your primary server.</p>\n<p>CDNs also often compress images, ensuring the best quality at the smallest size, which boosts performance even\nfurther. When combined with <code>NgOptimizedImage</code>, CDNs can help you build a fast, responsive app that works well\nfor users everywhere.</p>\n<hr />\n<h2 id=\"apracticalexample\">A Practical Example</h2>\n<p>Now, let's look at a real-world example to see how the <code>NgOptimizedImage</code> directive can make a big difference\nin performance. Imagine we’re building a site that displays 16 preview images.</p>\n<p><img src=\"/blog/ngoptimizedimage-1/demo-app.png\" alt=\"Preview of the Demo Site\" /></p>\n<p>Here’s the initial setup with the standard <code>src</code> attribute:</p>\n<pre><code class=\"html language-html\">&lt;div style=\"...\"&gt;\n  @for (image of list; track $index) {\n  &lt;img\n    width=\"300\"\n    height=\"300\"\n    [src]=\"image\"\n    alt=\"A 300x300 placeholder image with a light gray background and bold black 'Preview' text in the center\"\n  /&gt;\n  }\n&lt;/div&gt;\n</code></pre>\n<p>When we analyze the page in Lighthouse, the First Contentful Paint (FCP) comes in at 1.4 seconds, while the\nLargest Contentful Paint (LCP) lags behind at 13.5 seconds—not ideal.</p>\n<p><img src=\"/blog/ngoptimizedimage-1/demo-app-initial-lighthouse-score.png\" alt=\"Lighthouse Performance Score for Non-Optimized Images\" /></p>\n<p>By making a few tweaks with <code>NgOptimizedImage</code>, we can get those numbers way down:</p>\n<pre><code class=\"html language-html\">&lt;div style=\"...\"&gt;\n  @for (image of list; track $index) {\n    &lt;img\n      width=\"300\"\n      height=\"300\"\n      [src]=\"image\"\n      alt=\"A 300x300 placeholder image with a light gray background and bold black 'Preview' text in the center\"\n      priority\n      placeholder\n    /&gt;\n  }\n&lt;/div&gt;\n</code></pre>\n<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>\n<pre><code class=\"html language-html\">&lt;link rel=\"preconnect\" href=\"https://fpoimg.com/\"&gt;\n</code></pre>\n<p>And in our app configuration, we set up\na <a href=\"https://angular.dev/guide/image-optimization#configuring-an-image-loader-for-ngoptimizedimage\">custom image loader</a>\nfor our CDN (e.g., <code>Imgix</code>):</p>\n<pre><code class=\"typescript language-typescript\">const appConfig: ApplicationConfig = {\n  providers: [provideImgixLoader('https://fpoimg.com/')],\n};\n</code></pre>\n<p>With these small adjustments, we see a huge performance boost: FCP drops to just 0.2 seconds, and LCP is down\nto a quick 0.7 seconds! This is a perfect example of how <code>NgOptimizedImage</code> can make a real difference in your\napp’s speed and user experience.</p>\n<p><img src=\"blog/ngoptimizedimage-1/demo-app-final-lighthouse-score.png\" alt=\"Lighthouse Performance Score for Optimized Images\" /></p>\n<hr />\n<h2 id=\"wrappingup\">Wrapping Up</h2>\n<p>Angular’s <code>NgOptimizedImage</code> is a fantastic tool for improving image handling and app performance. Whether\nyou’re working with responsive images, lazy loading, or CDN integration, this directive makes it easy to get\nthings right. With these optimizations, you’ll have a faster, smoother app that keeps users happy. Give\n<code>NgOptimizedImage</code> a try and see the difference in your next project!</p>\n<hr />\n<p>You can access the application used in the article on\n<a href=\"https://github.com/jzolnowski/ngoptimizedimage-demo\">GitHub</a>.</p>",
            "url": "https://devintent.com/blog/2024-11-23-level-up-your-apps-speed-with-ngoptimizedimage.md",
            "title": "Level Up Your App`s Speed with `NgOptimizedImage`",
            "summary": "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.",
            "date_modified": "2024-11-23T14:18:00.000Z",
            "tags": [
                "angular",
                "perf"
            ]
        },
        {
            "id": "blog/2024-08-20-testing-reactive-angular-components.md",
            "content_html": "<h1 id=\"testingreactiveangularcomponentsacloserlook\">Testing Reactive Angular Components: A Closer Look</h1>\n<p>In this article, we will take a look at how to test the reactive components in Angular, especially with some\nof the nifty new features that have come along. Our case study involves a component we created for\ndemonstration, <code>UsersComponent</code>. Together, we'll unpack its code and walk through the testing process,\nhighlighting on the why's and how's of each step.</p>\n<h2 id=\"gettingtoknowuserscomponent\">Getting to Know UsersComponent</h2>\n<p>First off, let's chat about our <code>UsersComponent</code>. It's a nifty standalone component designed to handle a user\nlist in a reactive manner, making good use of Angular's reactive features\nlike <a href=\"https://angular.io/api/core/Signal\">signal</a> and <a href=\"https://angular.io/guide/signals#effects\">effect()</a> for\nhandling the data and keep the UI fresh.</p>\n<pre><code class=\"typescript language-typescript\">@Component({\n  standalone: true,\n  // Component metadata...\n})\nexport class UsersComponent implements OnInit {\n  private readonly usersService = inject(UsersService);\n  readonly dataSource: MatTableDataSource&lt;User&gt; =\n    new MatTableDataSource&lt;User&gt;([]);\n  readonly users: WritableSignal&lt;User[]&gt; = signal([]);\n\n  constructor() {\n    effect(() =&gt; {\n      this.dataSource.data = this.users();\n    });\n  }\n\n  async ngOnInit(): Promise&lt;void&gt; {\n    this.users.set(await lastValueFrom(this.usersService.getUsers()));\n  }\n\n  addUser(): void {\n    const iter = this.users().length + 1;\n    this.users.update(users =&gt; [...users, newUser]);\n  }\n\n  removeUser(id: string): void {\n    this.users.update(users =&gt; users.filter((user) =&gt; user.id !== id));\n  }\n}\n</code></pre>\n<p>The constructor is where the magic starts. We've got an <code>effect()</code> that set up the stage and ensures the\n<a href=\"https://material.angular.io/components/table/overview#datasource\">MatTableDataSource</a> is always reflecting\nthe latest users' data. It keeps our UI accurately updated, no manual refreshes needed.</p>\n<p>When <a href=\"https://angular.io/api/core/OnInit\">ngOnInit()</a> kicks in, it's all about fetching the async data and\nsetting it up in the users signal. This action gets the ball rolling for the effect to do its thing and\nupdate the UI.</p>\n<p>We have also implemented methods to add a new user or take one out. The <code>addUser()</code> and <code>removeUser()</code>\nfunctions tweak the users signal, which also triggers the <code>effect()</code> to update the data source accordingly.</p>\n<h2 id=\"thehowtooftesting\">The How-To of Testing</h2>\n<p>Now, when it comes to testing these reactive Angular pieces, there's a bit of know-how involved. We need to\nunderstand several Angular-specific methods and concepts, along with strategies to avoid calls to the real\nservices. We're tackling <code>TestBed.flushEffects()</code>, the mechanics behind <code>effect()</code>, <code>signal.update()</code>,\n<code>signal.set()</code> and <code>fixture.whenStable()</code>method, not to mention Jasmine's <code>spyOn</code> to keep our service calls in\ncheck.</p>\n<h3 id=\"understandingtestbedflusheffects\">Understanding TestBed.flushEffects()</h3>\n<p>The <a href=\"https://angular.io/api/core/testing/TestBed#flushEffects\">TestBed.flushEffects()</a> method, introduced in\nrecent Angular updates (<a href=\"https://github.com/angular/angular/pull/51049/files\">PR #51049</a>\nand <a href=\"https://github.com/angular/angular/pull/53843/files\">PR #53843</a>), is super important for testing\ncomponents with effects. It ensures that all the queued effects are executed in the test environment. This is\nespecially useful for those asynchronous moments when you want to make sure everything's settled before making\nyour assertions.</p>\n<h3 id=\"thetrioeffectsignalsetandsignalupdate\">The Trio: effect(), signal.set(), and signal.update()</h3>\n<p>In our <code>UsersComponent</code>, we used the power of <code>effect()</code>,\n<a href=\"https://angular.io/api/core/WritableSignal#update\">signal.update()</a>, and\n<a href=\"https://angular.io/api/core/WritableSignal#set\">signal.set()</a> to keep things reactive and fresh.</p>\n<p>The <code>effect()</code> function allows us to create a reactive link between the users signal and\nthe <code>MatTableDataSource</code>. This means whenever the users signal changes, the <code>effect()</code> function automatically\nupdates <code>dataSource.data</code>, ensuring the UI stays in sync with the state.</p>\n<p><code>signal.set()</code> is our direct line to replace the signal's current value and kick the <code>effect()</code> into gear,\nupdating the data source with the fresh list of users.</p>\n<pre><code class=\"typescript language-typescript\">signal.set([...users, newUser]);\n</code></pre>\n<p>And for those times when you need to finesse the current signal value, <code>signal.update()</code> is the go-to,\nallowing tweaking the signal's value based on its current state. Perfect for when you want to add a new user\nwithout replacing the whole users list.</p>\n<pre><code class=\"typescript language-typescript\">signal.update(users =&gt; [...users, newUser]);\n</code></pre>\n<h3 id=\"ensuringstabilitywithfixturewhenstable\">Ensuring Stability with fixture.whenStable()</h3>\n<p>Asynchronous operations are the norm when fetching data, we need to ensure that our tests wait for these\noperations to complete. This is\nwhere <a href=\"https://angular.io/api/core/testing/ComponentFixture#whenStable\">whenStable()</a> comes into play.</p>\n<pre><code class=\"typescript language-typescript\">await fixture.whenStable();\n</code></pre>\n<p>This function returns a promise that resolves when all pending asynchronous activities within the component\nare completed. It's essential for ensuring that our assertions are made after the component has finished\nprocessing the data.</p>\n<h3 id=\"keepingitrealwithjasminespyon\">Keeping it Real with Jasmine spyOn</h3>\n<p>We definitely don't want our tests making actual calls out to the real services. So, we bring\nin <a href=\"https://jasmine.github.io/api/edge/global.html#spyOn\">Jasmine's spyOn</a> method to intercept calls to\nthe <code>UsersService.getUsers()</code> method and provide controlled, predictable responses.</p>\n<pre><code class=\"typescript language-typescript\">beforeEach(() =&gt; {\n  spyOn(usersService, 'getUsers').and.returnValue(of(mockedUsers));\n...\n});\n</code></pre>\n<p>By doing so, we simulate the service's behavior without making actual HTTP requests. This approach ensures\nthat our tests remain fast and are not affected by external factors such as network latency or service\navailability.</p>\n<h3 id=\"firingupngoninit\">Firing up ngOnInit()</h3>\n<p>We used <a href=\"https://angular.io/guide/testing-components-scenarios#detectchanges\">fixture.detectChanges()</a> to work\nin the <a href=\"https://jasmine.github.io/api/edge/global.html#beforeEach\">beforeEach</a> to get the component's lifecycle\nrolling and make sure <code>ngOnInit</code> does its thing.</p>\n<pre><code class=\"typescript language-typescript\">beforeEach(() =&gt; {\n  ...\n  fixture.detectChanges();\n});\n</code></pre>\n<p>This is essential for setting up the initial state of the component, such as bind properties or fetching the\ninitial list of users and ensures that tests have a consistent starting state, with the component fully\ninitialized and ready to respond to simulated user interactions.</p>\n<h3 id=\"divingintotestinguserscomponent\">Diving into Testing UsersComponent</h3>\n<p>Armed with our understanding of Angular's reactive features and testing methods, we're now ready to delve into\nthe unit tests for UsersComponent. Each test case is meticulously crafted to verify the component's\nfunctionality, ensuring it behaves as expected under various scenarios.</p>\n<h4 id=\"test1populatingmattabledatasourcewithusers\">Test 1: Populating MatTableDataSource with Users</h4>\n<pre><code class=\"typescript language-typescript\">it('should populate MatTableDataSource with users', async () =&gt; {\n  expect(component.dataSource.data.length)\n    .withContext('Data Source length before fetch').toBe(0);\n\n  await fixture.whenStable();\n  TestBed.flushEffects();\n\n  expect(component.users()).withContext('User list after fetch')\n    .toEqual(mockedUsers);\n  expect(component.dataSource.data.length)\n    .withContext('Data Source length after fetch').toBe(3);\n  expect(component.dataSource.data).toEqual(mockedUsers);\n});\n</code></pre>\n<p>In this test, we first assert that our data source is initially empty. After calling <code>fixture.whenStable()</code>,\nwe ensure all asynchronous operations have completed. Then, <code>TestBed.flushEffects()</code> is invoked to process any\neffects, such as those linked to our users signal. This guarantees that our UI is synchronized with the\ncurrent state. We conclude by asserting that the data source now contains the mocked users, proving that our\neffects correctly update the UI in response to the signal changes.</p>\n<h4 id=\"test2addinganewuser\">Test 2: Adding a New User</h4>\n<pre><code class=\"typescript language-typescript\">it('should add a new user', async () =&gt; {\n  const newUser = {\n    id: 'id_4',\n    username: 'user_name_4',\n    email: 'test4@email.com'\n  }\n\n  await fixture.whenStable();\n  await component.addUser();\n  TestBed.flushEffects();\n\n  expect(component.dataSource.data.length)\n    .withContext('Data Source length after new user addition').toBe(4);\n  expect(component.dataSource.data).toEqual([...mockedUsers, newUser]);\n});\n</code></pre>\n<p>This test focuses on adding a new user. We initiate by awaiting component stabilization and then invoke the\n<code>async addUser()</code> method, which updates the users signal. Post this, <code>TestBed.flushEffects()</code> is called to\ntrigger the effects that update the UI. Our assertions confirm that the data source now includes the new user,\ndemonstrating the component's dynamic response to state changes.</p>\n<h4 id=\"test3removingauser\">Test 3: Removing a User</h4>\n<pre><code class=\"typescript language-typescript\">it('should remove user', async () =&gt; {\n  await fixture.whenStable();\n  await component.removeUser('id_2');\n  TestBed.flushEffects();\n\n  expect(component.dataSource.data.length)\n    .withContext('Data Source length after user remove').toBe(2);\n  expect(component.dataSource.data[1].id).toBe('id_3');\n});\n</code></pre>\n<p>In the final test, we validate the removal of a user. After stabilizing the component, we call <code>removeUser()</code>,\nupdating the users signal. Following this with <code>TestBed.flushEffects()</code> ensures our effects process this\nchange. The assertions then verify that the data source has been updated to reflect the removal of the\nspecified user, again highlighting the reactive nature of our component.</p>\n<h4 id=\"puttingitalltogether\">Putting it All Together</h4>\n<p>Here's the complete overview of our UsersComponent tests:</p>\n<pre><code class=\"typescript language-typescript\">describe('UserListComponent', () =&gt; {\n  let component: UsersComponent;\n  let usersService: UsersService;\n  let fixture: ComponentFixture&lt;UsersComponent&gt;;\n  const mockedUsers: User[] = [\n    {\"id\": \"id_1\", \"username\": \"user_name_1\", \"email\": \"test1@email.com\"},\n    {\"id\": \"id_2\", \"username\": \"user_name_2\", \"email\": \"test2@email.com\"},\n    {\"id\": \"id_3\", \"username\": \"user_name_3\", \"email\": \"test3@email.com\"}\n  ];\n\n  beforeEach(async () =&gt; {\n    await TestBed.configureTestingModule({\n      imports: [UsersComponent, NoopAnimationsModule, HttpClientTestingModule],\n      providers: [UsersService],\n    }).compileComponents();\n\n    usersService = TestBed.inject(UsersService);\n    fixture = TestBed.createComponent(UsersComponent);\n    component = fixture.componentInstance;\n  });\n\n  beforeEach(() =&gt; {\n    spyOn(usersService, 'getUsers').and.returnValue(of(mockedUsers));\n    fixture.detectChanges();\n  });\n\n  it('should create', () =&gt; {\n    expect(component).toBeTruthy();\n  });\n\n  it('should initialize with default values', () =&gt; {\n    expect(component.isLoading()).toBeTruthy();\n    expect(component.dataSource.data.length).toBe(0);\n    expect(component.displayedColumns.length).toBe(4);\n  });\n\n  it('should populate MatTableDataSource with users', async () =&gt; {\n    expect(component.dataSource.data.length)\n      .withContext('Data Source length before fetch').toBe(0);\n\n    await fixture.whenStable();\n    TestBed.flushEffects();\n\n    expect(component.users()).withContext('User list after fetch')\n      .toEqual(mockedUsers);\n    expect(component.dataSource.data.length)\n      .withContext('Data Source length after fetch').toBe(3);\n    expect(component.dataSource.data).toEqual(mockedUsers);\n  });\n\n  it('should add a new user', async () =&gt; {\n    const newUser = {\n      id: 'id_4',\n      username: 'user_name_4',\n      email: 'test4@email.com'\n    }\n\n    await fixture.whenStable();\n    await component.addUser();\n    TestBed.flushEffects();\n\n    expect(component.dataSource.data.length)\n      .withContext('Data Source length after new user addition').toBe(4);\n    expect(component.dataSource.data).toEqual([...mockedUsers, newUser]);\n  });\n\n  it('should remove user', async () =&gt; {\n    await fixture.whenStable();\n    await component.removeUser('id_2');\n    TestBed.flushEffects();\n\n    expect(component.dataSource.data.length)\n      .withContext('Data Source length after user remove').toBe(2);\n    expect(component.dataSource.data[1].id).toBe('id_3');\n  });\n});\n</code></pre>\n<h2 id=\"wrappingup\">Wrapping Up</h2>\n<p>I hope you found our stroll through <code>UsersComponent</code> testing as insightful as it was enjoyable. Testing,\nespecially with Angular's latest reactive features, doesn't have to be a pain in the neck. Actually, it's\nquite the opposite—it's a smooth, straightforward, and enjoyable task.</p>\n<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\ntests not just necessary but a piece of cake. With the right approach and understanding, testing becomes\nless of a chore and more of an exciting part of the development process.</p>\n<p>Incorporating these new features into our testing routine has shown us that it's not just about ensuring our\ncomponents are up to snuff. It's about embracing a more dynamic and enjoyable workflow. The tests we've walked\nthrough exemplify this mindset, proving that with Angular's advanced capabilities, we're fully equipped to\nhandle any reactive challenges that come our way, all with a smile.</p>\n<p>So, let's shake off any old notions that testing is a drag. With Angular's reactive features, we're ushering\nin a new era of testing that's efficient, effective, and, dare I say, fun :)</p>\n<p><br>\n<br></p>\n<p>You can find access to the working application and tests on\n<a href=\"https://github.com/jzolnowski/signal-testing\">GitHub</a>.</p>",
            "url": "https://devintent.com/blog/2024-08-20-testing-reactive-angular-components.md",
            "title": "Testing Reactive Angular Components - A Closer Look",
            "summary": "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.",
            "date_modified": "2024-08-20T12:30:00.000Z",
            "tags": [
                "angular",
                "testing"
            ]
        },
        {
            "id": "blog/2024-08-19-the-progressive-journey-of-change-detection-in-angular.md",
            "content_html": "<h2 id=\"introduction\">Introduction</h2>\n<p>In this article, we'll delve into the evolution of Angular's change detection strategies, exploring how\nthey've transformed our applications to be more responsive and effective. Angular has made significant strides\nfrom the global\ntop-down <a href=\"https://angular.dev/best-practices/skipping-subtrees#an-event-is-handled-by-a-component-with-default-change-detection\">Default</a>\napproach to the widely\nembraced <a href=\"https://angular.dev/best-practices/skipping-subtrees#an-event-is-handled-by-a-component-with-onpush\">OnPush</a>\nstrategy. However, the introduction of Signals-based methodology, as outlined in\nthe <a href=\"https://angular.dev/guide/signals\">Angular documentation</a> promises even more significant efficiency gains\nin the change detection.</p>\n<p>We'll explore the general inner workings of these strategies and analyze the performance gaps between them.\nFurthermore, we'll speculate on the direction of Angular's change detection mechanisms.\nSo, let's get started!</p>\n<h2 id=\"earlystage\">Early Stage</h2>\n<p>Change detection kicks off with any asynchronous browser events, and Angular relies on\nthe <a href=\"https://github.com/angular/angular/blob/main/packages/core/src/zone/ng_zone.ts#L96\">NgZone</a> module to\nobserve these interactions. When an async event occurs, Angular triggers the change detection process,\ntraversing the <a href=\"https://github.com/angular/angular/blob/17.1.3/packages/core/src/render3/view_ref.ts\">view</a>\ntree from top to bottom. However, there's a contrast in how components are marked for update across various\nstrategies</p>\n<h2 id=\"oldschoolchangedetection\">Old-School Change detection</h2>\n<p>Back in the early days, Angular's default change detection was like a noisy neighbor. It kept an eye on every\ncomponent, binding, and dependency whenever any event happened, leading to updates throughout the entire\napplication. This method works, but it often leads to performance issues in bigger apps because it tends to\nperform checks even when everything has stayed the same.</p>\n<h3 id=\"defaultchangedetectioninaction\">Default Change Detection in Action</h3>\n<p>With the default change detection strategy, Angular keeps an eye on all components unless the view is\nexplicitly <a href=\"https://github.com/angular/angular/blob/main/packages/core/src/render3/view_ref.ts#L200-L202\">detached</a>:</p>\n<pre><code class=\"typescript language-typescript\">@Component({\n  selector: 'detached',\n  template: `Detached Component`\n})\nexport class DetachedComponent {\n  constructor(private cdr: ChangeDetectorRef) {\n    cdr.detach();\n  }\n}\n</code></pre>\n<p>This strategy relies on the <code>CheckAlways</code> flag:</p>\n<pre><code class=\"typescript language-typescript\">let shouldRefreshView: boolean = !!(\n  mode === ChangeDetectionMode.Global &amp;&amp; flags &amp; LViewFlags.CheckAlways\n);\n</code></pre>\n<p>which ensures that Angular performs change detection on every view and executes\nthe <a href=\"https://github.com/angular/angular/blob/21741384f4/packages/core/src/render3/VIEW_DATA.md?plain=1#L90-L109\">template function</a>\nregardless of whether there are changes or not.</p>\n<p>[<img src=\"/blog/change-detection-1/2-default-change-detection.png\" alt=\"Default Change Detection\" /></p>\n<p>Click on component \"H,\" which creates a domino effect throughout the entire app, even when it's just a false\nalarm.</p>\n<h2 id=\"arelaxedapproachtochangedetection\">A Relaxed Approach to Change Detection</h2>\n<p>To speed things up, Angular brought in the OnPush change detection strategy. The OnPush option has been around\njust as long as the Default one. But to switch it on, developers needed to give their components a heads-up,\nletting them know they wanted to use it. OnPush is like a more discerning detective, only springing into\naction when a component's inputs change or events occur within that component. This optimized approach relied\non immutable states and reduced unnecessary checks, making our apps more straightforward and faster.\nSo, how does it work?</p>\n<h3 id=\"unpackingtheonpushchangedetectionstrategy\">Unpacking the OnPush Change Detection Strategy</h3>\n<p>With the OnPush strategy, change detection takes a back seat unless a component is flagged as dirty:</p>\n<pre><code class=\"typescript language-typescript\">shouldRefreshView ||= !!(\n  flags &amp; LViewFlags.Dirty &amp;&amp;\n  mode === ChangeDetectionMode.Global &amp;&amp;\n  !isInCheckNoChangesPass\n);\n</code></pre>\n<p>To mark that a component as dirty, we can change an input property, emit an event, or manually\ninvoke the\n<a href=\"https://github.com/angular/angular/blob/17.1.3/packages/core/src/render3/instructions/mark_view_dirty.ts#L24-L37\">markForCheck()</a>\nmethod, which marks the current view and all its folks up the family tree, all the way to the root view, for a\nthorough check.</p>\n<pre><code class=\"typescript language-typescript\">@Component({\n  selector: 'dirty',\n  template: `Dirty Component`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DirtyComponent {\n  constructor(private cdr: ChangeDetectorRef) {\n    cdr.markForCheck();\n  }\n}\n</code></pre>\n<p>Angular then takes a tour of each dirty flagged view, executing the template function associated with its\nrespective component.</p>\n<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>\n<p>With OnPush, a click in the component \"H\" triggers an event through clicked component itself and its parents.</p>\n<h2 id=\"signalsera\">Signals Era</h2>\n<p>From <a href=\"https://blog.angular.io/angular-v16-is-here-4d7a28ec680d\">Angular v16</a> onwards, Angular has been moving\ntowards adopting <a href=\"https://github.com/angular/angular/discussions/49683\">Signals</a>, altering front-end state\nmanagement. Unfortunately, as of <a href=\"https://blog.angular.io/introducing-angular-v17-4d7033312e4b\">version 17</a>\n, <a href=\"https://github.com/angular/angular/discussions/49682\">Signal-based Components</a> remain under development,\ndelaying the full implementation of Signal-based change detection. In the meantime, Angular allowed us to\nutilize the power of Signals and OnPush strategy to mark individual components as dirty. This Local Change\nDetection ensures no more unnecessary checks for parent or child components designated as OnPush.</p>\n<p>Additionally, Angular's recent advancements in event detection include\nimplementing <a href=\"https://github.com/angular/angular/pull/53521\">signal inputs</a>, where input value updates occur\nbefore the change detection cycle. This improvement ensures that change detection does not execute if the\ntemplate doesn't use the input. Moreover, changing the value bound to an input no longer triggers a refresh of\nthe parent view, as with the OnPush strategy.</p>\n<h3 id=\"streamliningchangedetectionwithsignals\">Streamlining Change Detection with Signals</h3>\n<p>When we change the signal within a component's template using methods\nlike <a href=\"https://github.com/angular/angular/blob/f56b6555bd5d4498c0b2e4e406c220213d70e274/packages/core/src/signals/src/signal.ts#L30\">set()</a>\nor <a href=\"https://github.com/angular/angular/blob/f56b6555bd5d4498c0b2e4e406c220213d70e274/packages/core/src/signals/src/signal.ts#L36\">update()</a>\n, we kick off a chain reaction. This signal\n<a href=\"https://github.com/angular/angular/blob/17.1.3/packages/core/primitives/signals/src/graph.ts#L292-L309\">triggers a notification</a>\nto the reactive live consumer within the view, marking it as dirty through the\n<a href=\"https://github.com/angular/angular/blob/main/packages/core/src/render3/util/view_utils.ts#L233C17-L249\">markAncestorsForTraversal()</a>.\nBut it doesn't stop there – it also marks all ancestors, up to the root, with the <code>HasChildViewsToRefresh</code>\nflag. If the view is marked as dirty, the template function is called, and the current value is returned.</p>\n<pre><code class=\"typescript language-typescript\">shouldRefreshView ||= !!(\n  consumer?.dirty &amp;&amp; consumerPollProducersForChange(consumer)\n);\n</code></pre>\n<p>However, if the view is marked with the <code>HasChildViewsToRefresh</code> flag, there's no need to bother with the\ntemplate function. It just takes a shortcut, skipping the template function and diving right into checking the\nchildren. This clever move helps Angular avoid unnecessary tasks, operations, calculations, and comparisons,\nensuring everything runs smoothly and efficiently.</p>\n<pre><code class=\"typescript language-typescript\">if (shouldRefreshView) {\n  refreshView(tView, lView, tView.template, lView[CONTEXT]);\n} else if (flags &amp; LViewFlags.HasChildViewsToRefresh) {\n  detectChangesInEmbeddedViews(lView, ChangeDetectionMode.Targeted);\n  const components = tView.components;\n  if (components !== null) {\n    detectChangesInChildComponents(lView, components,\n      ChangeDetectionMode.Targeted);\n  }\n}\n</code></pre>\n<h2 id=\"thefuture\">The future</h2>\n<p>Looking ahead, Angular seems set to embrace a Signals-based Change Detection system fully. It's like getting a\nsuperpower to track changes with laser precision, eliminating the need for NgZone to manage execution context\ncompletely. By going zone-less, developers will have better, fine-grained control over change detection,\nenabling a more efficient and focused approach and optimizing performance even further by running Change\nDetection only when necessary. This approach will fundamentally change how Angular tracks and handles changes,\nallowing developers to pinpoint precisely where and when updates should occur.</p>\n<p>However, transitioning to this new paradigm requires developers to understand signals better to harness their\nfull potential. Despite the learning curve, the performance and scalability gains make it a worthwhile\ninvestment for projects aiming for optimal performance.</p>\n<p>As Angular continues to evolve, developers must stay updated with these advancements in Change detection\nstrategies.</p>\n<p>The journey from the default strategy through OnPush and towards Signals-based Change Detection highlights\nAngular's commitment to enhancing performance and scalability. By adopting these advanced strategies,\ndevelopers are empowered to build functional and exceptionally performant Angular applications.</p>\n<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>\n<p>In the world of Local Change Detection, a change in component \"F\" gets the attention it deserves without\nredundantly checking parent or component children.</p>\n<h2 id=\"conclusions\">Conclusions</h2>\n<p>In conclusion, the evolution of change detection in Angular reflects a constant effort to refine and optimize\nperformance. Embracing these advancements empowers developers to create Angular applications that are not just\nfunctional but also highly performant, ensuring a seamless user experience across a wide range of\napplications. Given the progress that has been made in this regard, I look forward with optimism to further\nreleases of the Angular framework.</p>\n<p><br>\n<br></p>\n<p>The principle of change detection can be viewed in\nthis <a href=\"https://github.com/jzolnowski/deep-dive-into-change-detection\">GitHub application</a>.</p>",
            "url": "https://devintent.com/blog/2024-08-19-the-progressive-journey-of-change-detection-in-angular.md",
            "title": "The Progressive Journey of Change Detection in Angular",
            "summary": "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.",
            "date_modified": "2024-08-19T17:15:00.000Z",
            "tags": [
                "angular"
            ]
        },
        {
            "id": "blog/2023-09-26-build-time-benchmarking-using-angular-cli.md",
            "content_html": "<h1 id=\"buildtimebenchmarkofmonolithicapplicationbuildusingangularcli\">Build time benchmark of monolithic application build using Angular CLI</h1>\n<p>In this article, we’ll take a look at the impact of different build options of\nthe Angular CLI on the build time of a monolithic application. Building is\nusually on a critical path of the continuous integration (CI) pipeline—that is,\nany changes to build duration impact the total CI time. The Angular team makes\na few build optimizations available for developers, and in this post, we’ll\ntake a look at their impact.</p>\n<h2 id=\"measurements\">Measurements</h2>\n<p>To make the data reproducible and relevant, I’ll run the test builds with\nCircleCI. Using external servers for the build isolates the measurement from my\nlocal environment. At the same time, the results come from machines that others\nare using for building as well.</p>\n<p>The key measurement I’ll pay attention to is the time needed to run the <code>npm\nrun build</code> command:</p>\n<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>\n<p>At this level, I expect to see the most direct results of the optimization we\nuse. If we manage to cut the build time in half, then we should see this impact\nhere.</p>\n<p>Another value to consider is the time of a whole build job. This will be\nespecially important for optimizations that come with positives and negatives:\nfor example, caching can speed up some operations, but part of the gain will be\neaten by the downloading and uploading cache.</p>\n<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>\n<p>The last measurement for us to consider is the overhead: the difference between\nbuild script and build job. It will contain everything that is done before or\nafter the build: restoring the cache, installing dependencies, saving the\ncache. With this number, we should see clearly the downsides of some\noptimization.</p>\n<p>I’ll repeat each test build 5 times under the same circumstances and use the\naverage of the measurements as the measurement value. In this way, I’ll be able\nto reduce a bit of random noise in the data without turning it into a full\nscientific experiment.</p>\n<h2 id=\"applicationstructure\">Application structure</h2>\n<p>As a benchmark, I’m using the build time of a simple application generated and\nbuilt with the Angular CLI. The application models the real world complexity by\nincluding 1000 components. This approach is inspired by <a href=\"https://github.com/nrwl/nx-incremental-large-repo\">Nrwl’s Angular\nbenchmark</a>. Each component\nis very simple:</p>\n<p><code>src/app/component1/component1.component.ts</code>:</p>\n<pre><code class=\"js language-js\">import { Component } from '@angular/core';\n\n@Component({\n  selector: 'app-component1',\n  templateUrl: './component1.component.html',\n  styleUrls: ['./component1.component.css']\n})\nexport class Component1Component {\n\n}\n</code></pre>\n<p><code>src/app/component1/component1.component.html</code>:</p>\n<pre><code class=\"html language-html\">&lt;p&gt;component1 works!&lt;/p&gt;\n</code></pre>\n<p>And the whole application just displays each component one after another:</p>\n<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>\n<p>The biggest blind spot is the lack of third-party libraries. This is something\nthat almost all real-world applications do, but including it in the benchmark\nwould tie the results to the set of libraries used in the example application.</p>\n<h2 id=\"buildoptions\">Build options</h2>\n<p>In my test, I’m measuring the build time in the following setups.</p>\n<h3 id=\"baseline\">Baseline</h3>\n<p>This is the standard build as it’s generated by Angular CLI. Important features are as follows:</p>\n<ul>\n<li>it uses webpack under the hood</li>\n<li>it lacks <code>ng cache</code> for CI—so each build during CI starts from scratch</li>\n<li>the build job provides cache for <code>npm install</code></li>\n</ul>\n<h3 id=\"esbuild\">esbuild</h3>\n<p>esbuild is a promising bundler with much better performance than Webpack:\naccording to its own website, it’s up to 100 times faster. Because of its\nspeed, since version 14, the Angular team has provided an experimental builder\nbased on esbuild. It was recently improved in version 15. It can be turned on\neasily, with just 1 line change in <code>angular.json</code>:</p>\n<pre><code>       \"architect\": {\n         \"build\": {\n-          \"builder\": \"@angular-devkit/build-angular:browser\",\n+          \"builder\": \"@angular-devkit/build-angular:browser-esbuild\",\n           \"options\": {\n</code></pre>\n<p>Note! So far, this change affects only the build—the development server is\nstill using Webpack. This is likely to change in version 16.</p>\n<h3 id=\"ngcaching\">ng caching</h3>\n<p>For local builds, Angular CLI caches build results to save time on reruns. By\ndefault, this feature is turned off for CI. To use caching during CI, we need\ntwo changes:</p>\n<ul>\n<li>changing the cache configuration from local-only, and</li>\n<li>reading and saving the cache during CI.</li>\n</ul>\n<p>You can turn on caching with two commands:</p>\n<pre><code>ng config cli.cache.environment all\nng cache enable\n</code></pre>\n<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>\n<h3 id=\"typescript5\">TypeScript 5</h3>\n<p>TypeScript 5 promises up to 10% improvement for the build time. It’s not yet\navailable for Angular applications, but it’s on track to come in version 16.\nFor my tests, I’m updating Angular to pre-release version <code>16.0.0-next.4</code>.</p>\n<h2 id=\"data\">Data</h2>\n<p>The builds I’ve run measured as follows:</p>\n<p>|                  | npm run build (s) | Build job (s) | Overhead  (s) |\n|------------------|-------------------|---------------|---------------|\n| baseline         | 57.8              | 92            | 34.2          |\n| esbuild          | 14.4              | 50.2          | 35.8          |\n| hot build cache  | 31.4              | 67            | 35.6          |\n| cold build cache | 66.8              | 104.2         | 35.6          |\n| TypeScript 5     | 55                | 84.8          | 29.8          |</p>\n<p>The baseline time needed to complete <code>npm run build</code> was on average 57.8s. The\nbiggest improvement we can see is with switching to <code>esbuild</code>: it becomes 4\ntimes faster and takes only 14.4s to build. Both builds have very similar\noverhead. With esbuild, the build job takes 56% of time that was needed in the\nbaseline case—an excellent improvement.</p>\n<p>Another optimization—caching of the Webpack build—looks very promising as well.\nBecause there are more files cached, I expected a clear increase in the\noverhead. It went from 34.2s to 35.6s, but this difference could be\nstatistically insignificant. Caching of the build has two effects:</p>\n<ul>\n<li>speed increases when cache is “hot”—with files already in place, the build\njob finishes in 31.4s instead of 57.8s.</li>\n<li>speed decreases when the cache is “cold”—most likely, the build takes more\ntime because there are way more files to be written on the disk. Build went\nup from 57.8s to 66.8s.</li>\n</ul>\n<p>Lastly, an interesting case is updating to TypeScript 5. The time needed to\ncomplete the npm run build lowered slightly from 57.8s to 55.5s. At the same\ntime, the overall build job took 84.5s instead of 92s, which is a better\nimprovement than the build script alone. This could be explained by the more\nefficient installation—maybe TypeScript 5 or other v16 dependencies are faster\nto install.</p>\n<h2 id=\"conclusions\">Conclusions</h2>\n<ol>\n<li>Check out esbuild—if it won’t introduce regressions to your code, you can\nimmediately enjoy faster builds!</li>\n<li>If esbuild doesn't work in your case, try enabling caching for Webpack on\nCI.</li>\n<li>Don’t hold your breath for the speed increase that comes with switching to\nTypeScript 5.</li>\n</ol>\n<h2 id=\"links\">Links</h2>\n<p>You can find our test application <a href=\"https://github.com/DevIntent/ng-build-monolithic\">here</a>.</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in web development, including\nframework migration and updates. Check out our <a href=\"https://www.devintent.com/\">offerings</a>\nor <a href=\"https://www.devintent.com/contact-us\">reach out</a>.</p>",
            "url": "https://devintent.com/blog/2023-09-26-build-time-benchmarking-using-angular-cli.md",
            "title": "Build time benchmarking using Angular CLI",
            "summary": "Build time benchmarks of various configurations in the Angular CLI.",
            "date_modified": "2023-09-26T12:30:00.000Z",
            "tags": [
                "angular"
            ]
        },
        {
            "id": "blog/2023-05-01-angular-v-16-features-and-improvements-we-re-excited-about.md",
            "content_html": "<p>With Angular version 15 released on November 16 and the next version expected\nbefore summer, let’s see what upcoming changes look the most exciting.</p>\n<h2 id=\"newbundlers\">New bundlers</h2>\n<p>A lot of optimization in Angular happens at build time. For this to be\npossible, Angular provides a custom compiler. The compiler takes care of things\nspecific to Angular: ahead-of-time compilation or catching issues in the\ntemplates. The build is complex, but Angular CLI provides you all the\nconfiguration you need. Under the hood, Angular CLI uses Webpack, a well\nestablished bundler with a very active community.</p>\n<p>While Webpack is the most popular bundler available, it has its\ndownsides—especially speed when it builds larger codebases. Whereas Webpack is\nin active development and there are incremental improvements in speed between\nversions, there are other bundlers that take a fundamentally different approach\nand boast greatly improved speeds. A slower bundler causes slower builds, and\nthis can negatively affect productivity in the project at all stages—from\ndevelopment to continuous integration.</p>\n<p>To allow the Angular community to enjoy the benefits of faster bundlers,\nthe Angular CLI has offered an experimental esbuild configuration since\n<a href=\"https://blog.angular.io/angular-v14-is-now-available-391a6db736af#43b4\">version 14</a>,\nand it’s been\n<a href=\"https://dev.to/fabiobiondi/angular-esbuild-2540-build-time-3mfa\">reported</a> to\nlower build time by up to 44%. The\n<a href=\"https://angular.io/guide/roadmap#investigate-modern-bundles\">Roadmap</a> also\nlists further investigation and progress toward making the improved builds\nstable, so we hope to see continued speed increases coming to applications\nbuilt with the Angular CLI.</p>\n<h2 id=\"furtherdevelopmentoftheimagedirective\">Further development of the image directive</h2>\n<p>Due to their size, images have a disproportionately large impact on web\nperformance. Managing them well is especially important for the mobile user\nexperience for a couple of reasons:</p>\n<ul>\n<li>When on the go, mobile users can experience slower and less stable internet\nconnections or may be charged for the data transfer.</li>\n<li>Because of their often smaller screens, images on mobile devices don’t need\nthe same high resolution as desktop users.</li>\n</ul>\n<p>Managing images well can be difficult, especially in applications rendered on\nthe client side. Improvements to image management for both users and developers\nare welcome. So it’s promising to\n<a href=\"https://angular.io/guide/roadmap#improvements-in-the-image-directive\">see on the roadmap</a>\nfurther enhancements to <a href=\"https://angular.io/api/common/NgOptimizedImage\">NgOptimizedImage</a>\nthat the Angular team plans to add to the framework.</p>\n<h2 id=\"debuggingdependencyinjection\">Debugging dependency injection</h2>\n<p>In my AngularJS development work, I often use this snippet to access my\nservices from the dev tools console:</p>\n<pre><code class=\"js language-js\"> angular.element(document.body).injector().get('serviceName')\n</code></pre>\n<p>I find it very helpful to be able to test my methods interactively in the\nbrowser as I develop them. For that reason, I’m looking forward to seeing the\nupdates in Angular DevTools that will bring\n<a href=\"https://angular.io/guide/roadmap#introduce-dependency-injection-debugging-apis\">dependency injection debugging APIs</a>.</p>\n<h2 id=\"upcomingchanges\">Upcoming changes</h2>\n<p>Those are the changes I’m the most excited about in that are on the way to\nbecoming part of Angular v16. You can find the list of priorities for the\ncurrent development in the project’s <a href=\"https://angular.io/guide/roadmap\">roadmap</a>.</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in Angular development, testing,\nand software quality. If you'd like to chat about how we can help you, please\ncontact us at sales@devintent.com.</p>",
            "url": "https://devintent.com/blog/2023-05-01-angular-v-16-features-and-improvements-we-re-excited-about.md",
            "title": "Angular v16 Features And Improvements We’re Excited About",
            "summary": "Some of our favorite improvements coming in the new release.",
            "date_modified": "2023-05-01T12:30:00.000Z",
            "tags": [
                "angular"
            ]
        },
        {
            "id": "blog/2023-04-28-how-to-speed-up-your-web-application-with-brotli-compression.md",
            "content_html": "<p>Lossless compression is a great way of lowering the amount of data that users\nhave to download to access your application. Minimizing data transfer improves\nseveral critical metrics of your application:</p>\n<ul>\n<li>The load time of the application will be lowered, improving your users’\noverall experience—this is important for users with a slow internet\nconnection, which is critical for applications primarily used on mobile\ndevices.</li>\n<li>The amount of data transferred out of your servers—which can impact your\ncloud or data center cost, depending on the use case and hosting setup.</li>\n</ul>\n<h2 id=\"introducingbrotli\">Introducing Brotli</h2>\n<p>Currently, Brotli is the most efficient compression algorithm for website code.\nAccording to <a href=\"https://www.opencpu.org/posts/brotli-benchmarks/\">benchmarks</a>,\nHTML, CSS, and JS files are more than 10% smaller when compressed with Brotli\ncompared to traditional GZIP. Brotli offers better results and is supported\nacross all modern browsers—in most cases, it should be the go-to solution for\ncompressing website data.</p>\n<h2 id=\"whoseresponsibilityisittocompressthefiles\">Whose responsibility is it to compress the files?</h2>\n<p>Isn’t compression something done automatically by your hosting provider? It can\nbe, but there are few downsides to depending on a third party to compress the\napplication:</p>\n<ul>\n<li>Compressing files is fast, but doing it when users request the files will\nintroduce unnecessary delay. It’s safe to assume this is what happens when\nyou are using compression support provided by hosting.</li>\n<li>You are limited to what is provided by the hosting company. GZIP may be the\nonly option, which will produce files bigger than those compressed with\nBrotli.</li>\n</ul>\n<p>As an alternative to automatic compression provided by hosting, you can\ngenerate <code>.br</code> files every time you build your app for deployment. In this way,\nyou can ensure that <code>.br</code> files are up to date and ready on the server when\nneeded—and that the user experience will not be affected by slow compression.\nDepending on your hosting setup, there will be different ways to configure your\nserver to use <code>.br</code> files for user agents that accept Brotli.</p>\n<h2 id=\"howtosetupbrotliinyourangularbasedapplication\">How to set up Brotli in your Angular-based application</h2>\n<p>If you are interested in using Brotli for your AngularJS or Angular application, our team recently\npublished a guide on the XLTS.dev blog\n<a href=\"https://xlts.dev/blog/2023-01-25-how-to-efficiently-serve-an-angularjs-app-using-brotli\">here</a>.</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in Angular development, testing,\nand software quality. If you'd like to chat about how we can help you, please\ncontact us at sales@devintent.com.</p>",
            "url": "https://devintent.com/blog/2023-04-28-how-to-speed-up-your-web-application-with-brotli-compression.md",
            "title": "How To Speed Up Your Web Application With Brotli Compression",
            "summary": "Overview of Brotli—compression optimized for web documents.",
            "date_modified": "2023-04-28T21:00:00.000Z",
            "tags": [
                "perf",
                "ux"
            ]
        },
        {
            "id": "blog/2023-01-23-release-of-angular-15.md",
            "content_html": "<p>On November 16, 2022, the Angular team published version 15 of the framework.\nLet’s look at what changes are available in the newest version.</p>\n<h2 id=\"standalonecomponents\">Stand-alone Components</h2>\n<p>Stand-alone components are components that are defined outside any NgModule.\nThey are providing a simplified API that reduces the boilerplate necessary to\ndefine a component. Stand-alone components, directives and pipes integrate\nnicely with the existing Angular landscape. They</p>\n<ul>\n<li>can be used in traditional modules,</li>\n<li>can import modules to reuse existing code, and</li>\n<li>can even be used to bootstrap an application.</li>\n</ul>\n<p>You can learn more in the <a href=\"https://angular.io/guide/standalone-components\">official guide</a>.</p>\n<h2 id=\"newtreeshakeableapis\">New Tree-shakeable APIs</h2>\n<p>Along with the stand-alone components, some services are available in a lighter\nform that works better with tree shaking. These APIs will help you keep your\nreusable code smaller—instead of including entire modules with all the features\nyou don’t use. Thus, you can pick only the things that you need. All the rest\nis dropped during the build process with tree shaking.</p>\n<h3 id=\"router\">Router</h3>\n<p><a href=\"https://angular.io/api/router/provideRouter\"><code>provideRouter</code></a> allows you to\npick various <a href=\"https://angular.io/api/router/RouterFeatures\">features</a> of the\nrouter to optimize your build size:</p>\n<pre><code class=\"ts language-ts\">type RouterFeatures = PreloadingFeature | DebugTracingFeature | InitialNavigationFeature | InMemoryScrollingFeature | RouterConfigurationFeature;\n</code></pre>\n<h3 id=\"httpclient\"><code>HttpClient</code></h3>\n<p>Similarly,\n<a href=\"https://angular.io/api/common/http/provideHttpClient\"><code>provideHttpClient</code></a>\nallows you to choose from the following\n<a href=\"https://angular.io/api/common/http/HttpFeatureKind\">features</a>:</p>\n<pre><code class=\"ts language-ts\">enum HttpFeatureKind {\n  Interceptors\n  LegacyInterceptors\n  CustomXsrfConfiguration\n  NoXsrfProtection\n  JsonpSupport\n  RequestsMadeViaParent\n}\n</code></pre>\n<h2 id=\"imagedirective\">Image Directive</h2>\n<p>The <a href=\"https://angular.io/api/common/NgOptimizedImage\">NgOptimizedImage</a> directive\nhas become stable. The directive enforces best practices in loading images,\nimproving the page's load performance.</p>\n<p>Together with an <a href=\"https://angular.io/api/common/ImageLoader\">ImageLoader</a>, it\ncan be used to generate the appropriate resource URL for a given image file.\nYou can learn more about this (including plans for the future) on the Chrome blog in\n<a href=\"https://developer.chrome.com/blog/angular-image-directive/\">Optimizing Images with the Angular Image Directive</a>.</p>\n<h2 id=\"directivecompositionapi\">Directive Composition API</h2>\n<p>As of version 15, Angular allows you to reuse existing directives as building\nblocks when creating new directives or components. With\n<a href=\"https://angular.io/api/core/Directive#hostDirectives\"><code>hostDirectives</code></a>, you\ncan add directives to your host element, effectively combining a few directives\ninto one. It is similar to how some languages support multiple inheritance in\nclasses. You can learn more, including performance implications, in the\n<a href=\"https://angular.io/guide/directive-composition-api\">official guide</a>.</p>\n<h2 id=\"migrationofangularmaterialcomponentstonewcomponentsbasedonmdc\">Migration of Angular Material Components to new components based on MDC</h2>\n<p>The Angular team migrated the Angular Material components to reuse\nframework-independent code available in <a href=\"https://github.com/material-components/material-components-web\">Material Design Components for the\nWeb</a> (\"MDC\"). This\nresults in an improvement in how close the components are following the\n<a href=\"https://m2.material.io/\">Material Design 2</a> specification; in the future, it will allow for switching styling\nto <a href=\"https://m3.material.io/\">Material Design 3</a>.</p>\n<p>If you overwrite many styles in Angular Material components, be prepared for\na large amount of refactoring. Migration requires changing the internal DOM structure and\nstyling of the components, as well as some changes to the external API. You can\nlearn more about what was changed and what updates are needed in the application in\n<a href=\"https://github.com/angular/components/blob/main/guides/v15-mdc-migration.md\">the MDC migration guide</a>.\nThe previous components are deprecated, but are still available to smoothen the\nmigration.</p>\n<h2 id=\"deprecatedfeatures\">Deprecated Features</h2>\n<p>Besides new additions to the framework, a few things were deprecated and will\nbe removed in a future version. If you are using any of the features below in\nyour apps, you should start making plans to move away from them.</p>\n<h3 id=\"angularflexlayout\"><code>@angular/flex-layout</code></h3>\n<p>The Angular team will stop releasing new versions of <code>@angular/flex-layout</code> — but\nthey will publish security and browser compatibility updates for the following\nyear. Instead, there are two alternatives available in pure CSS:</p>\n<ul>\n<li><a href=\"https://developer.mozilla.org/docs/Web/CSS/CSS_Flexible_Box_Layout\">flexbox</a></li>\n<li><a href=\"https://developer.mozilla.org/docs/Web/CSS/grid\">grid</a></li>\n</ul>\n<p>You can find the official recommendations in the article on the Angular blog in\n<a href=\"https://blog.angular.io/modern-css-in-angular-layouts-4a259dca9127\">Modern CSS in Angular: Layouts</a>.</p>\n<h3 id=\"providedinanyandprovidedinngmodule\"><code>providedIn: any</code> and <code>providedIn: NgModule</code></h3>\n<p>Both options were decided to be uncommon and confusing enough to be deprecated.\nIf you use them, check the official <a href=\"https://blog.angular.io/angular-v15-is-now-available-df7be7f2f4c8#05d0\">release\nannouncement</a>\nto see the way forward. We will no longer be able to register services in lazy\nloaded modules using <code>providedIn: NgModule</code>, but only by using an old fashion\ntechnique—using the <code>NgModule.providers</code> array.</p>\n<h2 id=\"updateguide\">Update Guide</h2>\n<p>As always, you can find relevant update instructions in the <a href=\"https://update.angular.io/\">Angular Update\nGuide</a>.</p>\n<h2 id=\"angularv1510update\">Angular v15.1.0 update</h2>\n<h3 id=\"selfclosingtagsfornonnativehtmlelements\">Self-closing Tags for Non-native HTML Elements</h3>\n<p>Starting with version 15.1.0, Angular supports self-closing tags for non-native\nHTML elements (including Angular components). This will allow decluttering your\ntemplates by omitting closing tags. For example, you can replace\n<code>&lt;my-component&gt;&lt;/my-component&gt;</code> with just <code>&lt;my-component /&gt;</code>.</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in web development, including\nframework migration and updates.  Check out our <a href=\"https://www.devintent.com\">offerings</a> or\n<a href=\"https://www.devintent.com/contact-us\">reach out</a>.</p>",
            "url": "https://devintent.com/blog/2023-01-23-release-of-angular-15.md",
            "title": "Highlighting the Release of Angular v15",
            "summary": "What's new in the latest Angular release.",
            "date_modified": "2023-01-23T21:00:00.000Z",
            "tags": [
                "angular"
            ]
        },
        {
            "id": "blog/2023-01-20-better-way-to-share-components-in-angular.md",
            "content_html": "<h2 id=\"introduction\">Introduction</h2>\n<p>In order for large web applications to be scalable, they are usually broken up into a number of modules.\nVery often, we need to reuse individual <a href=\"https://angular.io/api/core/Component\">Components</a>,\n<a href=\"https://angular.io/api/core/Pipe\">Pipes</a>, and <a href=\"https://angular.io/api/core/Directive\">Directives</a> in many\nplaces of our application. Duplicating code for repetitious items is not the best practice. This is why we\nusually create a shared module, registering all reusable and generic elements of our application there, so\nthat we can use them later in any feature module.</p>\n<p>It makes sense to create a global place for all reusable items. Unfortunately, it also has disadvantages.</p>\n<p>As the project evolves and the demand for more and more reusable elements increases, the shared module can grow significantly. We\nmust be aware. that in order to use one component, we have to import all the elements registered in the shared\nmodule, which becomes inefficient.</p>\n<h2 id=\"sharedmodules\">Shared Modules</h2>\n<p><a href=\"/blog/scam-1/shared.jpg\"><img src=\"/blog/scam-1/shared.jpg\" alt=\"Shared Modules Image\" /></a></p>\n<p>Let's look at the situation from a <a href=\"https://github.com/jzolnowski/angularjs-scam\">sample application</a>.</p>\n<p><a href=\"/blog/scam-1/folder-structure.png\"><img src=\"/blog/scam-1/folder-structure.png\" alt=\"Angular Icon\" /></a></p>\n<p>We have defined 2 modules, <code>AppModule</code> and <code>UsersModule</code>. They both use <code>ButtonComponent</code>.\nAdditionally, <code>UsersModule</code> uses a <code>FilteredListComponent</code> with users, which is also a reusable component - it\naccepts any shape of a single list element. We put both reusable components in a shared module.</p>\n<pre><code class=\"typescript language-typescript\">export module SharedModule {\n  export const name: string = 'Shared';\n\n  angular\n    .module(SharedModule.name, […])\n    .component(FilteredListComponent.componentName, FilteredListComponent.componentConfig)\n    .component(ButtonComponent.componentName, ButtonComponent.componentConfig);\n}\n</code></pre>\n<pre><code class=\"typescript language-typescript\">angular.module('AppModule', [SharedModule.name])\n</code></pre>\n<pre><code class=\"typescript language-typescript\">angular.module(UsersModule.name, [SharedModule.name]);\n</code></pre>\n<p>As we can see, <code>AppModule</code> needs to import the entire <code>SharedModule</code> to access the reusable <code>ButtonComponent</code>.</p>\n<p>Now imagine that our application defines hundreds of such reusable elements. We won't need all of\nthese elements in every module. A Single Component Angular Module (\"SCAM\") comes to the rescue.</p>\n<h2 id=\"whatisscam\">What is SCAM?</h2>\n<p>Single Component Angular Module, or SCAM for short, is the concept of creating small, encapsulated and\nreusable AngularJS / Angular modules with only one <code>Component</code> (or <code>Directive</code>, or <code>Filter / Pipe</code>).</p>\n<h2 id=\"scaminaction\">SCAM in action</h2>\n<p>Instead of a global module with elements shared between the entire application, we can define modules for each\nof the elements:</p>\n<pre><code class=\"typescript language-typescript\">export module ButtonModule {\n  export const name: string = 'ButtonModule';\n  angular\n    .module(ButtonModule.name, ['ngMaterial'])\n    .component(ButtonComponent.componentName, ButtonComponent.componentConfig);\n}\n</code></pre>\n<pre><code class=\"typescript language-typescript\">export module FilteredListModule {\n  export const name: string = 'FilteredListModule';\n  angular\n    .module(FilteredListModule.name, ['ngMaterial'])\n    .component(FilteredListComponent.componentName, FilteredListComponent.componentConfig);\n}\n</code></pre>\n<p>We can see that we can easily build a module architecture that provides only the required elements for given\nviews, without the need to import unused <code>Components</code>, <code>Filters / Pipes</code>, or <code>Directives</code>.</p>\n<pre><code class=\"typescript language-typescript\">export module UsersModule {\n  angular.module(UsersModule.name, [ButtonModule.name, FilteredListModule.name]);\n}\n</code></pre>\n<pre><code class=\"typescript language-typescript\">module AppModule {\n  angular.module('AppModule', [ButtonModule.name]);\n}\n</code></pre>\n<h2 id=\"scamandrefactoring\">SCAM and Refactoring</h2>\n<p>Note that the SCAM-based architecture allows you to refactor the code quickly. If you reach the point where\n<code>UsersModule</code> no longer requires the use of buttons, you would need to delete the dependency to remove it.\nAdopting this method gives you a considerable advantage over shared modules when migrating from AngularJS\nto Angular. You can now migrate application sections more efficiently by breaking them into independent\nbut valuable parts because you depend on only one component and not on sets of components.</p>\n<h2 id=\"scamandstandalonecomponents\">SCAM and Standalone Components</h2>\n<p>Another point I would like to make is the similarity with Standalone Components. Let's recall that since\nAngular version 14, we can write code without using Angular modules. Having SCAM defined:</p>\n<pre><code class=\"typescript language-typescript\">import {UpperCasePipe} from '@angular/common';\n\n@Component({\n  selector: 'app-button',\n  template: `\n    &lt;button mat-button&gt;Sample Button&lt;/button&gt;\n  `,\n})\nexport class ButtonComponent {\n  // your component's code\n}\n\n@NgModule({\n  declarations: [ButtonComponent],\n})\nexport class ButtonComponentModule {\n}\n</code></pre>\n<p>we can easily migrate to Standalone Components without worrying that we messed up something in other parts\nof the application, since it is an independent piece of code.</p>\n<pre><code class=\"typescript language-typescript\">@Component({\n  standalone: true,\n  selector: 'app-button',\n  template: `\n    &lt;button mat-button&gt;Sample Button&lt;/button&gt;\n  `,\n})\nexport class ButtonComponent {\n  // your component's code\n}\n</code></pre>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>Using common SCAMs creates some overhead because you have more modules and more imports in your feature\nmodules. On the other hand, you get smaller, better encapsulated modules that are less\ncumbersome to maintain. SCAM-based code refactoring is much more straightforward and less time-consuming.\nEven more complicated migrations from AngularJS to Angular will be simpler to implement, and applying\nStandalone Components in the project will reduce the risk of bugs.</p>\n<p>As I mentioned <strong>SCAM is a concept, not imposed by a specific framework or API version. So it can be used\nwherever we are dealing with shared components</strong>.</p>\n<p>The source code for this example is in <a href=\"https://github.com/jzolnowski/angularjs-scam\">this GitHub repository</a>.</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.\nCheck out our <a href=\"https://www.devintent.com\">offerings</a> or <a href=\"https://www.devintent.com/contact-us\">reach out</a>.</p>",
            "url": "https://devintent.com/blog/2023-01-20-better-way-to-share-components-in-angular.md",
            "title": "A Better Way to Share Components",
            "summary": "A way to replace shared modules with a Single Component Angular / AngularJS Module.",
            "date_modified": "2023-01-20T21:00:00.000Z",
            "tags": [
                "angularjs",
                "angular"
            ]
        },
        {
            "id": "blog/2023-01-11-ensuring-an-easier-migration-path-with-framework-agnostic-libraries-using-axios.md",
            "content_html": "<h2 id=\"introduction\">Introduction</h2>\n<p>How often do you use data in your applications? I do this in every application I implement.</p>\n<p>We typically fetch data using an HTTP client in a service. Sometimes, the HTTP client is even used\ndirectly in a component, which is not very good practice. But this article is not about good and bad practices,\nso let’s move on.</p>\n<p>So inside the <code>Service</code>, we can inject another <code>Service,</code> for\nexample, <a href=\"https://docs.angularjs.org/api/ng/service/$http\">$http</a> (AngularJS),\nor <a href=\"https://angular.io/api/common/http/HttpClient\">HttpClient</a> (Angular). The built-in HTTP Angular services\nare outstanding.</p>\n<h3 id=\"whyareweusingthem\">Why are we using them?</h3>\n<p>When AngularJS was written, the browsers didn't have a\n<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/fetch\">fetch()</a> API. Well, now times have changed, and\nthey do!</p>\n<p>So why don’t we use <code>fetch()</code> instead of the HTTP client? You might think:</p>\n<blockquote>\n  <p>Well, it’s just easier to use the build-in HTTP client</p>\n</blockquote>\n<p>or simply:</p>\n<blockquote>\n  <p>Why should I use something else if I get an HTTP client with the framework I’m using?</p>\n</blockquote>\n<p>Think about <a href=\"https://reactjs.org/\">React</a>, <a href=\"https://vuejs.org/\">Vue.js</a>, other web frameworks or just plain\nJavaScript. What are they using? Well, they use the <code>fetch()</code> API. And if they need something more\ncomplex and involved, they can use things like <a href=\"https://axios-http.com/\">Axios</a> - a promise-based HTTP client\nfor Node.js and the browser.</p>\n<p><a href=\"/blog/axios-1/axios-logo.png\"><img src=\"/blog/axios-1/axios-logo.png\" alt=\"Axios Logo\" /></a></p>\n<h2 id=\"axiosinaction\">Axios in action</h2>\n<p>Let’s look at an AngularJS and Angular-based application that does not use the built-in HTTP client.\nHere’s what it might look like in AngularJS:</p>\n<pre><code class=\"typescript language-typescript\">import axios, {AxiosResponse} from 'axios';\nimport {User} from '../users.module';\n\nexport class UsersService {\n  loadAllUsers(): Promise&lt;AxiosResponse&lt;User[]&gt;&gt; {\n    return axios.get('assets/mocks/users.json');\n  }\n}\n</code></pre>\n<p>and Angular:</p>\n<pre><code class=\"typescript language-typescript\">import {Injectable} from '@angular/core';\nimport axios, {AxiosResponse} from 'axios';\nimport {User} from '../users.module';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class UsersService {\n  loadAllUsers(): Promise&lt;AxiosResponse&lt;User[]&gt;&gt; {\n    return axios.get('assets/mocks/users.json');\n  }\n}\n</code></pre>\n<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\nAxios. We can also see a method named <code>loadAllUsers()</code>. That method invokes Axios APIs, which return\na <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\">Promise</a> which\nwill eventually resolve with the returned data.</p>\n<p>The code examples above are straightforward and very similar. But notice what you do not see as well. It’s\nnot just the HTTP service switched out for Axios in this case.</p>\n<p>Where are the <a href=\"https://rxjs.dev/guide/observable\">Observables</a> in the Angular-based code example?</p>\n<p>Now <a href=\"https://rxjs.dev/guide/overview\">RxJS</a> is extremely powerful and valuable. But do you ever feel\nweighed down when you’re getting into a new technology? Maybe you feel like:</p>\n<blockquote>\n  <p>I don’t need this yet</p>\n  <p>I shouldn't need to learn all of these concepts to understand a basic example.</p>\n</blockquote>\n<p>Well, with this, you don’t have to. With <code>fetch()</code> and Axios, you can jump right into using Promises. But\nthere is an even more significant advantage that we may overlook at first glance.</p>\n<h2 id=\"migrationfromangularjstoangular\">Migration from AngularJS to Angular</h2>\n<p>As some of you know, migrating an AngularJS-based application to Angular is a real challenge. Interfaces and\nAPIs are so <strong>different</strong> that it's safe to say that they are two completely different frameworks. The way the\nHTTP client is used in the two mentioned versions is also completely different.</p>\n<p>Here is an example of how we use the built-in <code>$http</code> service in AngularJS:</p>\n<pre><code class=\"typescript language-typescript\">import {IHttpResponse, IHttpService} from 'angular';\nimport {User} from '../users.module';\n\nexport class UsersService {\n  constructor(private $http: IHttpService) {\n  }\n\n  loadAllUsers(): Promise&lt;IHttpResponse&lt;User[]&gt;&gt; {\n    return this.$http.get('assets/mocks/users.json');\n  }\n}\n</code></pre>\n<p>And here is an example of using the built-in <code>HttpClient</code> service for Angular:</p>\n<pre><code class=\"typescript language-typescript\">@NgModule({\n  imports: [HttpClientModule],\n  ...\n})\nexport class UsersModule {\n}\n</code></pre>\n<pre><code class=\"typescript language-typescript\">import {HttpClient} from '@angular/common/http';\nimport {Injectable} from '@angular/core';\nimport {Observable} from 'rxjs';\nimport {User} from '../users.module';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class UsersService {\n\n  constructor(private http: HttpClient) {\n  }\n\n  loadAllUsers(): Observable&lt;User[]&gt; {\n    return this.http.get&lt;User[]&gt;('assets/mocks/users.json');\n  }\n}\n</code></pre>\n<p>Maybe we should consider using a library that is independent of the framework used and guarantees a consistent\nAPI, whether in AngularJS, Angular or even React. Is Axios worth using? We would\nsave ourselves the problem and time of rewriting all Services to an entirely new API.</p>\n<h2 id=\"sodoesthebuiltinhttpclienthaveanyuse\">So, does the built-in HTTP client have any use?</h2>\n<p>There are some reasons why AngularJS/Angular have their HTTP clients.</p>\n<p>In both frameworks, the respective HTTP clients tie into the change detection system, automatically triggering\na change detection as soon as a response is received.</p>\n<p>If we use <code>fetch()</code> or Axios, we might need to handle that ourselves. This is not necessarily\nprohibitively complicated, but it’s worth remembering.</p>\n<p>Another difference in AngularJS that could break your application if not addressed is that the built-in HTTP\nclient returns <a href=\"https://docs.angularjs.org/api/ng/service/$q\">$q</a> promises, the AngularJS’s built-in promise\ntype rather than regular <code>Promise</code> instances. So it is worth paying attention to what type is returned from\nthe services and considering this argument when making a decision about the HTTP client.</p>\n<p>Another difference worth mentioning when using <code>fetch()</code> is that it does not support some features\noffered by built-in clients, such as request/response interception, transformations, etc.</p>\n<p>One last difference between <code>fetch()</code> and Axios is that they might be a little less easy to handle in tests\ncompared to the built-in HTTP clients, which offer utilities that make testing easier.</p>\n<p>With the above in mind, we should decide on the HTTP client based on our goals and objectives.</p>\n<h2 id=\"summary\">Summary</h2>\n<p>I am not trying to convince anyone that Axios is better than <code>HttpClient</code>. But I hope I have\nsucceeded in getting you to reflect on the future of your application. Perhaps years from now, Angular will be\nanother completely different framework implementing a new API. Regardless, using a framework-agnostic\nlibrary like Axios will ensure that your code that fetches data will look and function similarly!</p>\n<p>Sample application code based on AngularJS and Axios is available in\n<a href=\"https://github.com/jzolnowski/angularjs-axios\">this GitHub repository</a>.</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.\nCheck out our <a href=\"https://www.devintent.com\">offerings</a> or <a href=\"https://www.devintent.com/contact-us\">reach out</a>.</p>\n<p><br></p>\n<hr>\n<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>",
            "url": "https://devintent.com/blog/2023-01-11-ensuring-an-easier-migration-path-with-framework-agnostic-libraries-using-axios.md",
            "title": "Ensuring An Easier Migration Path With Framework-agnostic Libraries Using Axios",
            "summary": "The benefits of using framework-agnostic libraries when migrating to newer technologies.",
            "date_modified": "2023-01-11T09:20:00.000Z",
            "tags": [
                "angularjs-migration"
            ]
        },
        {
            "id": "blog/2022-12-22-why-an-expert-migration-partner-ultimately-saves-you-money.md",
            "content_html": "<p>Web application platform migrations are large and often daunting undertakings.\nEspecially when new feature developments, budgets, and revenue-driving business priorities have you pulled in\nmany, and sometimes conflicting, directions.</p>\n<p>When evaluating a migration strategy, one of the first questions is whether to use internal resources or\npartner with a migration expert. Initially, in-house migrations often feel like the easier choice, and the\nsticker shock can scare some away from bringing in outside help.</p>\n<p>However, internal teams can become overwhelmed with competing priorities or need more technical expertise,\ncausing the migration to drag on for years or, worse yet, never reach successful completion. With a closer\nlook, you’ll find the upfront costs of a partner return significant savings from many angles over the life of\nthe project.</p>\n<p>Let’s see how partnering with a migration expert helps save time and money while achieving a successful\nmigration.</p>\n<h2 id=\"toplinegrowth\">Top Line Growth</h2>\n<p>Migrations to newer web application platforms are an experienced migration architect’s specialty. Their\nmigration-specific expertise provides a blueprint for your application to work right, not only when the\nmigration is complete but also along the way. By deploying a hybrid environment, they can ensure the\napplication will be in a workable and releasable state throughout the migration. Compared to attempting a\nmigration in-house, this is a significant advantage that allows your team to focus on the core business goals\nof developing new features and applications that grow your top and bottom line.</p>\n<h2 id=\"inhousedevelopervsexpertmigrationarchitect\">In-house Developer vs. Expert Migration Architect</h2>\n<p>When you already have developer talent in-house, why should you trust outside help? Because a migration\narchitect’s skillset is unique to migrations, drastically differing from a developer’s proficiency in writing\napplication code. The mammoth undertaking of ramping up your team’s knowledge for a successful platform\nmigration is a legacy tech investment that won’t result in an ROI. You’ve burnt months or years of valuable\ntime preparing for an undertaking having high odds of failure. Instead, by using an expert partner, you can\nhave confidence in your approach while significantly increasing your success rate and starting your migration\nimmediately.</p>\n<h2 id=\"budgeting\">Budgeting</h2>\n<p>A migration expert can complete the project with fewer costs and a shorter delivery time when compared to\nusing in-house resources. Additionally, you’ll have confidence the correct route was taken, not requiring\ncostly revisits to address something twice. You can get where you need to go faster and at a lower cost than\nin-house. Depending on your budget allocations, you can dynamically throttle up your project’s momentum with\nfully dedicated migration services or with consistently dedicated part-time work.</p>\n<h2 id=\"stopsthebleeding\">Stops the Bleeding</h2>\n<p>Stops the accumulation of technical debt by ceasing the creation of antiquated end-of-life code. Each\nincrementally migrated module is proven to work when complete, not just verified at the end of the migration.\nFurther application development, like fixes and new features, can continue alongside the migration. Your team\ncan quickly develop on a modern platform, improving your application performance and security while reducing\nimplementation times for new features.</p>\n<h2 id=\"headcount\">Head Count</h2>\n<p>No need to hire, train, or maintain migration-specific talent for the project, allowing you to avoid overhead\ncosts and the time spent recruiting. Choosing to upskill internal talent for a migration comes with\nconsiderable risk. Many developers are unwilling to learn competencies on a deprecated platform or lack the\nspare time required. There are also chances of a fatal architecture error or newly trained developers\ntransitioning away from the project part-way through. These obstacles could leave you upside down with a\nbroken application or scrambling to hire replacements with a skill set that’s becoming obsolete.</p>\n<h2 id=\"riskmanagement\">Risk Management</h2>\n<p>You mitigate substantial risk by involving a proven web application migration expert early in the planning\nstages. Common errors avoided include confusing the easiest migration path as optimal for your future needs,\nchoosing the incorrect migration tools, or not knowing when an app is better suited for a complete rewrite.\nUltimately all these things could have severe negative consequences and huge costs associated.</p>\n<h2 id=\"conclusions\">Conclusions</h2>\n<p>The points above demonstrate a compelling business case of how teaming with a migration expert saves money and\ntime. Whether you’re in the planning stages of a migration, stuck in a perpetual rut of deciding which\nplatform to move to, or stalled halfway through, help is available. Keep your momentum moving forward and\nproject on target without breaking the bank.</p>\n<p>To learn more about the best path for your business, <a href=\"https://calendly.com/devintent/15min\">schedule</a>\na quick introductory chat with our team.</p>",
            "url": "https://devintent.com/blog/2022-12-22-why-an-expert-migration-partner-ultimately-saves-you-money.md",
            "title": "Why an Expert Migration Partner Ultimately Saves You Money",
            "summary": "Learn how to ensure the success of your migration while saving money, shortening the project timeline, and avoiding critical errors.",
            "date_modified": "2023-01-26T22:00:00.000Z",
            "tags": [
                "it-leadership"
            ]
        },
        {
            "id": "blog/2022-12-01-how-to-support-users-light-dark-mode-preferences-in-your-web-application.md",
            "content_html": "<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>\n<h2 id=\"whatisdarkmodeandhowtocontrolit\">What is dark mode, and how to control it</h2>\n<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>\n<ul>\n<li>always light</li>\n<li>always dark</li>\n<li>auto—light during the day and dark at night</li>\n</ul>\n<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>\n<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>\n<h2 id=\"howotherwebsiteslookindarkmode\">How other websites look in dark mode</h2>\n<p>Many websites already switch to dark mode automatically based on the users' preferences. For example:</p>\n<p>Google:</p>\n<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>\n<p>Twitter:</p>\n<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>\n<h2 id=\"whyyoushouldsupportitaswell\">Why you should support it as well</h2>\n<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>\n<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>\n<h2 id=\"examplewithcssvariables\">Example with CSS variables</h2>\n<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>\n<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>\n<p>You can use it very easily in any web application. You define two files defining variables:</p>\n<p><code>styles.light.css</code>:</p>\n<pre><code class=\"css language-css\">:root {\n  --main-bg-color: #fafafa;\n  --main-color: #000000de;\n}\n</code></pre>\n<p><code>styles.dark.css</code>:</p>\n<pre><code class=\"css language-css\">:root {\n  --main-bg-color: #303030;\n  --main-color: #fff;\n}\n</code></pre>\n<p>Then, in your main style file you use those variables for styling and import the color mode file based on user preferences.</p>\n<p><code>styles.css</code>:</p>\n<pre><code class=\"css language-css\">@import url(\"styles.light.css\") (prefers-color-scheme: light);\n@import url(\"styles.dark.css\") (prefers-color-scheme: dark);\n\nbody {\n  background-color: var(--main-bg-color);\n  color: var(--main-color);\n}\n</code></pre>\n<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>\n<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>\n<pre><code class=\"css language-css\">body {\n  background-color: #fafafa;\n  background-color: var(--main-bg-color);\n  color: #000000de;\n  color: var(--main-color);\n}\n</code></pre>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.\nCheck out our <a href=\"https://www.devintent.com\">offerings</a> or <a href=\"https://www.devintent.com/contact-us\">reach out</a>.</p>",
            "url": "https://devintent.com/blog/2022-12-01-how-to-support-users-light-dark-mode-preferences-in-your-web-application.md",
            "title": "How to Support Users’ Light/Dark Mode Preferences in Your Web Application?",
            "summary": "How to automatically switch styling between dark and light modes.",
            "date_modified": "2022-12-01T00:00:00.000Z",
            "tags": [
                "UX",
                "accessibility"
            ]
        },
        {
            "id": "blog/2022-10-15-back-and-better-than-ever-takeaways-from-ng-conf-2022.md",
            "content_html": "<p>Earlier this month marked another successful year of ng-conf, Angular's most prominent conference. This year's\nconference was the first one back in-person since 2020 and hosted more than 50 speakers from around the world.\nWhile we wait for <a href=\"https://www.youtube.com/playlist?list=PLOETEcp3DkCpNBWRSCq82AK2LTDfR2zDf\">more presentations</a>\nto be released online, our team wanted to share some of our key takeaways from the event, focusing\nspecifically on the areas of security, performance, and architecture.</p>\n<p>Let's get started!</p>\n<h2 id=\"performance\">Performance</h2>\n<p><a href=\"/blog/ng-conf-2022/performance.jpg\"><img src=\"/blog/ng-conf-2022/performance.jpg\" alt=\"Loading\" /></a></p>\n<p>From performance at scale, to tuning, to general best practices, web application performance was a big topic\nat ng-conf 2022. While we didn't have the opportunity to attend every presentation, we picked out a few\nhighlights we thought were particularly valuable.</p>\n<p>Lara Newsom's \"The Tell-Tale Code\" listed three standard Angular Code Smells:</p>\n<ul>\n<li>Calling functions inside Angular templates causes our method to be called multiple times instead of once</li>\n<li>Optional chaining EVERYTHING, which, when misused, increases the size of the bundle</li>\n<li>Tightly coupled component logic, which will require significant refactoring at a later stage for\nthe application to be maintained and scaled appropriately because it can cause a loss of reusability\nof components or difficulty in identifying dependencies between them</li>\n</ul>\n<p>In a presentation focused on the anatomy of slow web applications, Misko Hevery shared that the amount of\nJavaScript code in applications has caused performance problems for even the most mature players in the\nspace. This increase, he said, is not necessarily due to bad practices but can be attributed to the evolution\nof JavaScript itself. Today, JavaScript is capable of so much more and, naturally, developers want to\ntake advantage of that increased functionality.</p>\n<p>Misko shared that the most common problem is extraneous JavaScript code. By optimizing that code, we can correct\na lot of existing performance issues, even in larger web applications. He demonstrated one method by\ncomparing <code>Replayable</code> (<code>Angular</code>, <code>Vue</code>, <code>React</code>, <code>Svelte</code>), where JavaScript code is fetched\nfrom the server and executed on the browser side, and <code>Resumable</code> frameworks (<a href=\"https://markojs.com/\">Marko</a>,\n<a href=\"https://github.com/google/jsaction\">Wiz</a>, <a href=\"https://github.com/BuilderIO/qwik\">Qwik</a>), where code is\nexecuted on the server side, is serialized, and then encapsulated in HTML for user interaction.</p>\n<p>Ady Ngom presented seven basic principles to develop faster Angular applications. He mentioned that the\nsize of the application does not matter much when discussing performance. Budget plays a key role. He shared\npractical strategies, like lazy loading images, optimizing event detection with\n<a href=\"https://angular.io/api/core/NgZone\">ngZone</a>, the <a href=\"https://docs.angular.lat/guide/ivy\">Ivy</a> engine,\nnon-blocking processes, and prefetching all possible resources. These are captured in his \"Angular Checklist\"</p>\n<ul>\n<li>a list of practices that will help boost the performance of Angular applications.</li>\n</ul>\n<p>Michael Hladky spoke to Runtime Performance, comparing the performance of a regular Angular application with\na Zone-Less Angular application. He explained how event detection works in the framework and presented an\nefficient way of event detection and template re-rendering using the <a href=\"https://rx-angular.io/\">RxAngular</a>\nlibrary as an example.</p>\n<p>Ben Lesh, in turn, mentioned a patch release for <a href=\"https://rxjs.dev\">RxJS</a> version 7.5.4,\nwhere stream operations are performed <strong>31 times faster than in previous versions!</strong> So it's worth checking\nthe library version you're working with.</p>\n<p>On the last day, Houssein Djirdeh talked about Chrome browser features and improvements in the area of web\napplication performance:</p>\n<ul>\n<li>Updated the Largest Contentful Paint (LCP) metric in version 88 - previous versions did not consider\nelements removed from the DOM tree</li>\n<li>Automatically inline Google Fonts and critical CSS, so we don't have to make additional HTTP requests</li>\n<li>Image optimization during build time thanks to the\nnew <a href=\"https://angular.io/api/common/NgOptimizedImage\">NgOptimizedImage</a> module, which enforces best practices</li>\n</ul>\n<p>Finally, we got to experience a deep dive into image optimization best practices for Angular, presented by\nKara Erickson during her session called \"Image Optimization Best Practices with Angular\".</p>\n<h2 id=\"security\">Security</h2>\n<p><a href=\"/blog/ng-conf-2022/security.jpg\"><img src=\"/blog/ng-conf-2022/security.jpg\" alt=\"Security\" /></a></p>\n<p>Security is one of the greatest challenges in software development. It is a critical defense mechanism meant\nto cover any potentially vulnerable surfaces, as it's impossible to predict every form an attack may come in.\nHowever, despite its inherent importance, security is often overlooked or treated as an afterthought during\ndevelopment.</p>\n<p>After all, we count on the framework to do the security work for us, and the rest of the\ndependencies… well, since they have been released for production, they should be safe, right? :) Of course\nnot!</p>\n<p>In their cleverly-named presentation, \"OAyDaBy AAmn=/y SAinRe9L TArT, wait what?\" Jessica Janiuk\nand Joey Perrot raised topics related to the security of the Angular framework. They covered topics on secure\nsoftware development, operations to deploy and run applications securely in production, and how to ensure\nthat applications are protected by default when using Angular.</p>\n<p>Alisa Duncan's session, on the other hand, focused on the <strong>TOP 2 OWASP vulnerabilities</strong> from 2021:</p>\n<ul>\n<li><code>Broken Access Control</code>, which is the failure to properly enforce policies such that users cannot act\noutside their intended permissions</li>\n<li><code>Injection</code> - the attacker sends data to an application in a way that will change the meaning of commands\nbeing sent to an interpreter.</li>\n</ul>\n<p>She highlighted what can happen when an attacker has elevated access within the application and explained\nsome of the defenses we have against these attacks, both built into Angular and what we can do ourselves, as\ndevelopers.</p>\n<h2 id=\"architecture\">Architecture</h2>\n<p><a href=\"/blog/ng-conf-2022/architecture.jpg\"><img src=\"/blog/ng-conf-2022/architecture.jpg\" alt=\"Diagram\" /></a></p>\n<p>As you might expect, architecture was another topic covered in more than a few presentations.</p>\n<p>One of our consultants, Alain Chautard, walked us through creating generic components with content projection\non Thursday, using the <code>Dialog</code> and <code>Tabs</code> Components in an example.</p>\n<p>Manfred Steyer focused on topics related to Micro-frontend architecture\nand <a href=\"https://webpack.js.org/concepts/module-federation/\">Webpack Module Federation</a>. He discussed Static\nand Dynamic Federation configuration and showed how to share libraries and modules between independent\napplications.</p>\n<p>In a similar vein, Adrian Iskandar Espinosa Caballero discussed some advantages of using Micro frontends,\nnamely:</p>\n<ul>\n<li>Scalability</li>\n<li>Reusability</li>\n<li>Visual Continuity</li>\n</ul>\n<p>Both speakers presented sample Micro-frontend applications using React, AngularJS, and various versions of\nAngular.</p>\n<p>There were also topics related to Monorepos, which have <a href=\"https://nx.dev/more-concepts/why-monorepos\">Nx</a> at\ntheir heart. Michael Madsen and Erik Slack presented 20 reasons why you should use Nx.</p>\n<p>There was also a session on state management using NgRx as an example. Kate Sky and, in a later session,\nBrandon Roberts talked about some of the best and worst (or suboptimal, at least) practices for using\n<a href=\"https://ngrx.io/\">NgRx</a>. They also discussed separating smart and presentational components, clean code,\nand state management in a monorepo, using Nx as an example.</p>\n<p>In another session, Mike Ryan and Brandon Roberts presented the new v14 version of NgRx and its features,\nsuch as <a href=\"https://github.com/ngrx/platform/discussions/3337\">createActionGroup</a>, the new API\nfor <a href=\"https://angular.io/guide/standalone-components\">Standalone Components</a>,\nand <a href=\"https://github.com/timdeschryver/eslint-plugin-ngrx\">@ngrx/eslint-plugin</a>. The topic of new features\nin NgRx was continued by Marko Stanimirović, discussing\nthe <a href=\"https://github.com/ngrx/platform/discussions/3099\">createFeature</a>\nfunction that can help us to reduce repetitive code in selector files.</p>\n<p>The <a href=\"https://www.youtube.com/watch?v=hnVckmM6GZk&list=PLOETEcp3DkCpNBWRSCq82AK2LTDfR2zDf\">session</a> with Pawel\nKozlowski provided some additional insight into Standalone Components. We learned more about their power,\nmotivation, and how they differ from NgModules. We also found how we can use Standalone Components to\ndrastically reduce the number of lines of code and can break inheritance restrictions.</p>\n<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>\n<p>Manfred Steyer, on the other hand, in his talk on Standalone Components, showed us route handling in an\napplication without NgModules and a recommendation for file and folder structure in such applications.</p>\n<p>In his session, Mike Ryan demonstrated <a href=\"https://v10.ngrx.io/guide/component-store\">ComponentStore</a>\nin action using a sample drawing application as an example. He explained best practices for sharing states\nbetween components, managing streams and lifecycle <code>Subscriptions</code>, decoupling component logic, removing\nresponsibility outside the element, and making them easier to read, write, and test.</p>\n<p>We found Ward Bell's session on validating <a href=\"https://angular.io/guide/reactive-forms\">Reactive Forms</a> to be\nparticularly enlightening. He talked about frontend architecture and its role in form validation.\nHe said that it's the model that sets the rules, not the UI; that it's the model that should know if a field\nis required, not the UI; and that it's the model that should understand the relationships between fields in\ndifferent 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>\nlibrary. Ward’s fuchsia-colored outfit also attracted considerable attention. So if you were looking for Ward\nat the conference, you had no problem recognizing him :)</p>\n<p>In the last session of the conference, Deborah Kurata discussed best practices for RxJS, mentioned the\ndeclarative approach, and the differences between different\n<a href=\"https://rxjs.dev/guide/higher-order-observables\">Higher-Order Maps</a>.</p>\n<h2 id=\"finalthoughts\">Final thoughts</h2>\n<p>The conference ended with a Q&amp;A session with the Angular Team, during which attendees asked questions for\nnearly an hour. Among other things, they asked about <code>ngUpgrade</code> support for Standalone Components and the\nfuture of <a href=\"https://rxjs.dev/guide/observable\">Observables</a> in Angular. It was an excellent opportunity for the\ncommunity to learn about the upcoming but more distant plans for the framework.</p>\n<p>Each of the three days of the conference presented fascinating information and touched on the essential\naspects of Angular development and its community. There were topics on Angular's history, current best\npractices, and items still in the pipeline.</p>\n<p>What were my takeaways? First, I gained a better understanding of the mechanisms under Angular's hood,\nlearned more about the causes of poor performance in web applications, and the power\nof Standalone Components.</p>\n<p>I'm particularly looking forward to doing tests using the new <code>NgOptimizedImage</code> module and playing around\nwith RxAngular a bit more. I'm also curious about the new <code>Qwik</code> framework offering, according to Miško\nHevery, the fastest possible page load times.</p>\n<p>The only thing I missed was a lack of topics related to hybrid architecture that didn't depend upon using\nMicro frontends. The Angular Team officially\n<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>,\nbut many projects are stuck on the old framework with no clear path for migrating to the latest version of\nAngular.</p>\n<p>Hopefully, the materials from the conference will be released soon. It's worth checking out the videos when\nthey are published, and you have spare time. Next year, I hope there will be another ng-conf, may it be as\nsuccessful!</p>\n<p>Thank you for your attention!</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.\nCheck out our <a href=\"https://www.devintent.com\">offerings</a> or <a href=\"https://www.devintent.com/contact-us\">reach out</a>.</p>",
            "url": "https://devintent.com/blog/2022-10-15-back-and-better-than-ever-takeaways-from-ng-conf-2022.md",
            "title": "Back and Better Than Ever - Takeaways from ng-conf 2022",
            "summary": "Review of interesting sessions at the ng-conf 2022 conference",
            "date_modified": "2022-10-15T21:20:00.000Z",
            "tags": [
                "angular"
            ]
        },
        {
            "id": "blog/2022-10-04-react-to-screen-size-changes-in-angular.md",
            "content_html": "<h2 id=\"overview\">Overview</h2>\n<p>Imagine that you have an application where you display different content depending on the size of the screen.\nThere are different ways to solve this issue, for example\nwith <a href=\"https://www.w3schools.com/cssref/css3_pr_mediaquery.asp\">@media css</a>. Media queries with CSS is really\nhelpful, but if we have business logic to implement depending on the screen size, creating custom classes with\nseparate CSS just to handle these kinds of problems will create unnecessary chaos in our project.</p>\n<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>\n<p>This is where <a href=\"https://material.angular.io/cdk/categories\">Angular CDK</a> jumps in. In this article, we will\nfocus on the solution provided by the Angular team, the two main classes\nfrom <a href=\"https://github.com/angular/components/tree/master/src/cdk/layout\">@angular/cdk/layout</a>\npackage: <a href=\"https://material.angular.io/cdk/layout/overview#breakpointobserver\">BreakpointObserver</a>\nand <a href=\"https://material.angular.io/cdk/layout/overview#mediamatcher\">MediaMatcher</a>. We will also build an\napplication that will track changes in the screen size and display different content depending on the\nresolution.</p>\n<p>Let's get started!</p>\n<h2 id=\"angularcdklayout\">Angular CDK Layout</h2>\n<p>The layout package helps to build responsive UIs that react to screen-size changes. With it, we can catch any\nresize and know when the screen exits or enters a breakpoint.</p>\n<h2 id=\"prerequisites\">Prerequisites</h2>\n<p>If you would like to follow along with this article, you will need:</p>\n<ul>\n<li><a href=\"https://nodejs.org/en/download/\">Node.js</a> installed locally</li>\n<li><a href=\"https://www.npmjs.com/package/@angular/cli\">@angular/cli</a> installed globally</li>\n</ul>\n<p>In this article, the examples are based on <code>Angular CLI 14.2.2</code> and <code>Node 16.13.1</code>.</p>\n<h2 id=\"projectsetup\">Project Setup</h2>\n<p>Let's open a terminal, navigate to the directory where we want to create the project, and type:</p>\n<pre><code>ng new cdk-breakpointobserver-example\n</code></pre>\n<p>It will create and initialize a new Angular application.</p>\n<p>Navigate to the newly created project and install <code>@angular/cdk</code> package:</p>\n<pre><code>npm i --save @angular/cdk\n</code></pre>\n<p>To use services from Layout Module, we will first need to import it. Lets do that in app.module:</p>\n<pre><code class=\"typescript language-typescript\">import { NgModule } from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { BrowserAnimationsModule } from '@angular/platform-browser/animations';\nimport { LayoutModule } from '@angular/cdk/layout';\nimport { MatCardModule } from '@angular/material/card';\n\nimport { AppComponent } from './app.component';\n\n@NgModule({\n  declarations: [\n    AppComponent\n  ],\n  imports: [\n    BrowserModule,\n    BrowserAnimationsModule,\n    LayoutModule,\n    MatCardModule,\n  ],\n  bootstrap: [AppComponent]\n})\nexport class AppModule {}\n</code></pre>\n<p>Now we can start using the available utilities from the <code>LayoutModule</code>.</p>\n<h2 id=\"breakpointobserver\">BreakpointObserver</h2>\n<p><code>BreakpointObserver</code> lets you evaluate media queries to determine the current screen size and react to changes\nwhen the viewport size crosses a breakpoint.</p>\n<pre><code class=\"typescript language-typescript\">export declare class BreakpointObserver implements OnDestroy {\n  isMatched(value: string | readonly string[]): boolean;\n\n  observe(value: string | readonly string[]): Observable&lt;BreakpointState&gt;;\n  ...\n}\n</code></pre>\n<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\nobserve when the screen-size changes between\ndifferent [breakpoints](when the viewport changes between a matching media query). The <code>isMatched</code> tells us\nwhether one or more media queries match the current viewport size.</p>\n<h2 id=\"mediamatcher\">MediaMatcher</h2>\n<p><code>MediaMatcher</code> is a low-level utility that wraps around\nJavaScript’s <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia\">matchMedia</a>, which can be\nused to get a native <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList\">MediaQueryList</a>.</p>\n<pre><code class=\"typescript language-typescript\">export declare class MediaMatcher {\n  matchMedia(query: string): MediaQueryList;\n  ...\n}\n</code></pre>\n<p>As we can see, it gives us access to the native <code>MediaQueryList</code> object through the public method <code>matchMedia</code>\n.</p>\n<h2 id=\"breakpointobserverandmediamatcherinaction\">BreakpointObserver and MediaMatcher in action</h2>\n<p>Let's return to <a href=\"https://github.com/jzolnowski/cdk-breakpointobserver-example\">our application</a>. We want to\ntrack the changes of the viewport size, and also list the values of each predefined breakpoint.</p>\n<p>To do this, we need to inject <code>BreakpointObserver</code> and <code>MediaMatcher</code> into the class constructor and call\nthe <code>observe</code> and <code>matchMedia</code> methods for class instances.</p>\n<pre><code class=\"typescript language-typescript\">import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core';\nimport {BreakpointObserver, Breakpoints, BreakpointState, MediaMatcher} from '@angular/cdk/layout';\nimport {Observable} from 'rxjs';\n\n@Component({\n  selector: 'app-root',\n  templateUrl: './app.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppComponent implements OnInit {\n  breakpointsInfo: {name: string, value: MediaQueryList}[] = [];\n  breakpointState: Observable&lt;BreakpointState&gt; | undefined;\n  xSmall: string = Breakpoints.XSmall;\n  small: string = Breakpoints.Small;\n  medium: string = Breakpoints.Medium;\n  large: string = Breakpoints.Large;\n  xLarge: string = Breakpoints.XLarge;\n  webLandscape: string = Breakpoints.WebLandscape;\n\n  constructor(public breakpointObserver: BreakpointObserver, private mediaMatcher: MediaMatcher) {}\n\n  ngOnInit(): void {\n    this.breakpointsInfo = this.getBreakpointsInfo();\n\n    this.breakpointState = this.breakpointObserver.observe([\n      Breakpoints.XSmall,\n      Breakpoints.Small,\n      Breakpoints.Medium,\n      Breakpoints.Large,\n      Breakpoints.XLarge,\n      Breakpoints.WebLandscape,\n      Breakpoints.WebPortrait,\n    ])\n  }\n\n  getBreakpointsInfo(): {name: string, value: MediaQueryList}[] {\n    return [\n      Breakpoints.XSmall,\n      Breakpoints.Small,\n      Breakpoints.Medium,\n      Breakpoints.Large,\n      Breakpoints.XLarge,\n      Breakpoints.Web,\n      Breakpoints.WebLandscape,\n      Breakpoints.WebPortrait,\n      Breakpoints.Handset,\n      Breakpoints.HandsetLandscape,\n      Breakpoints.HandsetPortrait,\n      Breakpoints.Tablet,\n      Breakpoints.TabletLandscape,\n      Breakpoints.TabletPortrait\n    ].map((breakpoint, index) =&gt; ({name: Object.keys(Breakpoints)[index], value: this.mediaMatcher.matchMedia(breakpoint)}));\n  }\n}\n</code></pre>\n<p>The observe method returns <a href=\"https://rxjs.dev/guide/observable\">Observable</a>\nof <a href=\"https://material.angular.io/cdk/layout/api#BreakpointState\">BreakpointState</a> type, that we need to\nsubscribe to for observing when the viewport of your application changes. We can do this manually in the\ncomponent class with <a href=\"https://rxjs.dev/guide/observable#subscribing-to-observables\">subscribe</a> method, or in\nthe component template with <a href=\"https://angular.io/api/common/AsyncPipe\">async pipe</a>.</p>\n<pre><code class=\"html language-html\">&lt;div *ngIf=\"breakpointState | async as state\" style=\"display: flex; gap: 10px\"&gt;\n  &lt;h2 *ngIf=\"state.breakpoints[xSmall]\"&gt;Breakpoint: Extra Small&lt;/h2&gt;\n  &lt;h2 *ngIf=\"state.breakpoints[small]\"&gt;Breakpoint: Small&lt;/h2&gt;\n  &lt;h2 *ngIf=\"state.breakpoints[medium]\"&gt;Breakpoint: Medium&lt;/h2&gt;\n  &lt;h2 *ngIf=\"state.breakpoints[large]\"&gt;Breakpoint: Large&lt;/h2&gt;\n  &lt;h2 *ngIf=\"state.breakpoints[xLarge]\"&gt;Breakpoint: Extra Large&lt;/h2&gt;\n  &lt;h2&gt;Orientation: {{ breakpointObserver.isMatched(webLandscape) ? 'Landscape' : 'Portrait' }}&lt;/h2&gt;\n&lt;/div&gt;\n</code></pre>\n<p>It is worth adding that we can listen for non-standard breakpoints that we define ourselves:</p>\n<pre><code class=\"typescript language-typescript\">this.breakpointObserver.observe(['(min-width: 500px)'])\n</code></pre>\n<p>To additionally display information about the value of\nindividual <a href=\"https://material.angular.io/cdk/layout/overview#predefined-breakpoints\">Breakpoints</a>, we need to\nloop through <code>breakpointsInfo</code> collection and display the values of the <code>name</code> and <code>value</code> property:</p>\n<pre><code class=\"html language-html\">&lt;mat-card&gt;\n  &lt;mat-card-title&gt;Breakpoints ranges&lt;/mat-card-title&gt;\n  &lt;mat-card-content&gt;\n    &lt;ul&gt;\n      &lt;li *ngFor=\"let breakpoint of breakpointsInfo\"&gt;\n        &lt;p&gt;&lt;strong&gt;{{breakpoint.name}}&lt;/strong&gt;: {{breakpoint.value.media}}&lt;/p&gt;\n      &lt;/li&gt;\n    &lt;/ul&gt;\n  &lt;/mat-card-content&gt;\n&lt;/mat-card&gt;\n</code></pre>\n<p>As a result, we should see the following effect:</p>\n<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>\n<h2 id=\"conclusions\">Conclusions</h2>\n<p>We saw how to react to viewport size changes using <code>BreakpointObserver</code> and <code>MediaMatcher</code> classes. We can\neasily handle the elements of business logic, not being limited only to files with the styles, but also have\ncontrol over them in the component and its template.</p>\n<p>Source code with a working application described in the article can be found on\nthe <a href=\"https://github.com/jzolnowski/cdk-breakpointobserver-example\">GitHub repository</a>.</p>\n<p>Thank you for your attention!</p>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<p>Our team at DevIntent is highly experienced in web development, including framework migration and updates.\nCheck out our <a href=\"https://www.devintent.com\">offerings</a> or <a href=\"https://www.devintent.com/contact-us\">reach out</a>.</p>",
            "url": "https://devintent.com/blog/2022-10-04-react-to-screen-size-changes-in-angular.md",
            "title": "React To Screen-size Changes In Angular",
            "summary": "Using BreakpointObserver with MediaQuery to respond to screen-size changes",
            "date_modified": "2022-10-04T00:00:00.000Z",
            "tags": [
                "angular",
                "angular-cdk"
            ]
        },
        {
            "id": "blog/2022-07-29-testing-angular-applications-with-playwright.md",
            "content_html": "<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>\n<h2 id=\"whatisplaywright\">What is Playwright</h2>\n<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>\n<h3 id=\"howplaywrightworks\">How Playwright works</h3>\n<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>\n<h3 id=\"strengths\">Strengths</h3>\n<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>\n<ul>\n<li>JavaScript</li>\n<li>Python</li>\n<li>Java</li>\n<li>.Net</li>\n</ul>\n<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>\n<p>Playwright allows you to run your tests in major browsers:</p>\n<ul>\n<li>Chromium (Chrome and Edge)</li>\n<li>Firefox</li>\n<li>WebKit (Safari)</li>\n</ul>\n<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>\n<h2 id=\"exampletests\">Example tests</h2>\n<p>Let's take a look at an example test suite in Playwright.</p>\n<h3 id=\"application\">Application</h3>\n<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>\n<h3 id=\"configurationupdates\">Configuration updates</h3>\n<p>An easy way to initialize the Playwright tests in a project is to run:</p>\n<p><a href=\"/blog/playwright-1/1-init.png\"><img src=\"/blog/playwright-1/1-init.png\" alt=\"npm init playwright@latest\" /></a></p>\n<p>For easy access to running the tests, let's update <code>package.json</code>:</p>\n<p><a href=\"/blog/playwright-1/2-diff.png\"><img src=\"/blog/playwright-1/2-diff.png\" alt=\"package.json example\" /></a></p>\n<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>\n<h3 id=\"tests\">Tests</h3>\n<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>\n<pre><code class=\"js language-js\">import { test, expect, type Page } from '@playwright/test';\n\ntest.describe('Tour of Heroes pages', () =&gt; {\n  test('should load default route', async ({page}) =&gt; {\n    await page.goto('http://localhost:4200');\n\n    await expect(page).toHaveURL(/\\/dashboard$/);\n  });\n\n  test('should allow edits', async ({page}) =&gt; {\n    await page.goto('http://localhost:4200');\n\n    await page.locator('[data-test=\"detail-link\"]').first().click();\n\n    await expect(page).toHaveURL(/\\/detail\\/\\d+/);\n\n    await page.locator('#hero-name').fill('lorem ipsum');\n\n    await page.locator('[data-test=\"save-button\"]').click();\n\n    await expect(page.locator('[data-test=\"detail-link\"]').first()).toContainText('lorem ipsum');\n  });\n\n  test('should search for heroes', async ({page}) =&gt; {\n    await page.goto('http://localhost:4200');\n\n    await page.locator('#search-box').fill('nice');\n\n    await expect(page.locator('[data-test=\"search-result-link\"]')).toHaveCount(1);\n\n    await page.locator('[data-test=\"search-result-link\"]').click();\n\n    await expect(page).toHaveURL(/\\/detail\\/12/);\n  });\n\n  test('should delete heroes', async ({page}) =&gt; {\n    await page.goto('http://localhost:4200/heroes');\n\n    await expect(page.locator('.delete')).toHaveCount(9);\n\n    await page.locator('.delete').first().click();\n\n    await expect(page.locator('.delete')).toHaveCount(8);\n  });\n\n  test('should add heroes', async ({page}) =&gt; {\n    await page.goto('http://localhost:4200/heroes');\n\n    await page.locator('#new-hero').fill('Lorem Ipsum');\n\n    await page.locator('.add-button').click();\n\n    await expect(page.locator('.delete')).toHaveCount(10);\n  });\n});\n</code></pre>\n<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>\n<h3 id=\"runningtests\">Running tests</h3>\n<p>To run tests, we need to start the application server in the background:</p>\n<pre><code class=\"sh language-sh\">$ npm run start\n\n&gt; angular.io-example@0.0.0 start\n&gt; ng serve\n\n…\n\n** Angular Live Development Server is listening on localhost:4200. Open your browser on http://localhost:4200/ **\n\n…\n\n✔ Compiled successfully.\n</code></pre>\n<p>With the server running, we can run all tests with:</p>\n<p><a href=\"/blog/playwright-1/3-run.png\"><img src=\"/blog/playwright-1/3-run.png\" alt=\"npm run e2e\" /></a></p>\n<h2 id=\"summary\">Summary</h2>\n<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>\n<h2 id=\"lookingformoresupportforyourangularprojects\">Looking for more support for your Angular projects?</h2>\n<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>",
            "url": "https://devintent.com/blog/2022-07-29-testing-angular-applications-with-playwright.md",
            "title": "Testing Angular Applications With Playwright",
            "summary": "A brief introduction to writing end-to-end tests with Playwright.",
            "date_modified": "2022-07-29T00:00:00.000Z",
            "tags": [
                "angular",
                "testing"
            ]
        },
        {
            "id": "blog/2022-01-25-angularjs-end-of-life-what-next.md",
            "content_html": "<p>When AngularJS was first launched in 2010 it was ground-breaking for web development. After more than a\ndecade, millions of projects around the world still rely on this framework.\nAngularJS is still one of the most popular frontend frameworks today. In StackOverflow's 2021 survey which\nincluded responses from over 50,000 developers, nearly\n<a href=\"https://insights.stackoverflow.com/survey/2021#most-popular-technologies-webframe-prof\">13% said they are still using AngularJS</a>.</p>\n<p><a href=\"/large-images/end-of-road.jpg\"><img src=\"/large-images/end-of-road.jpg\" alt=\"End of Road Image\" /></a></p>\n<h2 id=\"angularjsendoflife\">AngularJS End-of-Life</h2>\n<p>On <a href=\"https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c\">July 1, 2018</a>, AngularJS\nentered its <a href=\"https://docs.angularjs.org/misc/version-support-status\">Long-term Support (LTS) period</a>. The\nsupport was originally scheduled to end on June 30th, 2021.</p>\n<p>Given the COVID-19 pandemic and its impact on teams migrating from AngularJS, the Google team extended the\nLTS for another 6 months, until December 31st, 2021.</p>\n<p>As of <strong>January 1st, 2022 AngularJS has reached End-of-Life.</strong> You can read more about it on the official\nAngular blog in\n<a href=\"https://blog.angular.io/discontinued-long-term-support-for-angularjs-cc066b82e65a\">Discontinued Long Term Support for AngularJS</a>.\nFor those who are still using this framework, it will have a profound impact on their development and support\nplans. AngularJS will <strong>not</strong> receive patches for security vulnerabilities or breaking issues caused by new\nbrowser releases.</p>\n<h2 id=\"whatifyouarestillusingangularjs\">What if you are still using AngularJS?</h2>\n<p>Now that AngularJS has reached its End-of-Life, AngularJS applications will continue to function, at least\nuntil the next breaking browser change happens.</p>\n<p>Nevertheless, using old versions of the framework is critical to the security of your application and your\nuser's data. Since security patches will no longer be provided by Google, your business and your customers may\nbe vulnerable to new / previously unknown security threats. Before a major vulnerability is disclosed to the\npublic or there is an announcement that it is being exploited in the wild, you will need to have a mitigation\nplan in place.</p>\n<h2 id=\"whatoptionsdoyouhave\">What options do you have?</h2>\n<h3 id=\"getuptodate\">Get up to date</h3>\n<p>If your project is based on an older version of AngularJS, consider upgrading to AngularJS <code>1.8.2</code>. The latest\nversion of AngularJS improves security, imposes a component-based architecture, fixes a few bugs and will make\nthe process of migrating to modern Angular much faster. If you aren't on AngularJS <code>1.8.0</code>, or later, then\nyour application and your users are already exposed to a\n<a href=\"https://snyk.io/vuln/npm:angular\">range of security vulnerabilities</a>, including Cross-site Scripting (XSS)\nattacks. Get protected now, by updating to the latest AngularJS version, if you haven't already done so!</p>\n<h3 id=\"extendyoursupport\">Extend your support</h3>\n<p>You can get Extended Long-term Support via <a href=\"https://xlts.dev/angularjs\">XLTS for AngularJS</a> from XLTS.dev.\nThis will allow you to continue developing or maintaining your application while using supported software.\nThis means that you will receive fixes for security vulnerabilities and breakages to browsers or jQuery when\nthey occur. If you have regulatory or other compliance obligations, this can help you stay compliant and\nget the customer approvals that your business needs.</p>\n<h3 id=\"hybridapplicationmigration\">Hybrid application migration</h3>\n<p>If you're ready to start migrating your legacy AngularJS application to modern <a href=\"https://angular.io/\">Angular</a>,\na good first step is to refactor your application step-by-step, module by module, creating a\nhybrid AngularJS/Angular application. Using this hybrid approach minimizes risk since small chunks of your\nexisting application can be migrated and tested. Using the <code>ngUpgrade</code> tool, you can mix and match AngularJS\nand Angular code in the same application and ensure their smooth cooperation.</p>\n<h3 id=\"rewritingfromscratch\">Rewriting from scratch</h3>\n<p>If your current AngularJS application is small and the business logic and other requirements are\nwell-documented, you may be able to perform a full re-write in a modern framework\n(e.g. Angular, React, Vue, etc.) without running into major issues. A full rewrite is a riskier approach for\nlarge or medium-sized applications. Careful planning, selection of the right tools/technologies, and building\na team with the right skill-sets is necessary to avoid broken/missing functionality, costly delays, or even\ncomplete project failure.</p>\n<h2 id=\"stillunsureinneedofexpertassistance\">Still unsure? In need of expert assistance?</h2>\n<p>If you require expert assistance or are unsure how to identify the best solution for your project,\nDevIntent has the expertise to help. Contact us at\n<a href=\"mailto:consulting@devintent.com\">consulting@devintent.com</a> to get in touch. We have worked with many\nenterprise and mid-sized companies since 2013 to help them update and migrate their AngularJS <code>1.x</code> based\napplications. We can help make your Angular or AngularJS project a success.</p>\n<p><br><br><br><br><br></p>\n<h4 id=\"areyouanexperiencedangularjsdeveloper\">Are you an experienced AngularJS developer?</h4>\n<p><small><bold>We are hiring!<bold> As part of the DevIntent team, you’ll get to work with current and former\nmembers of the Angular team, as well as other experts from the Angular Community.</p>\n<p>We’ve worked on projects like: Angular, AngularJS, Angular CDK, Angular Material, AngularJS Material, and the\nAngular CLI.</p>\n<p>Apply today at <a href=\"mailto:careers@devintent.com\">careers@devintent.com</a> to join us in moving the Angular\ncommunity forward from AngularJS.\n</small></p>",
            "url": "https://devintent.com/blog/2022-01-25-angularjs-end-of-life-what-next.md",
            "title": "AngularJS End-of-Life - What Next?",
            "summary": "What options are available now that Google has dropped support for AngularJS?",
            "date_modified": "2022-01-25T00:00:00.000Z",
            "tags": [
                "angularjs"
            ]
        },
        {
            "id": "blog/2021-12-30-angular-13-is-out.md",
            "content_html": "<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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<p>It's been six months since the last major version of the Angular framework was released. A completely new\nversion of Angular has just been released.</p>\n<p>In this article we'll look at some features and updates that will help you create amazing applications. We\nwill go through a few optimizations of the Ivy engine. We will also talk about what is being deprecated and\nbriefly discuss the process of migrating the application to <strong>Angular v13</strong>.</p>\n<p>So let's get started!</p>\n<h1 id=\"upgradetoangularv13\">Upgrade to Angular v13</h1>\n<p>With the release of the new version, the Angular team provides\na <a href=\"https://update.angular.io/?l=3&v=12.0-13.0\">complete guide</a> to upgrade from previous versions. By following\nthe guide, you shouldn't have any problems with getting migrated to the latest version.</p>\n<p>If you are using Nx, please follow the <a href=\"https://nx.dev/l/a/core-concepts/updating-nx\">guidelines</a> provided by\nthe Nwrl team. By running <code>nx migrate latest</code>, you will also update Angular and all its dependencies.</p>\n<h1 id=\"angulardependencyupdates\">Angular dependency updates</h1>\n<p>In the latest release of Angular, there are also changes in the dependencies of the framework. Angular v13\nintroduces TypeScript 4.4 support, which means that we can now\nuse <a href=\"https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html\">its new features</a>.\nSupport for older versions of TypeScript has been dropped.</p>\n<p>Moreover, version 7.4 is now the default version for RxJs. To learn more about the changes from version 6 to\nversion 7, please read <a href=\"https://rxjs.dev/6-to-7-change-summary\">this</a> article.</p>\n<p>Additionally, Angular v13 has dropped support for NodeJS versions below v12.20.0 and has introduced\nsupport for NodeJS &gt;=16.10.</p>\n<h1 id=\"ie11supportdropped\">IE11 support dropped</h1>\n<p>And it happened. IE11 is no longer supported by Angular v13. This is one of the most important pieces of news\nfor this release. Dropping support for IE11 is a good thing - it means Angular gets to fully embrace the Web\nAPIs of modern browsers. It also means that we no longer have to include polyfills for IE, which makes\napplications lighter and load faster than in previous versions of Angular. It is worth noting that the\nmigration process described previously will automatically remove polyfills for IE.</p>\n<p>The Angular team put out an <a href=\"https://github.com/angular/angular/issues/41840\">RFC</a> (request for comments) about\ndropping IE11 support, and the feedback they received was overwhelmingly in favor of doing so.</p>\n<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>\n<p>Note that Angular 12 will continue to support IE11 until <strong>November 2022</strong>.</p>\n<h1 id=\"ivyftw\">Ivy FTW</h1>\n<h3 id=\"ivyftwviewengine\">Ivy FTW View Engine</h3>\n<p>As promised in past announcements, Angular version 13 no longer supports the old rendering View Engine. For\nthe average Angular dev, this doesn't mean much (other than reaping the benefits of a more performant\nframework). For library builders in Angular, though, this is a big deal.</p>\n<p>As mentioned in the official announcement, removing View Engine also means that Angular can reduce its\nreliance on <a href=\"https://angular.io/guide/glossary#ngcc\">ngcc</a> (Angular compatibility compiler) in the future, and\nteams can look forward to faster compilation because metadata and summary files are no longer included.</p>\n<h3 id=\"angularpackageformatapf\">Angular Package Format (APF)</h3>\n<p>As mentioned in the official announcement,\nthe <a href=\"https://angular.io/guide/angular-package-format\">Angular Package Format</a> (APF) has been streamlined and\nmodernized to better serve developers. To streamline the APF in Angular v13, older output formats such\nas <code>CommonJS</code> (CJS) and <code>UMD</code> have been removed. Thanks to this change, the whole Web community will be better\noff once <code>ES Modules</code> (ESM) are used everywhere.</p>\n<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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<p>The Angular team has also updated the APF to support Node Package Exports. This will help developers from\ninadvertently relying on internal APIs that may change.</p>\n<p>It is now time for Angular library authors to stop using <code>enableIvy: false</code>, and to instead\nuse <code>compilationMode: partial</code> (in <code>tsconfig.prod.json</code>), as recommended by Younes.</p>\n<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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<p>The partial compilation mode is a partial-Ivy code format that is stable between different versions of\nAngular, and thus safe to publish to npm. Angular code that uses this partial format is processed during the\nbuild of the application using the same version of the Angular compiler. The benefit is that both the\napplication and its libraries rely on a single version of Angular, removing potential compatibility issues.</p>\n<blockquote>\n  <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>\n</blockquote>\n<p>To learn more check out\nthe <a href=\"https://angular.io/guide/creating-libraries#building-libraries-with-ivy\">official guidelines</a> for library\nauthors.</p>\n<h3 id=\"createcomponentsdynamicallyfromapiupdates\">Create components dynamically from API updates</h3>\n<p>Ivy enables a simpler way to create dynamic components. Angular no longer requires component factories to\ndynamically create components. Ivy creates the opportunity to instantiate the component\nwith <a href=\"https://github.com/angular/angular/pull/43022\">ViewContainerRef.createComponent</a> without creating an\nassociated factory. So, instead of:</p>\n<pre><code class=\"typescript language-typescript\">@Directive({...})\nexport class CustomyDirective {\n  constructor(\n    private viewContainerRef: ViewContainerRef,\n    private componentFactoryResolver: ComponentFactoryResolver\n  ) {\n  }\n\n  createCustomComponent() {\n    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(CustomComponent);\n    this.viewContainerRef.createComponent(componentFactory);\n  }\n}\n</code></pre>\n<p>We can now write:</p>\n<pre><code class=\"typescript language-typescript\">@Directive({...})\nexport class CustomDirective {\n  constructor(private viewContainerRef: ViewContainerRef) {\n  }\n\n  createCustomComponent() {\n    this.viewContainerRef.createComponent(CustomComponent)\n  }\n}\n</code></pre>\n<p>As we can see, the new approach requires much less boilerplate code!</p>\n<h1 id=\"angularcliimprovements\">Angular CLI improvements</h1>\n<p>With this release, Angular supports the use of persistent build cache by default,\nas <a href=\"https://github.com/angular/angular-cli/issues/21545\">requested by the community</a>. The persistent build\ncache is a feature that caches build results on disk (under the <code>.angular/cache</code> folder). This results in up\nto 68% improvement in compilation speed.</p>\n<p>In order to enable this feature in existing projects that have been upgrading to v13, we need to add the\nfollowing configuration to <code>angular.json</code>:</p>\n<pre><code class=\"json language-json\">{\n  \"$schema\": \"...\",\n  \"cli\": {\n    \"cache\": {\n      \"enabled\": true,\n      \"path\": \".cache\",\n      \"environment\": \"all\"\n      // other supported values: \"ci\" and \"local\"\n    }\n  }\n}\n</code></pre>\n<p>We can also disable this feature (which is not recommended) with ng config <code>cli.cache.enabled false</code>.</p>\n<p>If we need to clear the cache, we should delete the <code>.angular / cache</code> folder.</p>\n<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\nperformance has been improved. The Angular team has introduced esbuild, which now works\nwith <a href=\"https://terser.org/\">terser</a> to optimize global scripts. In addition, <em>ESBuild</em> supports CSS sourcemaps\nand can optimize global CSS, as well as optimizing all style sheets.</p>\n<h1 id=\"routerimprovements\">Router improvements</h1>\n<h3 id=\"disablealinksnavigation\">Disable a link’s navigation</h3>\n<p>Setting the <code>routerLink</code> directive value to <code>null</code> or <code>undefined</code> will completely disable navigation. Recall\nthat in the previous version, the <code>null</code> and <code>undefined</code> inputs for the <code>routerLink</code> directive were\ninterpreted as an empty string.</p>\n<h3 id=\"observerouterlinkactivestate\">Observe router link active state</h3>\n<p>A new output for the <code>routerLinkActive</code> directive called <code>isActiveChange</code> has been added. It emits\nwhenever <a href=\"https://github.com/angular/angular/pull/43280\">the link becomes active or inactive</a>.</p>\n<h3 id=\"lazyloadmodules\">Lazy load modules</h3>\n<p>The <code>loadChildren</code> property in the route definition no longer supports string values. It's been deprecated for\na while now. This has been replaced by the ESM dynamic import statement.</p>\n<h3 id=\"restorehistory\">Restore history</h3>\n<p>A new property has been added to Router public API</p>\n<ul>\n<li><a href=\"https://github.com/angular/angular/commit/3c6b653089837459809a370ebcaf8911c3bab9ed#diff-03cb1ea13f0b5890eb24ce6fef7a42eed85429da0a90cdb48ab06b58c30cb1c1L537\">canceledNavigationResolution</a>\n, which configures how Router attempts to restore the state when a navigation is canceled.</li>\n</ul>\n<pre><code class=\"typescript language-typescript\">RouterModule.forRoot(routes, {canceledNavigationResolution: 'computed'});\n</code></pre>\n<h3 id=\"neweventswhenanoutletgetsattacheddetached\">New events when an outlet gets attached/detached</h3>\n<p>Router now also provides new outputs for subscribing when an outlet gets attached/detached.</p>\n<h3 id=\"otherimprovementsandchanges\">Other improvements and changes</h3>\n<ul>\n<li>Support for question marks in query param values</li>\n<li><a href=\"https://github.com/angular/angular/pull/42434\">Custom route reuse strategy</a> through dependency injection\nfor the <code>RouterTestingModule</code></li>\n</ul>\n<pre><code class=\"typescript language-typescript\">  TestBed.configureTestingModule({\n    imports: [RouterTestingModule],\n    providers: [{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy}]\n  });\n</code></pre>\n<h1 id=\"formimprovements\">Form improvements</h1>\n<p>In this version, a little more attention is paid to Angular Forms, improving the security of reactive forms.\nLet's take a look at the changes.</p>\n<h3 id=\"bettertypecheckingforformstatus\">Better type checking for form status</h3>\n<p>A specific type called <code>FormControlStatus</code> has been introduced, which is the union type of all possible status\nstrings for form controls: <code>'VALID' | 'INVALID' | 'WAITING' | 'OFF'</code>. Until now, we could not use <em>Typescript</em>\nchecking because <code>AbstractControl.status</code> was entered as a string and <code>AbstractControl.statusChanges</code>\nwas <code>Observable&lt;any&gt;</code>.</p>\n<p>This is a breaking change! As mentioned in the release notes, this can break applications if an invalid form\nstatus string is used or if <code>statusChanges</code> events were something other than strings.</p>\n<h3 id=\"newmethodstomanagevalidators\">New methods to manage validators</h3>\n<p>New form methods have been added to <code>AbstractControl</code>:</p>\n<ul>\n<li><code>addValidators</code>: Add one or more synchronous validator(s) to the control, without affecting other validators</li>\n<li><code>setValidators</code>: Sets one or multiple validators by overriding the registered ones. For removing all\nregistered validators we can pass a value of <code>null</code></li>\n<li><code>hasValidator</code>: Determines whether a validator or validators array has a given validator</li>\n<li><code>removeValidators</code>: Remove synchronous validators from this control</li>\n</ul>\n<p>All of these methods also have an async version: <code>addAsyncValidators</code>, <code>setAsyncValidators</code>\n, <code>removeAsyncValidators</code>, and <code>hasAsyncValidator</code>.</p>\n<p>These new methods provide us with more control over the validation process. We can now easily add/remove\nsynchronous and asynchronous validators.</p>\n<h1 id=\"templatesimprovements\">Templates improvements</h1>\n<p>Angular now\nsupports <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>\n. The language service of Angular is now able to automatically insert the optional chaining operator (i.e.,\n?.) when property access (i.e., .) is done on a nullable symbol.</p>\n<p>Also, the <code>fullTemplateTypeCheck</code> compiler option has been deprecated. Instead, we should use <code>strictTemplates</code>\n.</p>\n<h1 id=\"componentsimprovements\">Components improvements</h1>\n<h3 id=\"accessibility\">Accessibility</h3>\n<p>The new version of Angular has also resulted in significant improvements and changes to the components of\nAngular Material.</p>\n<p>All MDC-based components have been assessed to meet elevated a11y standards in areas such as contrast, tactile\ntargets, ARIA, and more. For example let’s compare touch target sizes. The sizes on the right are the new\nsizes.</p>\n<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>\n<p>or for better support for high contrast mode for many components:</p>\n<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>\n<p>It’s always a pleasure to see large organizations put energy into improving accessibility.</p>\n<h3 id=\"angularmaterial\">Angular Material</h3>\n<p>There are also a few changes for Angular Material.</p>\n<p>It is now possible to define content sections in test harnesses for the Dialog component. Also, a new\ninjection token called <code>MAT_PROGRESS_BAR_DEFAULT_OPTIONS</code> has been added to the progress bar. It can be used\nto configure the default options as follows:</p>\n<pre><code class=\"typescript language-typescript\">provide: MAT_PROGRESS_BAR_DEFAULT_OPTIONS,\nuseValue: {\n  mode: 'buffer',\n  color: 'warn'\n}\n</code></pre>\n<h1 id=\"testsimprovements\">Tests improvements</h1>\n<p>Together with Angular v13, TestBed has also been improved. It now takes better care of tearing down test\nmodules and environments after each test. The DOM is now cleaned up after every test, avoiding side effects.\nOverall, tests should execute faster, use less memory, and be less interdependent.</p>\n<p>The automatic teardown functionality was an opt-in feature since Angular v12.1.0 and is now enabled by default.\nAs mentioned in the announcement, this behavior can be configured for the entire test suite via\nthe <code>TestBed.initTestEnvironment</code> method:</p>\n<pre><code class=\"typescript language-typescript\">beforeEach(() =&gt; {\n  TestBed.resetTestEnvironment();\n  TestBed.initTestEnvironment(\n    BrowserDynamicTestingModule,\n    platformBrowserDynamicTesting(),\n    {\n      teardown: {destroyAfterEach: true}\n    }\n  );\n});\n</code></pre>\n<p>Or it can be configured per module by updating the <code>TestBed.configureTestingModule</code> method:</p>\n<pre><code class=\"typescript language-typescript\">beforeEach(() =&gt; {\n  TestBed.resetTestEnvironment();\n...\n  TestBed.configureTestingModule({\n    declarations: [TestComp],\n    teardown: {destroyAfterEach: true}\n  });\n});\n</code></pre>\n<p>This allows us to approach testing differently depending on the situation.</p>\n<h1 id=\"summary\">Summary</h1>\n<p>The new release of Angular introduced a lot of new improvements and minor changes, but also unlocked the way\nto the critical ones, such as the <a href=\"https://www.youtube.com/watch?v=AdvQ_lBDLUY\">optional NgModules</a>.\nViewEngine is gone for good and Ivy has become ubiquitous.</p>\n<p>This is another release that improves runtime performance, shortens build time, simplifies API, and improves\ntests.</p>\n<p>Finally, I encourage you to check\nthe <a href=\"https://github.com/angular/angular/blob/master/CHANGELOG.md\">full list of changes</a>.</p>\n<p>Until next time!</p>\n<p><a href=\"/large-images/transamerica-pyramid.jpg\"><img src=\"/large-images/transamerica-pyramid.jpg\" alt=\"Transamerica Pyramid\" /></a></p>",
            "url": "https://devintent.com/blog/2021-12-30-angular-13-is-out.md",
            "title": "Angular v13 Is Out!",
            "summary": "Information about the Angular v13 Release.",
            "date_modified": "2022-08-09T23:45:00.000Z",
            "tags": [
                "angular"
            ]
        },
        {
            "id": "blog/2021-12-16-announcing-the-angularjs-material-v1-2-4-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.4/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.4/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n</ul>\n<h3 id=\"coderefactoring\">Code Refactoring</h3>\n<ul>\n<li><strong>sass:</strong> migrate from node-sass to sass (<a href=\"https://github.com/angular/material/commit/5e2d21350cd0278f210c1e2bb951786c4047bbb6\">5e2d213</a>)<ul>\n<li>If you consume our <code>.scss</code> files directly in your build, you will need to switch\nfrom the deprecated <code>node-sass</code> package to the <code>sass</code> package for compiling your Sass.</li></ul></li>\n<li><strong>sass:</strong> fix division deprecation warnings (<a href=\"https://github.com/angular/material/commit/b5a1a026202f9544847f2fba8e039c3abf1cdb1c\">b5a1a02</a>)</li>\n</ul>\n<h3 id=\"documentation\">Documentation</h3>\n<ul>\n<li>fix API docs issues related to <code>marked</code> Markdown rendering (<a href=\"https://github.com/angular/material/commit/441a9127676ba4a28aa0c5bc18a70c09815c7221\">441a912</a>)</li>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.2.4 release:</p>\n<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> |\n:---: |:---: |:---: |\n<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>",
            "url": "https://devintent.com/blog/2021-12-16-announcing-the-angularjs-material-v1-2-4-release.md",
            "title": "Announcing the AngularJS Material v1.2.4 Release",
            "summary": "Information about the AngularJS Material v1.2.4 Release.",
            "date_modified": "2021-12-16T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2021-07-15-announcing-the-angularjs-material-v1-2-3-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.3/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.3/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n</ul>\n<h3 id=\"features\">Features</h3>\n<ul>\n<li><strong>menu:</strong> add a new backdropParent option (<a href=\"https://github.com/angular/material/commit/78b107331e9903874cbb71404683f191f9172f7e\">78b1073</a>)</li>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.2.3 release:</p>\n<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> |\n:---: |:---: |\n<a href=\"https://github.com/Splaktar\">Splaktar</a> |<a href=\"https://github.com/atfzls\">atfzls</a> |</p>",
            "url": "https://devintent.com/blog/2021-07-15-announcing-the-angularjs-material-v1-2-3-release.md",
            "title": "Announcing the AngularJS Material v1.2.3 Release",
            "summary": "Information about the AngularJS Material v1.2.3 Release.",
            "date_modified": "2021-07-15T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-12-21-announcing-the-angularjs-material-v1-2-2-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.2/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.2/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes and enhancements.</p>\n<ul>\n<li>This is the final release of AngularJS Material prior to entering our\n<a href=\"https://material.angularjs.org/latest/#long-term-support\">Long Term Support (LTS) period</a>.</li>\n<li>This release includes many accessibility and localization improvements to components like autocomplete,\ncheckbox, datepicker, dialog, and fab speed dial.</li>\n<li>It fixes regressions with radio buttons in IE11 and with the datepicker modifying the model value (time)\nbefore a date is selected.</li>\n<li>A few long-standing issues with the fab speed dial have been fixed, significantly improving the UX of the\ncomponent.</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"features\">Features</h3>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.2.2 release:</p>\n<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> |\n:---: |:---: |:---: |:---: |:---: |\n<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>",
            "url": "https://devintent.com/blog/2020-12-21-announcing-the-angularjs-material-v1-2-2-release.md",
            "title": "Announcing the AngularJS Material v1.2.2 Release",
            "summary": "Information about the AngularJS Material v1.2.2 Release.",
            "date_modified": "2020-12-21T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-09-23-announcing-the-angularjs-material-v1-2-1-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.1/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.1/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>You can now tab in and out of <code>md-calendar</code> when it is used in outside of a datepicker</li>\n<li>Calendar and Datepicker regressions related to GMT+X timezones and MomentJS custom format\nsupport have been resolved</li>\n<li>Fixes a regression where <code>md-select</code> when used with the <code>md-select-header</code> attribute\nand without the <code>multiple</code> attribute, closes when clicking the filter input</li>\n<li>Fixes a regression where the ink-bar in <code>md-select</code> would be black instead of using the\ntheme color</li>\n<li>We now publish a list of supported screen readers on our\n<a href=\"https://material.angularjs.org/latest/#screen-reader-support\">home page</a></li>\n<li><code>md-icon</code> has been updated to match the behavior defined in the docs when you provide\n<code>aria-label=\"\"</code> or <code>alt=\"\"</code>, i.e. apply <code>aria-hidden=\"true\"</code></li>\n<li>Improved the handling of <code>md-list-items</code> that are clickable by screen readers</li>\n<li>Allow selecting the currently focused item in a radio group using the <code>space</code> key</li>\n<li>We now enable iOS long-press context menus in all AngularJS Material apps. If you don't\nwant this behavior, you can set the <code>-webkit-touch-callout: none;</code> style on your app's\n<code>html, body</code></li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<li><strong>select:</strong> respect theme color when select has focus (<a href=\"https://github.com/angular/material/commit/4afba571c8a91e17a354c61a1ab7d711d9f9f3b6\">4afba57</a>)</li>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"documentation\">Documentation</h3>\n<ul>\n<li><strong>mdSticky:</strong> update and clarify the usage and behavior (<a href=\"https://github.com/angular/material/commit/0d431e07330f1ea42c933ae80400adfae79b60d9\">0d431e0</a>)</li>\n<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>\n<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>\n<li><strong>icon:</strong> documentation refinement and cleanup (<a href=\"https://github.com/angular/material/commit/c644d6a29ce4d05e0bfb4588d62340157a98df52\">c644d6a</a>)</li>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.2.1 release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: |\n|                                             <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>",
            "url": "https://devintent.com/blog/2020-09-23-announcing-the-angularjs-material-v1-2-1-release.md",
            "title": "Announcing the AngularJS Material v1.2.1 Release",
            "summary": "Information about the AngularJS Material v1.2.1 Release.",
            "date_modified": "2020-09-23T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-09-01-announcing-the-angularjs-material-v1-1-26-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.26/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.26/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>Fixes a regression that broke MomentJS custom format support</li>\n</ul>\n<p>This is the last planned patch release for the <code>1.1.x</code> release branch. Future patch releases\nwill be based upon the <code>1.2.x</code> release branch.</p>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.1.26 release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: |\n|                                             <a href=\"https://github.com/Splaktar\">Splaktar</a>                                              |                                              <a href=\"https://github.com/mmalerba\">mmalerba</a>                                              |</p>",
            "url": "https://devintent.com/blog/2020-09-01-announcing-the-angularjs-material-v1-1-26-release.md",
            "title": "Announcing the AngularJS Material v1.1.26 Release",
            "summary": "Information about the AngularJS Material v1.1.26 Release.",
            "date_modified": "2020-09-01T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-08-31-announcing-the-angularjs-material-v1-1-25-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.25/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.25/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>Fixes a regression where <code>md-select</code> when used with the <code>md-select-header</code> attribute\nand without the <code>multiple</code> attribute, closes when clicking the filter input</li>\n<li>Fixes date selection and <code>min-date</code> validation issues in GMT+X timezones</li>\n</ul>\n<h3 id=\"knownissues\">Known Issues</h3>\n<ul>\n<li>There is a regression that broke MomentJS custom format support. Fixed in <code>1.1.26</code>\nvia PR <a href=\"https://github.com/angular/material/pull/12006\">#12006</a>.</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.1.25 release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: |\n|                                             <a href=\"https://github.com/Splaktar\">Splaktar</a>                                              |                                             <a href=\"https://github.com/jelbourn\">jelbourn</a>                                             |</p>",
            "url": "https://devintent.com/blog/2020-08-31-announcing-the-angularjs-material-v1-1-25-release.md",
            "title": "Announcing the AngularJS Material v1.1.25 Release",
            "summary": "Information about the AngularJS Material v1.1.25 Release.",
            "date_modified": "2020-08-31T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-08-03-announcing-the-angularjs-material-v1-2-0-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.0/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.2.0/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a major release that includes breaking changes, deprecation removals, enhancements,\nand bug fixes.</p>\n<ul>\n<li>Long awaited updates to align with the\n<a href=\"https://material.io/archive/guidelines/\">Material Design (2017) Specification</a>, including:</li>\n<li>Button</li>\n<li>Checkbox</li>\n<li>Chips</li>\n<li>Input and Input Container</li>\n<li>List</li>\n<li>Tabs</li>\n<li>Palette contrast colors</li>\n<li>Toolbar</li>\n<li>More robust opacity and contrast configuration for theming to meet the AA level of the WAI-ARIA\naccessibility guidelines.</li>\n<li>The full minified CSS is now 24 KB smaller. This translates to 3 KB smaller (37 KB) gzipped.</li>\n<li>Fixes and <a href=\"https://material.angularjs.org/latest/api/directive/mdInputContainer#aligning-form-elements\">docs for aligning form components</a>\nusing containers with the <code>md-inline-form</code> class.</li>\n<li>New Sass mixin (<code>auto-horizontal-margin($selector)</code>) for more easily laying out components\nin <code>layout=\"row\"</code> containers.</li>\n<li>See below for the details on breaking changes.</li>\n</ul>\n<h3 id=\"knownissues\">Known Issues</h3>\n<ul>\n<li><code>min-date</code> validation in <code>md-datepicker</code> is broken for GMT+T timezones\n<a href=\"https://github.com/angular/material/issues/11963\">#11963</a>.</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<li><strong>theming:</strong> dark contrast used incorrectly when only contrastStrongLightColors defined (<a href=\"https://github.com/angular/material/commit/4e3f7a7e0839d9adce8327e67bdb9237e1e91f78\">4e3f7a7</a>)</li>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"coderefactoring\">Code Refactoring</h3>\n<ul>\n<li><strong>autofocus:</strong> remove deprecated md-auto-focus attribute (<a href=\"https://github.com/angular/material/commit/bf0ec8c853c17cd60547ead11b2c1e9310ca8377\">bf0ec8c</a>)</li>\n<li><strong>card:</strong> remove styles for md-actions class (<a href=\"https://github.com/angular/material/commit/75aa734674324df42b3e5e57508281f60d576090\">75aa734</a>)</li>\n<li><strong>chips:</strong> remove deprecated md-on-append attribute (<a href=\"https://github.com/angular/material/commit/1a2e3d0b424fec4d2e3f68071b6520a5477284c8\">1a2e3d0</a>)</li>\n<li><strong>chips:</strong> remove deprecated MdChipsCtrl.selectAndFocusChip (<a href=\"https://github.com/angular/material/commit/01d2cde76fdc127bef4d52027c143b33dc0666c0\">01d2cde</a>)</li>\n<li><strong>dialog:</strong> remove deprecated content options and methods (<a href=\"https://github.com/angular/material/commit/e3b52a0c84134faaa7371041b732ee4c3f1ec713\">e3b52a0</a>)</li>\n<li><strong>dialog:</strong> remove styles for deprecated md-actions class (<a href=\"https://github.com/angular/material/commit/93e20819053117fa2b8679178840bbb65c97a301\">93e2081</a>)</li>\n<li><strong>layout:</strong> remove deprecated <em>-lt-</em> (\"less than\") attributes (<a href=\"https://github.com/angular/material/commit/e8e785e5a3a118026ca8e10e087bc76aa8db745a\">e8e785e</a>)</li>\n<li><strong>\\$mdCompilerProvider:</strong> remove deprecated \\$mdCompilerProvider.respectPreAssignBindingsEnabled() (<a href=\"https://github.com/angular/material/commit/579a3271698381c49803210c2efaa3b1f9e802bb\">579a327</a>)</li>\n<li><strong>menu:</strong> removed deprecated \\$mdOpenMenu API (<a href=\"https://github.com/angular/material/commit/f023ce766a816035fb3de8c1a47f9d089cb2f11d\">f023ce7</a>)</li>\n<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>\n<li><strong>select:</strong> rename ngMultiple to mdMultiple (<a href=\"https://github.com/angular/material/commit/4c758589f5ff8ad1b6fc1c990ffbbfd5dba913f7\">4c75858</a>)</li>\n<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>\n<li><strong>sidenav:</strong> remove md-sidenav-focus directive (<a href=\"https://github.com/angular/material/commit/8fc36d4a7ce1f15cb1398a31e5ea6cea36bcfcda\">8fc36d4</a>)</li>\n<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>\n<li><strong>tabs:</strong> remove deprecated md-no-disconnect (<a href=\"https://github.com/angular/material/commit/05bee8fb2350b066a778052db08a6009c0465ee1\">05bee8f</a>)</li>\n<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>\n</ul>\n<h3 id=\"features\">Features</h3>\n<ul>\n<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>\n<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>\n</ul>\n<h3 id=\"documentation\">Documentation</h3>\n<ul>\n<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>\n</ul>\n<h3 id=\"breakingchanges\">BREAKING CHANGES</h3>\n<ul>\n<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>\n</ul>\n<p>If you want to restore the previous behavior, add the following to your <code>md-autocomplete</code> components:</p>\n<pre><code class=\"html language-html\">md-escape-options=\"blur clear\"\n</code></pre>\n<ul>\n<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>\n<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>\n</ul>\n<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>\n<pre><code class=\"scss language-scss\">$button-left-right-padding: rem(0.6); // For 6px horizontal padding\n</code></pre>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<li><strong>chips:</strong> The deprecated <code>MdChipsCtrl.selectAndFocusChip()</code> function has been removed.\n<code>MdChipsCtrl.selectAndFocusChipSafe()</code> should be used instead.</li>\n<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>\n<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>\n</ul>\n<p>If you have</p>\n<pre><code class=\"js language-js\">alert = $mdDialog.alert().content('This is an example.');\n</code></pre>\n<p>It needs to be changed to</p>\n<pre><code class=\"js language-js\">alert = $mdDialog.alert().textContent('This is an example.');\n</code></pre>\n<p>If you have</p>\n<pre><code class=\"js language-js\">alert = $mdDialog.alert({\n  content: 'This is an example.',\n});\n</code></pre>\n<p>It needs to be changed to</p>\n<pre><code class=\"js language-js\">alert = $mdDialog.alert({\n  textContent: 'This is an example.',\n});\n</code></pre>\n<ul>\n<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>\n<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>\n<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>\n<li><p>layout-lt-md</p></li>\n<li><p>layout-lt-lg</p></li>\n<li><p>flex-lt-md</p></li>\n<li><p>flex-lt-lg</p></li>\n<li><p>layout-align-lt-md</p></li>\n<li><p>layout-align-lt-lg</p></li>\n<li><p>flex-order-lt-md</p></li>\n<li><p>flex-order-lt-lg</p></li>\n<li><p>flex-offset-lt-md</p></li>\n<li><p>flex-offset-lt-lg</p></li>\n<li><p>hide-lt-md</p></li>\n<li><p>hide-lt-lg</p></li>\n<li><p>show-lt-md</p></li>\n<li><p>show-lt-lg</p></li>\n<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>\n<li><p><strong>\\$mdCompilerProvider:</strong> The deprecated <code>$mdCompilerProvider.respectPreAssignBindingsEnabled()</code> API has been removed.\nWe no longer respect AngularJS's <code>$compileProvider.preAssignBindingsEnabled()</code> value as this API was removed\nin AngularJS <code>1.7.0</code>.</p></li>\n</ul>\n<p>If you had the recommended configuration for AngularJS 1.6.x:</p>\n<pre><code class=\"js language-js\">$compileProvider.preAssignBindingsEnabled(false);\n$mdCompilerProvider.respectPreAssignBindingsEnabled(true);\n</code></pre>\n<p>Then you should remove both of these calls as they are now the defaults in AngularJS <code>1.7.0</code>\nand AngularJS Material <code>1.2.0</code>.</p>\n<p>If you had the recommended configuration for AngularJS 1.7+:</p>\n<pre><code class=\"js language-js\">$mdCompilerProvider.respectPreAssignBindingsEnabled(true);\n</code></pre>\n<p>Then you should remove this call as it is now the default in AngularJS Material <code>1.2.0</code>.</p>\n<p>If you were using a backwards-compatible configuration for AngularJS 1.6+:</p>\n<pre><code class=\"js language-js\">$mdCompilerProvider.respectPreAssignBindingsEnabled(false);\n</code></pre>\n<p>Then you will need to remove this call and may need to refactor your Controllers for\nAngularJS Material components like <code>$mdDialog</code>, <code>$mdPanel</code>, <code>$mdToast</code>, or <code>$mdBottomSheet</code>.</p>\n<p>For example:</p>\n<pre><code class=\"js language-js\"> $mdDialog.show({\n   locals: {\n     myVar: true\n   },\n   controller: MyController,\n   bindToController: true\n }\n  function MyController() {\n   // No locals from Angular Material are available. e.g myVar is undefined.\n   // You would need to move anything accessing locals in here to $onInit().\n }\n  MyController.prototype.$onInit = function() {\n   // Bindings are now available in the $onInit lifecycle hook.\n }\n</code></pre>\n<ul>\n<li><strong>menu:</strong> Removed the deprecated <code>$mdOpenMenu</code> API. It was deprecated in favor of <code>$mdMenu.open</code>.</li>\n<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>\n<li><strong>select:</strong> <code>ngMultiple</code> has been renamed to <code>mdMultiple</code> to make it clear that this\nAPI is provided by AngularJS Material and not by AngularJS.</li>\n</ul>\n<p>If you had:</p>\n<pre><code class=\"html language-html\">&lt;md-select ng-multiple=\"expression\"&gt;...&lt;/md-select&gt;\n</code></pre>\n<p>You need to change to:</p>\n<pre><code class=\"html language-html\">&lt;md-select md-multiple=\"expression\"&gt;...&lt;/md-select&gt;\n</code></pre>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<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>\n<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>\n<ul>\n<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>\n</ul>\n<p>Change your code from this:</p>\n<pre><code class=\"js language-js\">    $mdToast.show(\n      $mdToast.simple()\n      .textContent('Simple Toast!'))\n    .then(...\n</code></pre>\n<p>To this:</p>\n<pre><code class=\"js language-js\">    $mdToast.show(\n      $mdToast.simple()\n      .textContent('Simple Toast!')\n      .position('top left'))\n    .then(...\n</code></pre>\n<ul>\n<li><strong>toast:</strong> The deprecated <code>content()</code> and <code>updateContent()</code> methods have been removed.</li>\n</ul>\n<p>If you had:</p>\n<pre><code class=\"js language-js\">$mdToast.show($mdToast.simple().content('This no longer works.'));\n</code></pre>\n<p>You will need to change to:</p>\n<pre><code class=\"js language-js\">$mdToast.show($mdToast.simple().textContent('This works.'));\n</code></pre>\n<p>If you had:</p>\n<pre><code class=\"js language-js\">$mdToast.updateContent('This no longer works.');\n</code></pre>\n<p>You will need to change to:</p>\n<pre><code class=\"js language-js\">$mdToast.updateTextContent('This works.');\n</code></pre>\n<p>If you had:</p>\n<pre><code class=\"js language-js\">$mdToast.show($mdToast.simple({ parent: parent, content: 'This no longer works.', theme: 'some-theme', capsule: true }));\n</code></pre>\n<p>You will need to change to:</p>\n<pre><code class=\"js language-js\">$mdToast.show($mdToast.simple({ parent: parent, textContent: 'This works.', theme: 'some-theme', capsule: true }));\n</code></pre>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.2.0 release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: |\n|                                             <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>\n<p>| <a href=\"https://github.com/tomaszgrabowski\"><img alt=\"tomaszgrabowski\" src=\"https://avatars0.githubusercontent.com/u/6688790?v=4&s=117\" width=\"117\"></a> |\n| :--------------------------------------------------------------------------------------------------------------------------------------------: |\n|                                             <a href=\"https://github.com/tomaszgrabowski\">tomaszgrabowski</a>                                              |</p>",
            "url": "https://devintent.com/blog/2020-08-03-announcing-the-angularjs-material-v1-2-0-release.md",
            "title": "Announcing the AngularJS Material v1.2.0 Release",
            "summary": "Information about the AngularJS Material v1.2.0 Release.",
            "date_modified": "2020-08-03T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-06-29-announcing-the-angularjs-material-v1-1-24-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.24/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.24/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>Fixes <code>$mdPanel</code> animation bugs</li>\n<li>Datepicker now passes <code>ng-model-options</code> on to calendar so that they both use the same timezone settings</li>\n<li>Fixes <code>md-datepicker</code> to work with a custom config via <code>$mdDateLocaleProvider</code>, including MomentJS</li>\n</ul>\n<h3 id=\"knownissues\">Known Issues</h3>\n<ul>\n<li><code>min-date</code> validation in <code>md-datepicker</code> is broken for GMT+T timezones\n<a href=\"https://github.com/angular/material/issues/11963\">#11963</a>. Planned for in <code>1.1.25</code>.</li>\n<li><code>md-select</code> using <code>md-select-header</code> closes on mouse click when not using multiple\n<a href=\"https://github.com/angular/material/issues/11969\">#11969</a>. Will be fixed in <code>1.1.25</code>.</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.1.24 release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: |\n|                                             <a href=\"https://github.com/Splaktar\">Splaktar</a>                                              |                                              <a href=\"https://github.com/mmalerba\">mmalerba</a>                                              |</p>",
            "url": "https://devintent.com/blog/2020-06-29-announcing-the-angularjs-material-v1-1-24-release.md",
            "title": "Announcing the AngularJS Material v1.1.24 Release",
            "summary": "Information about the AngularJS Material v1.1.24 Release.",
            "date_modified": "2020-06-29T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-06-18-announcing-the-angularjs-material-v1-1-23-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.23/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.23/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>Adds a <code>md-month-filter</code> API to <code>md-datepicker</code> and <code>md-calendar</code></li>\n<li>Fixes issue with the <code>md-date-filter</code> API</li>\n<li>Adds support for the <code>$onDestroy</code> hook in <code>$mdCompiler</code></li>\n<li>Fixes a number of issues with <code>$mdPanel</code> animations</li>\n<li>Many fixes for <code>md-select</code> including bringing back support for <code>ng-selected</code> on <code>md-option</code></li>\n<li>Adds <code>md-calendar</code> support for specifying timezone in <code>ng-model-options</code></li>\n</ul>\n<h3 id=\"knownissues\">Known Issues</h3>\n<ul>\n<li><code>md-datepicker</code> throws exceptions if you specify a custom config via <code>$mdDateLocaleProvider</code>\n<a href=\"https://github.com/angular/material/issues/11945\">#11945</a>. Fixed in <code>1.1.24</code>.</li>\n<li><code>min-date</code> validation in <code>md-datepicker</code> is broken for GMT+T timezones\n<a href=\"https://github.com/angular/material/issues/11963\">#11963</a></li>\n<li>Panels sometimes don't appear <a href=\"https://github.com/angular/material/issues/11946\">11946</a>.\nFixed in <code>1.1.24</code>.</li>\n<li><code>md-select</code> using <code>md-select-header</code> closes on mouse click when not using multiple\n<a href=\"https://github.com/angular/material/issues/11969\">#11969</a>. Will be fixed in <code>1.1.25</code>.</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"features\">Features</h3>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"documentation\">Documentation</h3>\n<ul>\n<li><strong>codepen:</strong> update for AngularJS <code>1.8.0</code></li>\n<li><strong>security:</strong> added <a href=\"https://github.com/angular/material/blob/master/SECURITY.md\">Security Policy</a></li>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the v1.1.23 release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: |\n|                                             <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>",
            "url": "https://devintent.com/blog/2020-06-18-announcing-the-angularjs-material-v1-1-23-release.md",
            "title": "Announcing the AngularJS Material v1.1.23 Release",
            "summary": "Information about the AngularJS Material v1.1.23 Release.",
            "date_modified": "2020-06-18T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-05-04-announcing-the-angularjs-material-v1-1-22-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.22/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.22/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>A number of significant fixes for <code>md-select</code> including an a11y overhaul</li>\n<li>Lots of important fixes for <code>md-list</code></li>\n<li>Fixes for <code>md-autocomplete</code> including a regression fix for <code>md-not-found</code> and some usability improvements</li>\n</ul>\n<h3 id=\"knownissues\">Known Issues</h3>\n<ul>\n<li><code>md-select</code> using <code>md-select-header</code> closes on mouse click when not using multiple\n<a href=\"https://github.com/angular/material/issues/11969\">#11969</a>. Will be fixed in <code>1.1.25</code>.</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"documentation\">Documentation</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the <code>v1.1.22</code> release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: |\n|                                             <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>\n<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> |\n| :--------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: |\n|                                             <a href=\"https://github.com/psamim\">psamim</a>                                              |                                              <a href=\"https://github.com/qubiack\">qubiack</a>                                              |</p>",
            "url": "https://devintent.com/blog/2020-05-04-announcing-the-angularjs-material-v1-1-22-release.md",
            "title": "Announcing the AngularJS Material v1.1.22 Release",
            "summary": "Information about the AngularJS Material v1.1.22 Release.",
            "date_modified": "2020-05-04T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2020-05-03-announcing-the-angularjs-material-v1-1-21-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.21/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.21/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>Accessibility and touch improvements for <code>md-autocomplete</code></li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the <code>v1.1.21</code> release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: |\n|                                             <a href=\"https://github.com/Splaktar\">Splaktar</a>                                              |                                            <a href=\"https://github.com/neilsh\">neilsh</a>                                             |</p>",
            "url": "https://devintent.com/blog/2020-05-03-announcing-the-angularjs-material-v1-1-21-release.md",
            "title": "Announcing the AngularJS Material v1.1.21 Release",
            "summary": "Information about the AngularJS Material v1.1.21 Release.",
            "date_modified": "2020-05-03T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2019-09-27-announcing-the-angularjs-material-v1-1-20-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.20/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.20/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes.</p>\n<ul>\n<li>A number of fixes for iOS, Android, and IE11</li>\n<li>Fixes for a number of accessibility issues</li>\n<li>Improvements to internationalization through support for specifying <code>dir=\"rtl\"</code> on any DOM\nelement</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the <code>v1.1.20</code> release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------: |\n|                                             <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>",
            "url": "https://devintent.com/blog/2019-09-27-announcing-the-angularjs-material-v1-1-20-release.md",
            "title": "Announcing the AngularJS Material v1.1.20 Release",
            "summary": "Information about the AngularJS Material v1.1.20 Release.",
            "date_modified": "2019-09-27T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2019-06-08-es-hora-de-la-vista-previa-compatibilidad-de-ivy.md",
            "content_html": "<blockquote>\n  <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>\n</blockquote>\n<p>Estamos buscando desarrolladores que deseen probar cosas nuevas (con algunas limitaciones) y que deseen\ncompartir tus experiencias con nosotros. Si estás interesado, siga los pasos a\ncontinuación y háganos saber en qué problemas se encuentra.</p>\n<p><a href=\"/angular/angularCompilerOptions-enableIvy.png\"><img src=\"/angular/angularCompilerOptions-enableIvy.png\" alt=\"angularCompilerOptions: { enableIvy: true }\" /></a></p>\n<p>Esta vista previa se destina principalmente a validar la compatibilidad con versiones\nanteriores, ya que las mejoras de rendimiento y tamaño del paquete aún están en curso.</p>\n<p>El plan es asegurarse de que la mayoría de las aplicaciones de Angular sigan\nfuncionando sin cambios significativos, y luego enfocarse en aprovechar las mejoras al\nframework subyacente.</p>\n<h1 id=\"estadoactual\">Estado Actual</h1>\n<p>Hemos logrado un importante hito de estabilidad con la compatibilidad con versiones\nanteriores de Ivy. Basándonos en nuestras pruebas en miles de suites de prueba\ndentro de Google (el 97% de las suites de prueba se pasan en Google), estamos\nrazonablemente seguros de que la mayoría de las aplicaciones funcionarán sin cambios\nen todo el ecosistema. Tenemos varios problemas conocidos en los que estamos\ntrabajando, pero esperamos que haya una larga cola de problemas más pequeños que\nsolucionar.</p>\n<p>Ahora que hemos alcanzado este hito, necesitamos tu ayuda para identificar e\ninformar estos problemas. Inscríbete en la vista previa, pruébelo y háganos saber\nqué se rompe.</p>\n<p>Hay tres cosas que vamos a hacer con los problemas que se nos informan:</p>\n<ol>\n<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>\n<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>\n<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>\n</ol>\n<h1 id=\"qupasaconelrendimientoyeltamaodelpaquete\">¿Qué pasa con el rendimiento y el tamaño del paquete?</h1>\n<p>Todavía estamos trabajando en mejoras para el tamaño del paquete y el rendimiento del\ntiempo de ejecución. Cuando actualice hoy, todavía no verá todos estos beneficios.</p>\n<p>Actualmente estamos viendo que el código generado y las aplicaciones “Hello World” son\nmás pequeñas, pero en algunos casos, Angular en sí es más grande. Estos son algunos de\nlos primeros resultados que hemos visto al actualizar las aplicaciones a Ivy:</p>\n<p><a href=\"https://gist.github.com/StephenFluin/fffe2421fc6a8da3d245da84f0e6c20c\"><strong>ng new my-app</strong></a> @ <code>8.1.0-next.1</code></p>\n<p><strong>Antes de Ivy:</strong> Paquete principal (135 KiB)</p>\n<p><strong>Con vista previa de Ivy:</strong> Paquete principal (122 KiB)</p>\n<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>\n<p><strong>Antes de Ivy:</strong> Paquete principal (358 KiB)</p>\n<ul>\n<li>Lazy Chunks (7.7–34 KiB)</li>\n</ul>\n<p><strong>Con vista previa de Ivy:</strong> Paquete principal (400 KiB)</p>\n<ul>\n<li>Lazy Chunks (3.3–27 KiB)</li>\n</ul>\n<p>Ahora estamos trabajando para reducir el tamaño del framework, de modo que hemos\nreducido el tamaño de los paquetes para aplicaciones reales en casi todos los casos\nantes de que Ivy sea el valor predeterminado. También serán posibles beneficios\nadicionales, ya que ofrecemos nuevas formas de arranque que van a reducir el tamaño\ndel framework en tu paquete principal.</p>\n<p>Haremos más anuncios sobre el rendimiento y los hitos del tamaño del paquete para\nlas aplicaciones del mundo real en los próximos meses a medida que nos acerquemos a\nactivar a Ivy de forma predeterminada para todas las aplicaciones.</p>\n<h1 id=\"qudeboesperarverhoy\">¿Qué debo esperar ver hoy?</h1>\n<p>Tu aplicación debe construir y funcionar como lo hace hoy. Notarás los siguientes\nbeneficios que se deben al nuevo compilador y conjunto de instrucciones:</p>\n<ul>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<p>También hemos solucionado muchos errores de larga data, hemos mejorado el comportamiento confuso y hemos solucionado algunos problemas de rendimiento.</p>\n<ul>\n<li><p>Los enlaces de clase siempre anulan otras clases (<a href=\"https://github.com/angular/angular/issues/7289\">7289</a>)</p></li>\n<li><p><code>ContentChildren</code> consultas seleccionar nodo de host (<a href=\"https://github.com/angular/angular/issues/10098\">10098</a>)</p></li>\n<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>\n<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>\n<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>\n<li><p>El comportamiento de referencia de la plantilla local es inconsistente / confuso</p></li>\n<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>\n</ul>\n<h1 id=\"cmomeinscribo\">¿Cómo me inscribo?</h1>\n<p>Hemos publicado una guía aquí: <a href=\"https://angular.io/guide/ivy\">angular.io/guide/ivy</a></p>\n<p>Siempre debe ejecutar la última versión de Angular desde npm (etiquetada a <code>next</code>) siempre que use Ivy.\nEstaremos haciendo cambios frecuentes en los próximos meses. Puede usar <code>ng update</code>\npara obtener la última versión de la siguiente manera:</p>\n<pre><code class=\"bash language-bash\">ng update —-next @angular/core\n</code></pre>\n<p>Una vez que estés en la última versión, actualiza tu <code>src/tsconfig.app.json</code> para\nincluir <code>“enableIvy\": true</code> bajo un nivel superior <code>angularCompilerOptions</code> llave.</p>\n<p>Cuando ejecutas <code>ng build</code>, haremos la compilación de compatibilidad Angular (<code>ngcc</code>)\nde tu carpeta <code>node_modules/</code> y actualizaremos todos tus archivos de metadatos en un\nformato que podamos convertir en instrucciones Ivy.</p>\n<h1 id=\"danostuopinin\">Danos Tu Opinión</h1>\n<p>Nos estamos acercando rápidamente a un futuro en el que los beneficios de Ivy son\nautomáticos y universales para todos los desarrolladores y el Proyecto Ivy llega a\nuna conclusión. Mientras tanto,\n<a href=\"https://github.com/angular/angular/issues/new?template=1-bug-report.md\">abra un problema</a>\no comuníquese con <a href=\"mailto:devrel@angular.io\">devrel@angular.io</a> para darnos tu\nopinión acerca de tus experiencias con la vista previa.</p>",
            "url": "https://devintent.com/blog/2019-06-08-es-hora-de-la-vista-previa-compatibilidad-de-ivy.md",
            "title": "¡Es hora de la vista previa compatibilidad de Ivy!",
            "summary": "Detalles sobre la vista previa opcional de Ivy en Angular v8.1.0-next.1.",
            "date_modified": "2019-06-08T00:00:00.000Z",
            "tags": [
                "angular",
                "español"
            ]
        },
        {
            "id": "blog/2019-06-11-announcing-the-angularjs-material-v1-1-19-release.md",
            "content_html": "<p>This release is now available in our <a href=\"https://material.angularjs.org/latest/\">Online Documentation</a>,\n<a href=\"https://www.npmjs.com/package/angular-material\">NPM</a>, and Bower.\nIt is also available on the Google CDN\n(<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.19/angular-material.min.js\">JS</a>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.19/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h2 id=\"highlights\">Highlights</h2>\n<p>This is a patch release that includes bug fixes, enhancements, and documentation improvements.</p>\n<ul>\n<li>Fixed the 3 known regressions from the <code>1.1.18</code> release</li>\n<li>Published a new guide for migrating your AngularJS Material app to Angular Material and the CDK</li>\n<li>A number of cross browser bug fixes</li>\n<li>The documentation can now be scrolled while reading it using the up/down/pageup/pagedown keys!</li>\n</ul>\n<h3 id=\"bugfixes\">Bug Fixes</h3>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"features\">Features</h3>\n<ul>\n<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>\n</ul>\n<h3 id=\"documentation\">Documentation</h3>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h3 id=\"contributors\">Contributors</h3>\n<p>Thank you to the contributors who helped with the <code>v1.1.19</code> release:</p>\n<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> |\n| :------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: |\n|                                             <a href=\"https://github.com/Splaktar\">Splaktar</a>                                              |                                              <a href=\"https://github.com/codymikol\">codymikol</a>                                              |</p>",
            "url": "https://devintent.com/blog/2019-06-11-announcing-the-angularjs-material-v1-1-19-release.md",
            "title": "Announcing the AngularJS Material v1.1.19 Release",
            "summary": "Information about the AngularJS Material v1.1.19 Release.",
            "date_modified": "2019-06-06T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2019-05-09-announcing-the-angularjs-material-v1-1-18-release.md",
            "content_html": "<p>We have released AngularJS Material <code>v1.1.18</code>.</p>\n<p>This release is now available in our\n<a href=\"https://material.angularjs.org/latest/\"><strong>Online Documentation</strong></a>,\n<a href=\"https://www.npmjs.com/package/angular-material\"><strong>NPM</strong></a>, and Bower. It is also\navailable 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>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.18/angular-material.min.css\">CSS</a>).</p>\n<p>You can find the details for all releases in our\n<a href=\"https://github.com/angular/material/blob/master/CHANGELOG.md\"><strong>Change Log</strong></a>.</p>\n<h1 id=\"highlights\">Highlights</h1>\n<p>This is a patch release that includes bug fixes, infrastructure, and documentation improvements.</p>\n<ul>\n<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>\n</ul>\n<h4 id=\"knownissues\">Known Issues</h4>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"bugfixes\">Bug Fixes</h1>\n<ul>\n<li><strong>icon:</strong> stop breaking SVGs that have id references</li>\n</ul>\n<h1 id=\"infrastructure\">Infrastructure</h1>\n<ul>\n<li><strong>release:</strong> workaround NPM bug that publishes <code>.git/</code> directory</li>\n</ul>\n<h1 id=\"documentation\">Documentation</h1>\n<ul>\n<li><strong>docs:</strong> fix demos not loading in CodePen</li>\n</ul>\n<h1 id=\"contributors\">Contributors</h1>\n<p>Thank you to the contributors who helped with the <code>v1.1.18</code> release:</p>\n<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>",
            "url": "https://devintent.com/blog/2019-05-09-announcing-the-angularjs-material-v1-1-18-release.md",
            "title": "Announcing the AngularJS Material v1.1.18 Release",
            "summary": "Information about the AngularJS Material v1.1.18 Release.",
            "date_modified": "2019-05-09T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2019-03-31-announcing-the-angularjs-material-v1-1-17-release.md",
            "content_html": "<p>We have released AngularJS Material <code>v1.1.17</code>.</p>\n<p>This release is now available in our\n<a href=\"https://material.angularjs.org/latest/\"><strong>Online Documentation</strong></a>,\n<a href=\"https://www.npmjs.com/package/angular-material\"><strong>NPM</strong></a>, and Bower. It will be\navailable 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>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.17/angular-material.min.css\">CSS</a>).</p>\n<p>You can find the details for all releases in our\n<a href=\"https://github.com/angular/material/blob/master/CHANGELOG.md\"><strong>Change Log</strong></a>.</p>\n<h1 id=\"highlights\">Highlights</h1>\n<p>This is a patch release that includes bug fixes and documentation improvements.</p>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h4 id=\"knownissues\">Known Issues</h4>\n<ul>\n<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>\n</ul>\n<h1 id=\"bugfixes\">Bug Fixes</h1>\n<ul>\n<li><p><strong>autocomplete</strong>: default dropdown position to the bottom again.</p></li>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"documentation\">Documentation</h1>\n<ul>\n<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>\n</ul>\n<h1 id=\"contributors\">Contributors</h1>\n<p>Thank you to the contributors who helped with the <code>v1.1.17</code> release:</p>\n<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>",
            "url": "https://devintent.com/blog/2019-03-31-announcing-the-angularjs-material-v1-1-17-release.md",
            "title": "Announcing the AngularJS Material v1.1.17 Release",
            "summary": "Information about the AngularJS Material v1.1.17 Release.",
            "date_modified": "2019-03-31T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2019-03-18-announcing-the-angularjs-material-v1-1-14-release.md",
            "content_html": "<p>We have released AngularJS Material <code>v1.1.14</code>.</p>\n<p>This release is now available in our\n<a href=\"https://material.angularjs.org/latest/\"><strong>Online Documentation</strong></a>,\n<a href=\"https://www.npmjs.com/package/angular-material\"><strong>NPM</strong></a>, and Bower. It is also\navailable 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>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.14/angular-material.min.css\">CSS</a>).</p>\n<p>You can find the details for all releases in our\n<a href=\"https://github.com/angular/material/blob/master/CHANGELOG.md\"><strong>Change Log</strong></a>.</p>\n<h1 id=\"highlights\">Highlights</h1>\n<p>This is a patch release that includes bug fixes and documentation improvements.</p>\n<ul>\n<li><p>1 memory leak, 2 regressions, and 5 other bugs fixed</p></li>\n<li><p>Fixed an accessibility issue with <code>md-nav-bar</code></p></li>\n<li><p>Fixed linking to specific sections of the documentation site and specific demos</p></li>\n<li><p>Build output (JS and CSS files) will be easier to compare from <code>1.1.14</code> onward</p></li>\n</ul>\n<h4 id=\"knownissues\">Known Issues</h4>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"bugfixes\">Bug Fixes</h1>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"documentation\">Documentation</h1>\n<ul>\n<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>\n<li><p><strong>radio-button</strong>: correct two misspellings of Latin names in the demo</p></li>\n<li><p><strong>colors</strong>: clean up Closure / JSDoc comments and types</p></li>\n</ul>\n<h1 id=\"infrastructure\">Infrastructure</h1>\n<ul>\n<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>\n<li><p><strong>ci</strong>: we moved over to CircleCI from TravisCI in the previous <code>1.1.13</code> release</p></li>\n</ul>\n<h1 id=\"contributors\">Contributors</h1>\n<p>Thank you to the contributors who helped with the <code>v1.1.14</code> release:</p>\n<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>",
            "url": "https://devintent.com/blog/2019-03-18-announcing-the-angularjs-material-v1-1-14-release.md",
            "title": "Announcing the AngularJS Material v1.1.14 Release",
            "summary": "Information about the AngularJS Material v1.1.14 Release.",
            "date_modified": "2019-03-18T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2019-02-28-announcing-the-angularjs-material-v1-1-13-release.md",
            "content_html": "<p>We have released AngularJS Material <code>v1.1.13</code>.</p>\n<p>This release is now available in our\n<a href=\"https://material.angularjs.org/latest/\"><strong>Online Documentation</strong></a>,\n<a href=\"https://www.npmjs.com/package/angular-material\"><strong>NPM</strong></a>, and Bower.\nIt 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>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.13/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h1 id=\"highlights\">Highlights</h1>\n<p>This is a patch release that includes a couple enhancements in addition to bug fixes and documentation improvements.</p>\n<ul>\n<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>\n<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>\n<li><p>A number of issues specific to IE11 and Firefox were resolved.</p></li>\n<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>\n</ul>\n<h4 id=\"knownissues\">Known Issues</h4>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"bugfixes\">Bug Fixes</h1>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<li><p><strong>menu</strong>: fix min-height when scrollable (<a href=\"https://github.com/angular/material/pull/11602\">#11602</a>)</p></li>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"features\">Features</h1>\n<ul>\n<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>\n<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>\n</ul>\n<h1 id=\"documentation\">Documentation</h1>\n<ul>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"contributors\">Contributors</h1>\n<p>Thank you to the contributors who helped with the <code>v1.1.13</code> release:</p>\n<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>",
            "url": "https://devintent.com/blog/2019-02-28-announcing-the-angularjs-material-v1-1-13-release.md",
            "title": "Announcing the AngularJS Material v1.1.13 Release",
            "summary": "Information about the AngularJS Material v1.1.13 Release.",
            "date_modified": "2019-02-28T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2019-01-04-announcing-the-angularjs-material-v1-1-12-release.md",
            "content_html": "<p>We have released AngularJS Material <code>v1.1.12</code>.</p>\n<p>This release is now available in our\n<a href=\"https://material.angularjs.org/latest/\"><strong>Online Documentation</strong></a>,\n<a href=\"https://www.npmjs.com/package/angular-material\"><strong>NPM</strong></a>, and Bower. It is also\navailable 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>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.12/angular-material.min.css\">CSS</a>).</p>\n<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>\n<h1 id=\"highlights\">Highlights</h1>\n<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>\n<h1 id=\"bugfixes\">Bug Fixes</h1>\n<ul>\n<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>\n<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>\n</ul>\n<h1 id=\"contributors\">Contributors</h1>\n<p>Thank you to the contributors who helped with the <code>v1.1.12</code> release over the holiday break:</p>\n<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>",
            "url": "https://devintent.com/blog/2019-01-04-announcing-the-angularjs-material-v1-1-12-release.md",
            "title": "Announcing the AngularJS Material v1.1.12 Release",
            "summary": "Information about the AngularJS Material v1.1.12 Release.",
            "date_modified": "2019-01-04T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2018-12-31-announcing-the-angularjs-material-v1-1-11-release.md",
            "content_html": "<p>We have released AngularJS Material <code>v1.1.11</code>.</p>\n<p>This release is now available in our\n<a href=\"https://material.angularjs.org/latest/\"><strong>Online Documentation</strong></a>,\n<a href=\"https://www.npmjs.com/package/angular-material\"><strong>NPM</strong></a>, and Bower. It is also\navailable 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>,\n<a href=\"https://ajax.googleapis.com/ajax/libs/angular_material/1.1.11/angular-material.min.css\">CSS</a>).</p>\n<p>You can find the details for all releases in our\n<a href=\"https://github.com/angular/material/blob/master/CHANGELOG.md\"><strong>Change Log</strong></a>.</p>\n<h1 id=\"highlights\">Highlights</h1>\n<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>\n<p>Here are the highlights:</p>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h4 id=\"advisories\">Advisories</h4>\n<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>\n<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>\n<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>\n<p>We hope to have a <code>v1.1.12</code> release out in mid-January.</p>\n<h1 id=\"bugfixes\">Bug Fixes</h1>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"features\">Features</h1>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<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>\n<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>\n</ul>\n<h1 id=\"performanceimprovements\">Performance Improvements</h1>\n<ul>\n<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>\n<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>\n<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>\n</ul>\n<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>\n<h1 id=\"documentation\">Documentation</h1>\n<ul>\n<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>\n<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>\n<li><p>We also made changes across the docs and demos to properly support dark mode themes.</p></li>\n<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>\n<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>\n<li><p><strong>contact-chips:</strong> add docs for <code>md-highlight-flags</code></p></li>\n<li><p><strong>highlight-text:</strong> add <code>md-highlight-flags</code> example</p></li>\n<li><p><strong>list:</strong> clarify the docs around <code>md-avatar-icon</code></p></li>\n<li><p><strong>slider:</strong> add missing docs for APIs like <code>md-vertical</code>. Fix demos in IE11</p></li>\n<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>\n<li><p><strong>select:</strong> add missing docs for <code>md-option</code> and <code>md-optgroup</code></p></li>\n<li><p><strong>toast:</strong> add example of using <code>locals</code> to the custom toast demo</p></li>\n<li><p><strong>typography:</strong> fix URL for Roboto font and general cleanup of the guide</p></li>\n</ul>\n<h1 id=\"contributors\">Contributors</h1>\n<p>Thank you to the <a href=\"https://github.com/angular/material/blob/master/CHANGELOG.md#contributors\">contributors</a>,\nespecially the first timers, who helped with the v1.1.11 release:</p>\n<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>",
            "url": "https://devintent.com/blog/2018-12-31-announcing-the-angularjs-material-v1-1-11-release.md",
            "title": "Announcing the AngularJS Material v1.1.11 Release",
            "summary": "Information about the AngularJS Material v1.1.11 Release.",
            "date_modified": "2018-12-31T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2018-12-07-my-experience-with-the-macbook-pro-2018-w-vega-graphics.md",
            "content_html": "<p>After exploring the\n<a href=\"https://www.devintent.com/blog/2018-11-25-my-pixelbook-dev-experience\">Pixelbook as a development platform</a>,\nI decided that I need to replace my mid-2014 MBP w/ 16 GB RAM 256 GB SSD and Intel graphics with the new\n2018 MBP w/ Touch Bar 32 GB RAM 512 GB SSD and Vega 20 graphics.</p>\n<p>I am going to use this post to chronicle the first days of using this machine. I hope that it will help other\ndevelopers and professionals who may also be looking at the latest MacBook Pro line up. Oh and I’m sure\nthere will be some gaming content in here as well 😁</p>\n<h1 id=\"day0\">Day 0</h1>\n<p>When I purchased my 2014 MBP, I opted to pass on the Nvidia discrete graphics card. This was based on two\nprimary drivers: heat and usage.</p>\n<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\nMBP. I was also upgrading from a Chromebook Pixel 2013 which had a very hot i5 CPU. Thus, I wanted to get a\ndevice that I could use on my lap while doing basic web browsing or writing.</p>\n<p>Fast forward to 2018, my 2014 MBP is 4.5 years old and well outside of the extended warranty plus my gaming\ndesktop is about to be retired. I’m also in a situation where I anticipate needing to be able to do all of my\nprofessional work on a mobile platform for the next few years. This means that something like the attractive\n2018 Mac mini won’t work for me.</p>\n<p>I watched the early 2018 MBP i9 thermal drama unfold from a distance. I was happy to see that Apple quickly\nreleased a patch for this. The resulting benchmarks were acceptable to me. Additionally, as a developer, the\nburst speed of the i9 processor is valuable to me as it helps to eliminate micro interruptions in my workflow.\nI don’t really need to run the CPU at max for extended periods of time as is needed for video processing.</p>\n<p>I was convinced to go with the Vega 20 after watching a number of videos that covered the benchmarks,\nthermals, and real world performance. For reference, some of those include:</p>\n<ul>\n<li><p><a href=\"https://www.youtube.com/watch?v=cw1daSLJ-rc\">Vega 20 MacBook Pro Benchmarks vs 560X!</a></p></li>\n<li><p><a href=\"https://www.youtube.com/watch?v=OEgl4B8A_qw\">Gaming on the VEGA 20 MacBook Pro — 2018</a></p></li>\n<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>\n<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>\n<li><p><a href=\"https://www.youtube.com/watch?v=2zWSNHuqtPA\">Best MacBook Pro? (Radeon Vega 20) — Unboxing + Benchmarks</a></p></li>\n<li><p><a href=\"https://www.youtube.com/watch?v=neRjnJ4SWMk&t=1s\">Gaming on the Vega 20 MacBook Pro!?</a></p></li>\n</ul>\n<p>A brief summary of those videos</p>\n<ul>\n<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>\n<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>\n<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>\n<li><p>The i9 w/ Vega 20 graphics provided a ~20–60+% increase to graphics performance for ~10% increase in cost.</p></li>\n<li><p>Gaming on Windows 10 in Boot Camp provided an increase of about 10–25 FPS over the same in macOS.</p></li>\n</ul>\n<p>Additionally, I researched peripherals and adapters so that I could work with USB-C effectively. I\npicked up a <a href=\"https://smile.amazon.com/gp/product/B07B9PJ7FQ/\">USB-C card reader</a> and\n<a href=\"https://smile.amazon.com/gp/product/B07BT11PTP/\">two Thunderbolt 3 to HDMI adapters</a>. These were used to\nhook up my two external monitors and, since the MBP has 4 USB-C ports, I’ll also be able to\nplug in power and a dongle for my external mouse and keyboard. The adapters also came with a discount for a\n<a href=\"https://smile.amazon.com/gp/product/B07F7HY6VW\">Thunderbolt 3 to VGA adapter</a> which will be useful when\npresenting at some schools and meetups. I decided to wait on ordering a dock until I was confident the\nlaptop was going to be a keeper. The dock that I have my eye on is the\n<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>\n<p>My new MBP shipped straight from Shanghai. There was a delay of 2 days in Japan and that triggered UPS to\npush my expected delivery date by 4 days. Thankfully, soon after that it started moving again and was quickly\nback on track for on time delivery.</p>\n<h1 id=\"day1\">Day 1</h1>\n<p>When FedEx delivered my new MBP, it was a familiar unboxing experience. I went with silver, partially since\nI didn’t want a darker color that might absorb more external heat. It’s probably only the smallest possible\ndifference, but it was enough for me 😉</p>\n<p>The feel and build was similar to by 2014 MBP, but there were some differences. It felt slightly thinner\noverall and instead of a light up apple on the top, it’s just a shiny silver apple. 👍🏼</p>\n<p>When I opened it up, the giant touchpad really stood out and worried me that it might cause issues\nwhile typing. The Touch Bar was there too… and the keyboard…</p>\n<p>Thankfully it arrived with macOS Mojave already installed.</p>\n<h4 id=\"migration\">Migration</h4>\n<p>I booted it up and wasn’t sure what to expect of the Migration Assistant. The first attempt was with Wi-Fi,\nbut 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\ncable that came with my Pixel XL and plugged that in to each laptop. My old MBP detected it and switched to\nPeer-to-Peer networking, but the new MBP got stuck at “Switching”.</p>\n<p>I had to cancel and restart the process. This time connected via USB from the start. I also had to make sure\nto overwrite and not duplicate any of the users, or the files (uncheck a box in the Migration Assistant wizard).\nThe migration went smoothly this time. It originally estimated around 3 hours and 45 minutes to complete, but\nit was done within a couple of hours.</p>\n<p>I knew that it was going to try to migrate some apps and settings, but I didn’t have high hopes and expected\nto install a bunch of apps and tweak a lot of settings after it was done. To my surprise, it basically copied\nover my entire device to the new device with almost nothing missing other than re-granting security and\naccessibility permissions! <strong>This was really the experience that I was hoping for!</strong></p>\n<p>This gives me a lot of confidence that should I have a MBP fail, I can restore to another MBP device from a\nTime Machine backup and be productive again in just a couple of hours. This is critical to me and my\nconsulting business.</p>\n<h4 id=\"bootcamp\">Boot Camp</h4>\n<p>I read a number of articles about installing Windows 10 via Boot Camp and it seemed somewhat straight forward.\nIt was my first time working with Boot Camp though.</p>\n<p>I downloaded the 5.08 GB Windows ISO from October 2018. I picked 150 GB for my Windows 10 partition and started\nit up. After about 30 minutes, it failed to copy the Windows files and started trying to back out the\npartitions that it had created. This seemed to get stuck, so I had to cancel it and manually clean up the\npartitions as detailed <a href=\"https://twocanoes.com/using-larger-windows-10-isos-with-boot-camp-assistant/\">here</a>.</p>\n<p>That <a href=\"https://twocanoes.com/using-larger-windows-10-isos-with-boot-camp-assistant/\">same article</a> explained\nthat the issue was Boot Camp’s partitions being FAT32 which support file sizes up to 4 GB. Then it provided a\nBoot Camp ISO Converter tool to split the ISO into smaller chunks in Boot Camp. I also disabled Time Machine\nand installed an update to Mojave just to be safe. This worked like a charm for me!</p>\n<p>Windows 10 on a Mac was quite disorientating to me initially. Dragging windows with the touchpad didn’t seem\nto work and tap to click wasn’t enabled. Thankfully I found options in the Boot Camp settings to enable tap\nto click. It also had an option to change how window dragging worked, but that didn’t seem to help. I just\nhad to figure out that I had to click and drag all with one finger instead of holding a click with one\nfinger and dragging with another finger.</p>\n<p>There were some prompts to install drivers, Windows updates that needed to install, virus scanning, and the\nusual range of other Windows tasks that had to be sorted out. I also went and cleaned up most of the privacy\nsettings, disabled Cortana, and uninstalled as many Windows store apps as possible. Oh but I did install\nSlack from the Windows store. Then I downloaded and installed Chrome, Firefox, NVDA, Guild Wars 2, and\nStar Wars, The Old Republic.</p>\n<p>Downloading, installing, and patching these games really gave the machine a workout. It flew through most\ntasks, but this got the fans going and got the CPU load up to around 18% while the Wi-Fi was going as fast as\npossible (unfortunately, we don’t have Fiber here). Even with all of this load, the palm rest remained a\ncomfortable ~45C while the CPU ramped up to around ~80C. It certainly created a hot spot on my desk and\nwould not have been comfortable on my lap under this kind of load.</p>\n<p>That said, while sitting here in macOS with a 30+ open Chrome tabs, Slack open, numerous menu add-ons\nrunning, lots of Chrome extensions enabled, and writing this post, the palm rest is at a cool 30C, the GPU\nis only 35–40C, and the CPU is 38–45C. These temperatures are perfectly comfortable to use on your lap.</p>\n<p>The MBP handled this load just fine over a period of about 3–4 hours while ~80GBs of game assets and patches\nwere downloaded. After one of the games finished, and the other was playable, but downloading background\nupdates, I decided to walk away for a bit and shut the lid. Doh! I hadn’t changed the Windows 10 settings\nfor this, and it went to sleep right away. I could tell when the fans cut off about 20 seconds after closing\nthe lid.</p>\n<p>I opened it back up and went to change the setting when <strong>BSOD</strong>! Windows crashed, and the Event Viewer\ndidn’t have much useful information for me. I didn’t see anything related to bridges or T2 chips… After\nrebooting, I was able to change the setting and get it to keep running after closing the lid.</p>\n<p>About 5 hours later, after all the updates and downloads finished, I was installing NVDA when\nWindows 10 prompted me with a popup about sound issues. Then another <strong>BSOD</strong>! After rebooting, I was\nable to install NVDA without any problems. I tested using it for a bit and verified that sound was\nworking in Google Play Music.</p>\n<p>Using a <a href=\"https://smile.amazon.com/nonda-Adapter-Thunderbolt-Aluminum-Indicator/dp/B015Z7XB30/\">Nonda USB-A to USB-C adapter</a>,\nI was able to work with my U2F security key just fine. This adapter is Thunderbolt 3 compatible and passes\ndata just fine while I have another adapter that only handles charging and doesn’t work with data. Keep\nthis in mind if you are looking into USB-C adapters. I had picked up this attractive Nonda adapter at\n<a href=\"https://devfestflorida.org/\">DevFest Florida</a> 2016 as a speaker’s gift.</p>\n<h1 id=\"day2\">Day 2</h1>\n<h4 id=\"backtomacos\">Back to macOS</h4>\n<p>I decided to head back to macOS in order to write up the first day of experiences and to start testing\nperipherals like my external keyboard, mouse, monitors, and backup drive.</p>\n<h4 id=\"keyboard\">Keyboard</h4>\n<p>Now I’ve been typing on this keyboard for a few hours now… It’s certainly worse than my 2014 MBP, and\nit’s much worse than the Pixelbook’s keyboard. Even with the minimal typing required for installing\nsoftware and entering basic details, it caused me to make a lot more mistakes than usual. I figured that\nthis might just take some getting used to, so I waited until day 2, after writing this post, to provide\nfeedback on the typing.</p>\n<p>So the verdict after writing up this post with the MBP 2018 keyboard? I can certainly still type fast!\nBut there are a lot missed keystrokes and mistyped keys, much more than any other typing experience that\nI’ve had in years. The “new, softer sounding keys” are too loud for my tastes and the “new, softer feel”\nis also not something that I am happy with.</p>\n<p>The arrangement of the up and down arrow keys on the MBP is not something that I like compared to the 2014\nmodel. That said, it hasn’t caused me too much pain, yet.</p>\n<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\n20% 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\nit a bunch of times here in Medium, the light stays off, but the caps lock mode does enable and disable.\n<strong>Solved:</strong> this turned out to be a <a href=\"https://github.com/tekezo/Karabiner-Elements/issues/1502\">bug in Karabiner</a>\nthat was fixed in their beta a couple months ago and just got fixed in their stable release in February 2019.</p>\n<p>In my home office, these keyboard issues won’t be a problem since I’ll be using a trackball and external\nkeyboard. However, I’ve never been a person to carry an external keyboard to co-working spaces. That may\nneed to change. I wonder if there is already a keyboard on Kickstarter that fits over the top of the\nMBP’s keyboard 🤔</p>\n<p>Now before we get into the Touch Bar, I just wanted to be clear, the MBP 2018 keyboard is by far the\nmost underwhelming and disappointing feature of the device.</p>\n<h4 id=\"touch\">Touch</h4>\n<p>I am generally happy with the touchpad so far. I’m also happy with the Touch ID sensor. However, I wish that\nI could use my fingerprint for even more of the admin password prompts.</p>\n<p>The Touch Bar experience in Windows 10 was a little confusing. Sometimes the volume up and down virtual\nkeys would work, sometimes they would not. The <code>esc</code> key seemed to work.</p>\n<p>The Touch Bar experience is unsurprisingly better in macOS. I have enjoyed being able to tap the volume or\nbrightness buttons and then use the slider to find a setting that I was happy with. Some shortcuts\nin Finder and Chrome are useful, but I haven’t used them much yet.</p>\n<p>Slack doesn’t offer anything but the default <code>esc</code> and brightness / volume / mute / Siri virtual buttons.</p>\n<p>The Touch Bar in JetBrains’ WebStorm and IntelliJ IDEA seems quite useful! Here’s what I see when I open a project:</p>\n<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>\n<p>You can see that it offers me a menu to pick from the Run Configurations, then buttons to run, debug, or\nstop a Configuration. Additionally, it offers to the Git Update and Git Commit buttons.</p>\n<p>If you open the Run Configurations menu, you can scroll through the options in the Touch Bar:</p>\n<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>\n<p>In this case, there is a green dot on “Watch Site” because it is currently running. If I exit the menu,\nI can see that the Run button has changed to Re-run, and the Stop button is enabled:</p>\n<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>\n<p>Even the Git Commit dialog has Touch Bar support. In this case it saves me an extra click by showing\n“Commit and Push…” in the Touch Bar:</p>\n<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>\n<p>Since I use a Logitech K800 Wireless, back-lit keyboard with a Windows layout for most of my work, I have\nthe F1-FX keys mapped to actions like volume up/down, mute, etc. Thus, I don’t really make use of these\nFunction keys when doing development. My primary shortcuts in WebStorm are all configured to use\n<code>control</code> , <code>shift</code> , <code>option</code> , combinations instead.</p>\n<p>That means that I’m not really sad to be “missing” the F keys. I also haven’t hit a situation yet where\nI needed the <code>esc</code> key, and it wasn’t there. I’ll certainly be keeping my eye open for that though.</p>\n<p>Verdict after 2 days: I’m learning to live happily with the new Touch Bar. Hopefully I don’t like it too\nmuch though. There are no external keyboards with Touch Bars yet and getting used to this 2018 MBP\nkeyboard isn’t proving to be easy.</p>\n<h4 id=\"peripherals\">Peripherals</h4>\n<p>Everything went super smoothly with hooking up two 27\" AOC 1080p HDMI monitors, an Anker 10 port\nUSB 3.x Hub, and power. The time it takes to wake and sync the monitors seems to be cut in half\ncompared to my 2014 MBP w/ Intel graphics.</p>\n<p>I was a little worried that, with all 4 USB-C ports in use, I would have a problem with using my\nTitan U2F Security key. That was solved easily by just plugging it into my Anker Hub.</p>\n<p>I haven’t had time, or a need to test out my Uni Thunderbolt 3 to VGA Adapter or\nAnker Thunderbolt 3 SD Card Reader yet.</p>\n<p>It’s certainly a pleasure to be using this high speed laptop with my beloved Logitech K800 keyboard and\nM570 Trackball!</p>\n<h4 id=\"additionalperipheralresearch\">Additional Peripheral Research</h4>\n<p>I noticed that Logitech released the new <a href=\"https://smile.amazon.com/gp/product/B0753P1GTS\">MX Ergo Trackball</a>\nlast year. So I put in an order immediately since it was at its lowest price in 4+ months (it’s now about \\$6\nhigher than yesterday). I can’t wait to try it out after 5 solid years with two of the M570s.</p>\n<p>I also did a lot of research on keyboards in the last 2 weeks. I got some great recommendations for things\nlike the Code keyboard, and the Apple Magic keyboard, however I’m looking for a wireless, back-lit keyboard\nwith a Mac keyboard layout. The Code isn’t wireless. The Magic isn’t back-lit. The K800 has a Windows layout.</p>\n<p>I looked at the Macally keyboards, but wasn’t able to find a good fit. However, it sounds like they may be\nlaunching something that meets my needs in the next few months.</p>\n<p>I got a suggestion for Matias keyboards as well, but there are too many reviews that are very negative on\nthe typing experience.</p>\n<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>.\nHowever, it’s $199 MSRP (twice that of the K800) stopped me in my tracks. It’s currently $169 on Amazon, but\nI’m going to try waiting a few more months to see if there are any price dips. One of the biggest complaints\nwith the Craft is the Logitech software support. Hopefully over the next few months, they can squash a few\nmore bugs.</p>\n<h1 id=\"day3\">Day 3</h1>\n<p>I spent a good deal of time cleaning up my machine today. This meant removing old VirtualBox VMs and\nuninstalling VirtualBox since I have VMWare Fusion now. While doing that I noticed some old multi-GB\ndocker images, Android Virtual Devices, and some other cached files from NVM, Gradle, Maven, etc that\ncould be cleaned up.</p>\n<p>I also noticed that some programs weren’t compatible with Mojave. This wasn’t an issue with the new MBP,\nas the same needed to be done on my old laptop as well. This just meant downloading and installing updates\nto things like KeyCastr, Robo 3T, Android File Transfer, Postman, Logitech Camera Settings, Logitech\nControl Center, etc.</p>\n<p>While Git, SSH, GPG, and many other CLI tools were working fine after the migration, there were still\nsome issues with MacPorts giving some <code>plist</code> warnings when running <code>sudo port selfupdate</code>. I followed\nthe steps in the <a href=\"https://www.macports.org/install.php\">Install Guide</a> and I was back up and running\n(without needing to do the steps in the <a href=\"https://trac.macports.org/wiki/Migration\">Migration Guide</a>).</p>\n<p>I also spent some time customizing the key mappings when using my external keyboard via\n<a href=\"https://pqrs.org/osx/karabiner/\">Karabiner Elements</a>. While doing this, I noticed that my volume up,\nvolume down, and mute keyboard buttons were working w/o the need to map them to a Function key.\nSome time ago, this wasn’t working on my 2014 MBP, but I didn’t go back to verify if this still an\nissue on that device.</p>\n<p>Just like I saw with the built-in keyboard, the <code>caps lock</code> light not coming on while using my\nLogitech K800. I tried to enable Karabiner’s option to “manipulate” the Caps Lock LED, but it didn’t help.\n**Solved: **this turned out to be a <a href=\"https://github.com/tekezo/Karabiner-Elements/issues/1502\">bug in Karabiner</a>\nthat was fixed in their beta a couple months ago and just got fixed in their stable release in February 2019.</p>\n<p>I ran into some confusing behavior in Chrome that seems to be related to the Migration. I went into Sharing\nSettings to give this new Mac an updated Name. This didn’t seem to help though. Whenever I go into Chrome’s\nHistory and look at “tabs from other devices”, I can’t see tabs from my 2014 MBP. It’s like Chrome somehow\nthinks that the two devices are a single device. I disabled and re-enabled sync on both devices without any\nluck. I stopped short of completely clearing my sync data, which the forums mentioned may be required.</p>\n<p>I also setup Chrome Remote Desktop. After the migration, this meant disabling remote desktop on both MBPs\nand then re-enabling it with updated names and PINs.</p>\n<p>Overall, things are feeling clean and fast now. This “Spring cleaning” cleared up around 20 GB of disk space.</p>\n<p>I also watched a nice summary video on this machine from AppleInsider</p>\n<ul>\n<li><a href=\"https://www.youtube.com/watch?v=0zmxkmDDpAM\">Vega 20 MacBook Pro Review — The Dream is Finally Complete!</a></li>\n</ul>\n<p>It looks like some of my keyboard settings didn’t make the migration. I noticed that I wasn’t able to hold\na key to have it repeat. This is especially important with <code>delete</code>. I found that the “Delay Until Repeat”\nsetting in Keyboard settings was set too long. I moved it to the second shortest value. Then <code>delete</code>\nstarted working as expected. So of course I tried it with some other keys like <code>aaaaaa</code>, but that didn’t\nwork! Instead, it opened up an accent picker.</p>\n<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>\nhelped me understand what was going on. I am happy with the <code>option</code> shortcut method:</p>\n<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>\n<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.\nUsing this same approach but typing <code>option+u</code> and then <code>e</code> will give you <code>ë</code>. Great! This will work\nperfectly for me when I need to use different accents (something that I am trying to get better with in\nSpanish).</p>\n<p>However, I want to repeat keys on long press. To do that, I found\n<a href=\"https://apple.stackexchange.com/a/167834/87494\">this answer</a> which advised running the following in the\nTerminal to disable the accent picker on long press:</p>\n<pre><code class=\"bash language-bash\">defaults write -g ApplePressAndHoldEnabled -bool false\n</code></pre>\n<p>Then you need to reboot for it to take effect.</p>\n<h1 id=\"day4\">Day 4</h1>\n<p>I went back to work with a full focus on productivity. This machine blew my mind with its speed 🚀 and\ngeneral productivity boosts ❤️. I haven’t taken measurements yet (planning on it), but there is a very\nnoticeable improvement in the speed in my every day development and testing tasks.</p>\n<h1 id=\"day5\">Day 5</h1>\n<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\nphotos off of my DSLR. Then I proceeded to copy and organize those files before batching uploads to both\nGoogle Photos and a Synology NAS. This resulted in driving the network card and CPU quite heavily for many\nhours in a row. Everything went extremely smoothly.</p>\n<p>I’m not an experienced video editor, but I did some work on some small video editing in iMovie. I’ve\nidentified a 2.75 GB video that I plan to do some additional testing with. Other than my own issues\nlearning to use the iMovie user interface, everything here went smoothly as well.</p>\n<p>The Logitech MX Ergo Trackball arrived. Pairing it up with the Logitech receiver and installing Logitech\nOptions was simple. The transition from the Logitech M570 Trackball was pretty smooth. After a few hours,\nmost all the minor differences faded away. This even included using the Ergo at the 20 degree tilt.\nI appreciate the minor amount of extra friction / stepping in both the trackball, and the mouse wheel.\nThe precision mode is very handy, but I forgot to use it earlier when I was editing images in GIMP.</p>",
            "url": "https://devintent.com/blog/2018-12-07-my-experience-with-the-macbook-pro-2018-w-vega-graphics.md",
            "title": "My Experience with the MacBook Pro 2018 w/ Vega graphics",
            "summary": "Description of migrating to and configuring a new MacBook Pro 2018 w/ Vega graphics from a web developer.",
            "date_modified": "2018-12-07T00:00:00.000Z",
            "tags": [
                "mac",
                "webstorm",
                "chrome",
                "git"
            ]
        },
        {
            "id": "blog/2018-11-25-my-pixelbook-dev-experience.md",
            "content_html": "<p>I ordered the <code>i7 16GB RAM 512GB SSD</code> Pixelbook with the Black Friday deal that started on\nNovember 22nd.</p>\n<h1 id=\"day1\">Day 1</h1>\n<p>My Pixelbook arrived this afternoon. Within a few hours, I’ve already got my\n<a href=\"https://www.devintent.com/blog/2018-11-24-using-a-pixelbook-for-angular-development\">primary dev tooling installed and working</a>!\nThere were only a few minor bumps in the road, and they were quickly resolved with a quick Google search.</p>\n<p>I’m curious how things will play out over the next week as I try to push it for productivity tasks.</p>\n<p>I’ll also be monitoring the thermal performance since I don’t want to be working at some point in\nthe future with burning finger tips. So far today, I felt some heat when I reached up above the\nkeyboard and below the screen. However, when I checked\n<a href=\"https://chrome.google.com/webstore/detail/cog-system-info-viewer/difcjdggkffcfgcfconafogflmmaadco?utm_source=chrome-app-launcher-search\">Cog</a>,\nthe temps were actually not bad at all (160 F / 71 C or less).</p>\n<p>With the machine mostly idle, 4–5 tabs open, while I wrap up this post, the CPU is barely over body\ntemperature at 104–109 F.</p>\n<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>\n<p>The battery life is very impressive so far. I’ve been off of power most all day, and I’ve still got\nover 30% power remaining and almost 3 hours of estimated run time.</p>\n<p>I’ll also be doing a good deal of testing with Bluetooth. I was able to use an LG Tone 700 headset\nfor over an hour today without any disconnections or issues.</p>\n<p>There has been one minor usability glitch that has bothered me a few times today. On about 5–10\ndifferent occasions, the machine seemed to lag or freeze up. Sometimes this was only affecting the\nscroll of the touch pad, or the responsiveness of the touch screen. Other times the entire UI was\nfrozen and there was no way to interact with the device. This generally only lasted 1–20 seconds…\nuntil just about 5 minutes ago.</p>\n<p>I wrote 99% of this post on the Pixelbook, but I’m finishing up the first draft here on my mid-2014\nMacBook Pro. With 30% battery left and low heat (as seen above), I closed all of my Linux and\nAndroid apps. I also closed a few open tabs to get down to only 4 tabs open. Then while making\nminor edits to this post in the Medium web app, everything froze.</p>\n<p>It never came back. After about 5 minutes, the machine rebooted itself to this:</p>\n<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>\n<p>I pressed the power button and tried to reboot it, but it just turned off. There were no connected\ndevices. Nothing I did was able to wake it back up, even holding the power button for 30+ seconds,\nuntil I plugged it into power. It then booted up pretty quickly and still had 29% battery left.</p>\n<p>That was… a little scary. When I first unboxed the device, I had a similar experience. I couldn’t\nget the power button to do anything. Only when I connected my Pixel XL via USB-C did it power on\nand start responding.</p>\n<h1 id=\"day2\">Day 2</h1>\n<p>I found out that the Chrome OS missing or damaged screen\n<a href=\"https://www.digitaltrends.com/computing/most-common-pixelbook-problems/\">isn’t new and isn’t that uncommon</a>.</p>\n<p>I didn’t have a lot of time today for development tasks, but I did get a good deal of web browsing,\nand a little Android gaming done. I found that using the device on the lap in either tablet or\nlaptop mode did not generate enough heat to bother me. This was after about an hour of web browsing\nand some <a href=\"https://play.google.com/store/apps/details?id=com.ea.game.starwarscapital_row\">Star Wars Galaxy of Heroes</a>.</p>\n<p>On the gaming side, I’m still getting a feel for the touch screen as there are quite a few occasions\nwhere I don’t touch it with enough force to register and need to tap again. Gaming performance-wise,\nI’m seeing a significant improvement over my Nexus 9, but I feel like my Pixel XL may outperform the\nPixelbook in the GPU category.</p>\n<p>I was able to get the Google Cloud SDK (gcloud) installed using their\n<a href=\"https://cloud.google.com/sdk/docs/downloads-apt-get\">instructions for Debian</a>.</p>\n<p>I was able to get IntelliJ IDEA installed and running with almost the same instructions that I used\nfor WebStorm. I ran into an issue with the Google Cloud Tools plugin and\n<a href=\"https://github.com/GoogleCloudPlatform/google-cloud-intellij/issues/2295\">opened a bug</a>.</p>\n<p>I was also able to get Android Studio installed and running. I am generally able to install the\nSDKs and libraries and get my Gradle builds to succeed. However, there are a number of other minor\nissues like not being able to sign in to Google due to the callback going over a port that isn’t\nforwarded to Crostini and resolution of secondary SSH keys when using Git. Android Studio suggested\nthat I install <code>libsecret-1-0</code> and <code>gnome-keyring</code> so that it could preserve access to my keys, but\nit doesn’t appear to be working.</p>\n<p>I’m also seeing an issue where I need to re-authenticate with GitHub either after rebooting or\nre-launching of WebStorm. It says “missing access token” as if the previous token has been lost. I’m\nseeing similar issues using a secondary SSH key in WebStorm as well.</p>\n<p>I’m getting the feeling Crostini and Chrome OS are on the edge of being a real development platform.\nHowever, the concern that Crostini (beta) may have too many productivity-draining issues with edge\ncases is getting more real.</p>\n<h1 id=\"day3\">Day 3</h1>\n<p>I spent many more hours trying to get a second SSH key to work in IntelliJ IDEA and WebStorm. I\ntried both the Built-In and Native SSH, but had no luck. Then I learned about, and setup, a\n<a href=\"https://www.reddit.com/r/Crostini/comments/8rt9gq/sshagent/\">ssh-agent service with systemctl</a>.\nAdditionally, I tried <code>keychain</code> and <code>gnome-keyring</code>some more. Even though everything appeared to be\nset up properly and worked from the Terminal, it would never work from the IDE.</p>\n<p>I finally just gave up and decided to use the key for associated with my BitBucket account for\naccessing both GitHub and BitBucket. I was able to add that email address to my GitHub account.\nI’ll have to wait and see if this causes me problems with some PR review bots, commit\nverification, or CLA checks in GitHub.</p>\n<p>I found out today the issue I reported about the Google Cloud Tools plugin for IntelliJ IDEA wasn’t\nspecific to Chrome OS. It was just an issue that they hadn’t added support for the latest version of\nIntelliJ (2018.3). They released that fix today, and it resolved the issue.</p>\n<p>I did however run into another problem with that plugin. It uses a strategy where it logs you in\nvia OAuth redirects. However, when it tries to send the confirmation back to the IDE, the browser\nshows a Not Found page. This is because they use a random high level port (40–60K) each time, and\nthose ports are not forwarded between Crostini and Chrome OS. Only some well-known ports\nare forwarded. For now, being logged into the Google Cloud Tools plugin is not critical for my work,\nso I am going to ignore this issue.</p>\n<p>That said, Firebase is critical for my work, and they use a similar model for authenticating with\ntheir <code>firebase-tools</code> CLI. I’ll have to give that a shot soon to see if it will be a problem.</p>\n<p>Another important activity that I did today was hosting a two-hour Hangouts Meet video call. I did\nthe whole call connected to my LG HBS 700 Bluetooth headset without any issues. I did some screen\nsharing and navigated through a few tabs while on the call. Everything was smooth for about 99% of\nthe call. I didn’t notice any excess heat being generated and the keyboard and palm rests were still\ncomfortable to use.</p>\n<p>The other person on the call was also using a Pixelbook. While the video quality on both sides was\nacceptable, I wasn’t really impressed. The Pixelbook has a 720p 60 FPS webcam which should be\nsimilar in quality to my MacBook Pro mid-2014’s 720p webcam. However, in this small sample, I felt\nthat it wasn’t really up to par with my MacBook Pro. There was a bit of graininess and as it got\ndark, the low light performance didn’t seem to be very good.</p>\n<p><em>Note that this is just anecdotal evidence based on a general feel and not head-to-head comparison.</em></p>\n<p>I also have some feedback on the keyboard, palm rests, and track pad. In general, the keys have a\nreally nice feel and are a pleasure to press. I do still get a little disoriented at times and end\nup pressing keys 1 column to the right, but I don’t see that being a long term issue.</p>\n<p>I <strong>VERY</strong> frequently press the Assistant key when I do not desire to speak with the Assistant. I\nreally wish that it was up near the function keys, perhaps replacing the hamburger/settings key.\nHowever, I haven’t taken the step to disable it yet, but it’s certainly under consideration.</p>\n<p>The palm rests are excellent! They are very comfortable and keep quite cool! Similarly, the track\npad is really a pleasure to use! Sometimes Chrome OS doesn’t scroll quite as smoothly or\nresponsively as I would like, but that isn’t an issue with the track pad itself.</p>\n<p>I did some interesting reading today over at the\n<a href=\"https://old.reddit.com/r/Crostini/wiki/index\">Crostini Wiki</a> and\n<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>.\nThe wiki has some great resources and guides for installing and configuring different tools. The\nblog post covers some internals of how Crostini is built.</p>\n<p>Oh! Finally, I learned\n<a href=\"https://9to5google.com/2018/02/12/how-to-use-emoji-chrome-os-android-basics/\">how to insert emojis</a> 🌟!\nThis is also helpful for adding in some special characters like jalepe<strong>ñ</strong>o. Unfortunately, the\nemoji picker doesn’t have text search (like macOS or Slack) 😞 and there are no tooltips on hover\nto help you differentiate similar emojis. Additionally, there appears to be a bug where I’m not\nable to use the trackpad to scroll through all the emojis (the touch screen does allow you to\ndo this though).</p>\n<h1 id=\"day4\">Day 4</h1>\n<p>While I have not run into Bluetooth issues with my Pixelbook, there are a lot of other reports out\nthere. It looks like a firmware fix from Intel will help mitigate some of these issues in\nChrome 71 (beta). Stay up to date by starring this\n<a href=\"https://bugs.chromium.org/p/chromium/issues/detail?id=904571\">bug</a>.</p>\n<hr />\n<p>I’m finally running into random Bluetooth disconnections. I had 3 of these today in about 30 minutes\nof SWGOH with my LG HBS 700 connected. One note on the positive side, this is certainly the best\nsound I’ve ever had on SWGOH. On some Android devices (like the Nexus 9), I can sometimes get poor,\ncrackling audio. On the Pixelbook, it was so crisp and deep! I heard sounds that I had never been\nable to discern before!</p>\n<p>It looks like there is some bad news for Pixelbook Bluetooth users in the above bug. Today, the\nChromium team responded that while things have been improved with the firmware update in Chrome 71,\nthere is still an underlying hardware issue that won’t be able to be resolved in existing hardware\n(Pixelbooks included).</p>\n<p>If you need a device with solid Bluetooth performance, it doesn’t look like the Pixelbook will work\nout for you. The bug mentions that the Pixel Slate and\n<a href=\"https://chromeunboxed.com/news/3-new-kaby-lake-chromebooks-in-the-works\">‘Nami’ devices</a>, including\nthe Acer Chromebook 13 and Spin 13, should have the hardware capability to have Bluetooth that\nauto-recovers (without a reboot) when it has issues.</p>\n<hr />\n<p>I spent a couple of hours coding while streaming Google Play Music over Bluetooth via the web\n(not the Android app). I wanted to try this to see if my earlier disconnects were related to\nactively using an Android app. It wasn’t related. I had about 6 more disconnects (with no auto\nreconnection) over this time. Again, the sound seemed very clear, but the disconnections make it\nproblematic to use the Pixelbook with any Bluetooth accessories 😞</p>\n<h1 id=\"day5betachannel\">Day 5 — Beta Channel</h1>\n<p>Today I decided that it was time to try the Beta Channel of Chrome OS. The main reason was to try\nout the Intel firmware update for the Bluetooth/Wi-Fi chip. It took about 15 minutes to download,\ninstall the updates, and reboot.</p>\n<p>This evening I streamed music while coding for about 5 hours with numerous breaks, disconnections\ndue to going out of range, turning my headset on/off, etc. I also got in about 30 minutes of SWGOH\nwith BT. Thankfully, I can report that I did not have a single bogus disconnection, and the system’s\nBT did not disable itself.</p>\n<p>I didn’t do any coding or fiddling with configuration today. I needed to get my productivity up, so\nI stuck with my MacBook Pro for dev today.</p>\n<h1 id=\"day6\">Day 6</h1>\n<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\nhours on BT without any disconnections or issues.</p>\n<p>I also ordered a set of USB-C to HDMI adapters so that I could do some testing with dual external\nmonitors. I didn’t want to spend the money on a whole\n<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>\n<h1 id=\"day7\">Day 7</h1>\n<p>I hooked up the following today</p>\n<ul>\n<li><p>Uni USB-C to HDMI adapter to AOC 27\" monitor</p></li>\n<li><p>Anker 10 port USB-A 3.0 Hub</p></li>\n<li><p>Logitech K800 Wireless Keyboard</p></li>\n<li><p>Logitech M570 Trackball</p></li>\n<li><p>Western Digital 1 TB My Book for Mac</p></li>\n</ul>\n<p>In this configuration, I was only using one of two monitors, but this allowed me to have WebStorm\nrunning side by side: macOS vs. Chrome OS.</p>\n<p>I messed with the scaling in the Chrome OS display settings a bit. However, with this configuration,\nanything but 100% scaling resulted in blurry text in WebStorm. I needed to bump my font size in\nWebStorm up from 9 to 12 (same as in macOS). I had previously lowered it for the Pixelbook display.\nLater when I opened WebStorm settings, it appears that the font size was auto converted to 28.</p>\n<p>I also had to tweak the font since the Menlo font that I use on macOS isn’t available on Chrome OS.\nI settled with Fira Code Medium.</p>\n<p>With the scaling and font sizes sorted out and both displays of WebStorm (macOs, Chrome OS) looking\nsimilar, here’s what I noted</p>\n<ul>\n<li><p>The text in the Project panel (where your files and directories are) has a real nice contrast in\nmacOS, but it’s smaller and dull in Chrome OS.</p></li>\n<li><p>Many parts of WebStorm on Chrome OS are smaller and need to be scaled up to match the size on\nmacOS. Unfortunately, I can’t do that due to the blurring.</p></li>\n<li><p>Fonts and UI elements are significantly sharper on macOS. This actually used to be a weakness\nwhen running any IntelliJ product on macOS compared to Windows. However, JetBrains solved this issue\na couple of years ago. It looks like some kind of similar fix is needed for Chrome OS’ Freon\ngraphics stack.</p></li>\n</ul>\n<p>After this, I decided that I needed to get two external monitors set up. However, this meant losing\nmy external mouse and keyboard since I don’t have a USB-C Hub. The good news is that the Pixelbook’s\nkeyboard and trackpad are excellent, so I’m using them in that configuration to write up this post.\nOf course this also means that I can’t charge in this configuration due to only having 2 USB-C\nports. For any longer term use, you would certainly want a USB-C Hub to solve that.</p>\n<p>So configuration #2 consisted of the following</p>\n<ul>\n<li><p>Uni USB-C to HDMI adapter to AOC 27\" monitor</p></li>\n<li><p>Uni USB-C to HDMI adapter to AOC 27\" monitor</p></li>\n</ul>\n<p>I had to plug in the 2nd monitor twice as the first time it wasn’t recognized by Chrome OS. The\nsecond time it worked fine and was available in the Display settings. I was able to set up the\nmonitor positioning (each 27\" on one side of the PB’s internal display. This was quite a nice\nexperience.</p>\n<p>The first thing I tried was to move an open Chrome window from my PB’s internal display to one of\nthe external monitors. This crashed Chrome OS and I lost my WebStorm instance which was hosting an\nAngular CLI project and Firebase Functions.</p>\n<p>I was able to open the Chrome window again and move the tab back to the external display. I have\nread online this is a common issue with Chrome OS. However, I haven’t yet tracked down the related bug\non https://crbug.com.</p>\n<p>The other issue that I ran into here, which I don’t think is restricted to external monitors, is\nthat Linux apps which are running in fully expanded windows don’t have their position remembered\nwhen they restarted. This means that I have to use an extra click every time that I open an app to\nmake it take up the full screen.</p>\n<p>These are software bugs which should be fixed. I’m not sure if the blurry scaling and lack of\nsharpness in WebStorm is 100% a software problem, but it certainly needs to be addressed by either\nthe Chrome team or JetBrains. For now, these issues make the whole external monitor experience on\nChrome OS sub-par. It’s certainly workable but, much like tablet mode, there seems to be quite a\nlot of space for improvement.</p>\n<p>Some additional positive notes:</p>\n<p>Letting the Pixelbook go to sleep connected to external monitors worked well. I was able to wake it\nusing a variety of options including an external mouse, external keyboard, and the Pixelbook’s\ntrackpad and keyboard. All the window positions and states were intact.</p>\n<h4 id=\"issuewithmovingandroidappsbetweenmonitorssolved\">Issue with moving Android apps between monitors - Solved</h4>\n<p>When I open certain Android apps, like SWGOH, the app appears to open in the first monitor. This\nhappens even if you launched the app from the launcher on another display. In my case, it opens in\nthe left external monitor. However, I want it to open on the Pixelbook’s internal display so that\nI can use the touch screen. There doesn’t appear to be a way to move a full screen app like this\nfrom one display to another. It’s impossible to take the app out of full screen mode either via\nthe mouse cursor, or the full screen button on the Pixelbook. There are some\n<a href=\"https://chromeunboxed.com/news/chromebook-shortcut-move-windows-between-displays/\">articles about shortcuts for moving windows across displays</a>,\nbut they reference the out of date <code>Launcher+Alt+Arrow</code> shortcut.</p>\n<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>\nwith <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\nfull screen Android apps like this.</p>\n<p>Finally, I decided to open the Chrome OS shortcut search panel via <code>Launcher+Alt+/.</code> Then searching\nfor “move” immediately showed me the proper shortcut: <code>Launcher+Alt+m</code>. This works!</p>\n<p>Like a number of functions in Chrome OS, a keyboard shortcut is the only way to access the\nfunctionality, and the discoverability of this functionality is poor.</p>\n<h4 id=\"morenotesonthegeneraldeveloperexperience\">More notes on the general developer experience</h4>\n<p>I mentioned in a day 3 that the Google Cloud Tools plugin login didn’t work due to the redirect not\nbeing mapped between Crostini and Chrome OS. This wasn’t the case for logging in from the Firebase\nCLI via <code>firebase login</code>. Everything worked smoothly there. I also tried the Google Cloud SDK via\nthe <code>gcloud auth login</code> command and that worked well.</p>\n<p>On the Pixelbook, I always saw an accumulation of the same error in my browser console when I have\na site open in live reload (dev) mode:</p>\n<pre><code class=\"js language-js\">Unchecked runtime.lastError: The message port closed before a response was received.\n</code></pre>\n<p>I’m not sure what is causing this or how to solve it. However, it does not appear to be causing a\nsignificant issue.</p>\n<p>I did some performance tests with Angular CLI <code>v7.1.0</code>. Eventually, I decided to test against a\nbrand new <code>ng new</code> project. I used the existing project only for build times, but not reload times\nas they were too funky due to the project using a number of different libraries. For comparison, I\nincluded some numbers from my primary dev machine: a mid-2014 <code>i7 16GB RAM 256GB</code> SSD MacBook Pro.</p>\n<h4 id=\"pixelbookperformanceinanewproject\">Pixelbook Performance in a new project</h4>\n<p>Time to run <code>ng serve</code>: <strong>~16s</strong></p>\n<p>Time to refresh the browser on a page served via <code>ng serve</code>: <strong>~1s</strong></p>\n<p>Round trip for making a change and seeing it live in the browser: <strong>~2–3s</strong></p>\n<p>Production build time: <strong>~33s</strong></p>\n<h4 id=\"pixelbookperformanceinanexistingproject\">Pixelbook Performance in an existing project</h4>\n<p>I had to throw out the browser refresh and round trip times here due to an issue with this project\nthat caused both platforms to run much slower than they should.</p>\n<p>What about that production and dev build times though?</p>\n<p>Production build: <strong>~3 minutes</strong></p>\n<p>Dev Build: <strong>~29s</strong></p>\n<p>For the production build, looking at the CPU cores in Cog, a few of the longer running tasks like\nthe <code>TerserPlugin</code> have significant portions that run on a single CPU. When this happened, the\nother CPUs were hanging around 5–25% while one CPU was around 90–100%.</p>\n<p>This was done on battery power and none of these tests really drove up the thermals in any\nsignificant way. Everything continued to run around 105–140F.</p>\n<h4 id=\"buildingsignificantangularjsproject\">Building significant AngularJS project</h4>\n<p>I also tried and AngularJS project that just uses Gulp and <code>gulp-connect</code>. In this case the build\ntook <strong>~22s</strong> and live reload did not work at all. On the MacBook Pro, this project builds in <strong>~17s</strong>.\nThis app also had the same console errors.</p>\n<p>By default, the app used <code>http://localhost:35729/livereload.js?snipver=1</code> for live reload. I was\nable to get <code>gulp-connect</code> livereload working using the following config:</p>\n<pre><code class=\"json language-json\">livereload: { hostname: ‘penguin.linux.test’ },\n</code></pre>\n<p>This did not fix the console errors, but it fixed live reload.</p>\n<h4 id=\"macbookproperformanceinanewproject\">MacBook Pro Performance in a new project</h4>\n<p>I wanted to provide some comparable times for the above data points in the same project on\nmy 2014 MacBook Pro. These are numbers that I’m mostly fine with and would like to see equaled or improved\nupon by a new laptop.</p>\n<p>Time to run <code>ng serve</code>: <strong>~10s</strong></p>\n<p>Time to refresh the browser on a page served via <code>ng serve</code>: <strong>~1.5s</strong></p>\n<p>Round trip for making a change and seeing it live in the browser: <strong>~2–3s</strong></p>\n<p>Production build time: <strong>~26s</strong></p>\n<h4 id=\"macbookproperformanceinanexistingproject\">MacBook Pro Performance in an existing project</h4>\n<p>Production build: <strong>~2m 19s</strong></p>\n<p>Dev Build: <strong>~26s</strong></p>\n<h4 id=\"androidapplaunchperformance\">Android App Launch Performance</h4>\n<p>On Android, one of the slowest tasks that I do with apps is opening up SWGOH.</p>\n<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>\n<p>Here’s the data:</p>\n<ul>\n<li><strong>Nexus 9:</strong> ~70s</li>\n<li><strong>Pixel XL:</strong> ~34s</li>\n<li><strong>Pixel 3:</strong> ~21s</li>\n<li><strong>Pixelbook:</strong> ~15s</li>\n</ul>\n<h4 id=\"performancesummary\">Performance Summary</h4>\n<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>\n<p>The Pixelbook was 10–40% slower for CPU intensive tasks like running builds. I was surprised that it\nrefreshed pages in dev mode approximately <strong>0.2–0.4s</strong> faster than the MacBook Pro. This may be explained by\nthe fact that the Pixelbook is running Chrome 71 while the MacBook Pro is running Chrome 70. Or the\nPixelbook is just slightly better tuned for running Chrome?</p>\n<p>These results aren’t overly surprising. The Pixelbook is running a newer generation i7 processor,\nbut it’s also tuned for mobility and thermal performance in a laptop w/o fans. The Pixelbook is\nalso half of the price of this mid-2014 MacBook Pro.</p>\n<p>Overall, performance-wise the <code>i7</code> Pixelbook packs enough punch to do web, backend, and Android\ndevelopment, but it won’t blow you away with speed.</p>\n<h1 id=\"day8powerwash\">Day 8 - Powerwash</h1>\n<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\nan effective backup development machine.</p>\n<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\nof it’s extended Apple Care warranty. The MacBook Pro still works great and does most everything that I need.\nI’ve found that the 256 GB SSD is a little too small for me, and I’ve run into cases where I wish that\nI had more graphics power. That said, it has proven to be an incredibly reliable, performant, and\nproductive tool over the last 4.5 years. It was clearly one of my best tech purchases, ever.</p>\n<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>\n<p>That said, there are still enough rough edges in Chrome OS and Crostini (beta) that getting things\nset up properly and keeping things running over time will be too large of a drain on my\nproductivity. This is obviously a personal decision. If you don’t have kids and find that you have\na lot of spare time in your life, then you may make the opposite choice here.</p>\n<p>Another aspect of this decision also relates to productivity. That is the speed and smoothness with\nwhich I would be able to make the transition from a temporarily or permanently disabled primary\ndevelopment machine (my MacBook Pro). While I use almost no macOS-specific apps, preferring mostly\nLinux-based apps, it is still not a simple transition for me to switch my dev environment from\nmacOS to Linux. There are a number of contributing factors here:</p>\n<ol>\n<li><p>My MacBook Pro time machine backups are on a USB-A 3.x drive that my Chromebook cannot read due to the\nMac OS Extended Volume Hard Drive Format (HFS+).</p></li>\n<li><p>The Pixelbook does not support Thunderbolt 2 or Thunderbolt 3. So peripherals for my MacBook Pro need\nextra adapters and if I upgrade to a new MacBook Pro there will be peripherals that may not work with the\nPixelbook. This problem is especially painful when it comes to \\$300+ docking stations to support\ndual external monitors.</p></li>\n<li><p>There are minor differences between the two systems which would cost me a good deal of time to\nmitigate. These include font and resolution settings in IDEs, differences in window management\nbehaviors and shortcuts, differences in keyboard layouts, etc.</p></li>\n</ol>\n<p>I’ve seen some reviews out there about Chrome OS and the Pixel Slate. They mention the idea of a\nthousand little cuts. Each one may have a work around or mitigation, but taken on a whole there\nare enough of them that the total impact is significant.</p>\n<p>Thankfully, most of these issues are on the software side and will be improved or resolved over\ntime! I feel strongly that Chrome OS has a strong future in most all markets (even development).</p>\n<p>The Pixelbook is an amazing device for so many people today. It’s going to keep improving over time,\nespecially since it will get updates for 7 years after its launch date instead of 5 like many other\nChromebooks.</p>\n<h4 id=\"nowthepixelbookhardware\">Now the Pixelbook hardware</h4>\n<p>Most of it is amazing. The keyboard and trackpad are superstars. The overall feel is very solid and\npremium. I was happy with the thermal performance and quiet fan-free usage.</p>\n<p>The hinge worked great for me in most all cases. It has a little more movement than I’d like when\ntouched in non-tablet and tent modes. Plus you need to hold down the keyboard when opening the\nscreen. This is a hard problem. In one case I want the hinge to be more stable and in another I\nwant it to open more easily.</p>\n<p>I have very positive and negative opinions on the Pixelbook’s screen. The bezels are indeed\nenormous, but it’s not a deal breaker for me. I much prefer the 3:2 aspect ratio over the wide\nscreens seen on many of laptops (Dell, etc.). This gives more vertical space for productivity\ntasks like reading, writing, or coding. The screen is impressively thin. The webcam worked well\nenough, but did not impress me.</p>\n<blockquote>\n  <p>The Pixelbook has 235 pixels per inch, and my MacBook Pro has 220 pixels per inch. The Pixelbook’s\n  display has 400 nits of brightness which makes it usable outdoors. My MacBook Pro only has 320 nits of\n  brightness, and it doesn’t excel outdoors. That said, new MacBook Pros have 500 nits of brightness.</p>\n</blockquote>\n<p>On paper, the Pixelbook’s screen is very solid. However, in practice I found that changing\nresolution or scaling display output resulted in blurry or pixelated images and text. This was\nlikely due to Chrome OS’ Freon graphics stack, Linux apps being in beta, and Android apps not\nbeing fully tuned to Chrome OS yet. This resulted in a display experience that I wasn’t completely\nsatisfied with.</p>\n<h4 id=\"stonepeak2byintel\">Stone Peak 2 by Intel</h4>\n<p>The Intel Bluetooth/Wi-Fi combo chip is the primary reason that I am returning the Pixelbook. I had\nmany occurrences in Chrome OS 70 (Stable) of Bluetooth disconnecting and not auto reconnecting on me.</p>\n<p>This device has been on the market for a year now. Lately, I’ve been waiting to buy a number of\ntech products until they have been in the market for a few months. This gives me the chance to see\nwhich products have serious flaws and which have flaws that can be addressed via software updates.\nThis strategy has saved me a lot of wasted time, frustration, and money in the last 4 years.</p>\n<p>That said, the Pixelbook still having serious feature-breaking problems in the Stable channel after\na year is too much for me to ignore. Yes, I had better luck with Chrome 71 (Beta), but there are\nnumerous users who are still reporting Bluetooth issues with that build. I don’t have the luxury\nof waiting to see since the return period is only 15 days. Plus I’ve already spent as much time\ntesting this device as I can afford.</p>\n<p>Additionally, comments in the various Bluetooth\n<a href=\"https://bugs.chromium.org/p/chromium/issues/detail?id=904571\">bugs</a> in the Chrome OS issue tracker\nseem to indicate that there is a hardware flaw or missing feature with the Pixelbook’s Intel Stone\nPeak 2 Bluetooth/Wi-Fi chip. There is some additional discussion of this issue on\n<a href=\"https://www.reddit.com/r/PixelBook/comments/a0om0y/progress_in_m72_for_bluetooth_issues/\">Reddit</a>.</p>\n<h4 id=\"finaldecision\">Final Decision</h4>\n<p>It doesn’t seem wise for me to spend \\$1,700+ on a device that has an issue like this that may never\nbe fully fixed. Bluetooth is something that I make heavy use of, so issues with this chip could\nseriously impact productivity.</p>\n<p>That combined with the many little cuts to productivity, mentioned above, resulted in me making the\ndecision to return the Pixelbook.</p>\n<h4 id=\"nextsteps\">Next Steps</h4>\n<p>If I can pick up the cheaper model on a big discount, then I would love to have a Pixelbook, but I\ncan’t justify keeping the top end model.</p>\n<p>I will certainly continue to keep my eye on high-end Chromebooks which can be used for development.\nI’m excited by the progress and goals of Crostini. Additionally, I’m also confident Android apps on\nChrome OS will continue to improve each year. I do plan to make a Chromebook my primary development\nmachine at some time in the future.</p>\n<p>Until then, I am planning to stick with MacBook Pro devices for my primary development platform.\nI’m very happy I’m able to test my web apps on Android, macOS, iOS, Windows, and Chrome OS\nusing a MacBook Pro. You can find out more about running Chrome OS in a VM on a MacBook Pro in\n<a href=\"https://twitter.com/Splaktar/status/1068329287433052161\">this Twitter thread</a>.</p>\n<hr />\n<p>If you haven’t checked it out yet, <a href=\"https://devfestflorida.org/\">DevFest Florida</a> is happening at\nDisney World’s Contemporary Resort on January 19th. The\n<a href=\"https://devfestflorida.org/speakers/\">list of speakers</a> is really impressive. Tickets for students\nand professors are only $99 (plus fees) and general tickets are $175 (plus fees).</p>\n<blockquote>\n  <p>If you are interested, <strong>I am happy to offer readers 25% off of general ticket prices using\n<a href=\"https://www.eventbrite.com/e/devfest-florida-orlando-tickets-48558589047?discount=PRENTICE#tickets\">this link</a></strong>!\n  I hope to see some of you there.</p>\n</blockquote>",
            "url": "https://devintent.com/blog/2018-11-25-my-pixelbook-dev-experience.md",
            "title": "My Pixelbook Developer Experience",
            "summary": "Head-to-head comparison of the development experiences on the Google Pixelbook and Apple MacBook Pro.",
            "date_modified": "2018-11-25T00:00:00.000Z",
            "tags": [
                "chrome",
                "mac"
            ]
        },
        {
            "id": "blog/2018-11-24-using-a-pixelbook-for-angular-development.md",
            "content_html": "<p>If you just received a new Pixelbook, congratulations! Hopefully you have had some fun with\nInfinite Painter and possibly some other Android apps from Google Play.</p>\n<blockquote>\n  <p>Note: <em>I wrote a\n<a href=\"https://www.devintent.com/blog/2018-11-25-my-pixelbook-dev-experience\">separate, detailed post</a>\nabout my initial Pixelbook Developer experience.</em></p>\n</blockquote>\n<p>Now let’s get down to the business of getting your machine ready for some Angular development!</p>\n<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>\n<h1 id=\"getupdated\">Get updated</h1>\n<p>First, make sure you update to the latest patch by checking for an update in your status bar\n(click the clock). Select the option to reboot and install the update if one exists. Ideally you\nare on Chrome OS 70 or later.</p>\n<p>You can check your Chrome OS version in <code>Settings-&gt;Hamburger menu-&gt;About Chrome OS</code>.</p>\n<h1 id=\"enablelinuxappsbeta\">Enable Linux Apps (beta)</h1>\n<p>Go to the <a href=\"https://support.google.com/pixelbook/answer/9031351?hl=en\">Support Page for Linux Apps</a>\nand follow the instructions. In my case, there were some upgrades available from <code>apt-get</code>.</p>\n<h1 id=\"installjava\">Install Java</h1>\n<p>From your Linux terminal:</p>\n<pre><code class=\"bash language-bash\">sudo apt install openjdk-8-jdk\n</code></pre>\n<h1 id=\"installwebstorm\">Install WebStorm</h1>\n<p>Go to the <a href=\"https://www.jetbrains.com/webstorm/\">JetBrains WebStorm Download</a> page and click the\nDownload button.</p>\n<p>In your Linux terminal, create a downloads folder:</p>\n<pre><code class=\"bash language-bash\">mkdir ~/downloads\n</code></pre>\n<p>Open the Files app.\nCopy your download from <code>My files-&gt;Downloads</code> to <code>Linux files-&gt;downloads</code> via drag and drop.</p>\n<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>\n<p>In your Linux Terminal, extract the WebStorm archive into <code>/opt</code>:</p>\n<pre><code class=\"bash language-bash\">sudo tar xf ~/downloads/WebStorm-2018.3.tar.gz -C /opt\n</code></pre>\n<p>In your Linux Terminal, launch WebStorm:</p>\n<pre><code class=\"bash language-bash\">/opt/WebStorm-183.4284.130/bin/webstorm.sh\n</code></pre>\n<p><em>Note that your path to the WebStorm directory will be slightly different per version.</em></p>\n<p>Go through the setup steps and make sure the box to create a Desktop Entry is checked (default) but\ndon’t check the box for All Users. Complete the wizard, give WebStorm a minute to settle, and then\nclose it.</p>\n<h1 id=\"launchwebstormfromthechromeoslauncher\">Launch WebStorm from the Chrome OS Launcher</h1>\n<p>That last step made WebStorm available in the Linux apps directory of the Chrome OS Launcher.</p>\n<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>\n<p>Launch WebStorm from the Chrome OS Launcher and repeat the setup steps other than creating a\nDesktop Entry.</p>\n<h1 id=\"setupssh\">Setup SSH</h1>\n<p>Now for using GitHub, you will want to <a href=\"https://github.com/settings/keys\">setup SSH and GPG</a>. We’ll\nstart with SSH.</p>\n<p>Follow <a href=\"https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/\">these steps</a>\nto generate a SSH public and private key for your Pixelbook. If the part about “Adding your SSH key\nto the ssh-agent” is empty, scroll to the top and make sure Linux is selected. Then follow\nthose steps. I reported this issue to GitHub, so manually selecting Linux for Chrome OS should not\nbe required once they fix their <code>user-agent</code> detection.</p>\n<p>Open <a href=\"https://github.com/settings/keys\">GitHub SSH and GPG keys</a> and create a new key with the\ncontents of <code>id_rsa.pub.</code> You can get the contents via</p>\n<pre><code class=\"bash language-bash\">cat ~/.ssh/id_rsa.pub\n</code></pre>\n<p>Now back in WebStorm, you need to set up GitHub under <code>File-&gt;Settings-&gt;Version Control-&gt;GitHub</code>.\nCheck the box for “Clone git repositories using ssh”. Then click “Add account”.</p>\n<p>Fill in your username and password. It will prompt you for your 2FA code in the next step. If that\nis successful, GitHub will be configured properly.</p>\n<h1 id=\"additionalsshagentconfigurationoptional\">Additional SSH Agent Configuration (optional)</h1>\n<p>If you created your SSH key with a password (recommended), then you need to make sure the SSH\nAgent prompts you for your password after a reboot. There are many options available for doing this\ntask. We’re going to use a simple setup that uses an open source package called\n<a href=\"https://github.com/funtoo/keychain\">keychain</a>.</p>\n<p>In your Linux Terminal, install keychain:</p>\n<pre><code class=\"bash language-bash\">sudo apt-get install keychain\n</code></pre>\n<p>Open your <code>~/.bashrc</code> file and add the following line at the end:</p>\n<pre><code class=\"bash language-bash\">eval `keychain --eval id_rsa -q`\n</code></pre>\n<p>This setup will prompt you for your SSH key’s passphrase only once per reboot.</p>\n<p><em>Note: You can use <code>vi</code> to make this change or install something like <code>nano</code> if you prefer.\nRemove the <code>-q</code> if you want keychain to print some information every time you open a shell.\nThis comes from a couple different sources:\n<a href=\"https://stackoverflow.com/a/24902046/633107\">StackOverflow</a>,\n<a href=\"https://unix.stackexchange.com/a/90869/61959\">Unix StackExchange</a>.</em></p>\n<h1 id=\"setupgpg\">Setup GPG</h1>\n<p>Check if you already have GPG2 via</p>\n<pre><code class=\"bash language-bash\">gpg --version\n</code></pre>\n<p>If not, in your Linux Terminal, install GPG2:</p>\n<pre><code class=\"bash language-bash\">sudo apt-get install gpg2\n</code></pre>\n<p>If you have a new Pixelbook, then you can go straight to installing GPG. If your Pixelbook is not\nnew, then you should\n<a href=\"https://help.github.com/articles/checking-for-existing-gpg-keys/\">check if you have any existing GPG keys</a>.</p>\n<p>Follow <a href=\"https://help.github.com/articles/generating-a-new-gpg-key/#platform-linux\">these steps</a>\nto generate your GPG key and export it to a format for adding to GitHub.</p>\n<p>Setting up a GPG key allows GitHub to show the green “Verified” label next to the commits in your\nPull Requests.</p>\n<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>\n<h1 id=\"clonearepositoryinwebstorm\">Clone a repository in WebStorm</h1>\n<p>In WebStorm, checkout a Git repository:</p>\n<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>\n<p>If you successfully logged into GitHub earlier, then your repositories will be available in the URL\ndrop down.</p>\n<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>\n<p><em>Note that the first time you clone, it should warn you about an unknown host and allow you to add\nthat host and remember it.</em></p>\n<p>Also make sure that you choose a directory in your home directory and not in <code>/root/</code>. It picked\n<code>~/Webstorm/Projects/</code> for me.</p>\n<h1 id=\"configurewebstorm\">Configure WebStorm</h1>\n<p>If you use WebStorm on another computer, you can sync your settings there and have your Pixelbook\npick those settings up easily.</p>\n<p>On your Pixelbook, in the bottom right-hand corner of the screen, click on the Gear with the\nquestion mark. Then select “Enable Sync…”</p>\n<p><a href=\"/large-images/webstorm-sync-settings.png\"><img src=\"/large-images/webstorm-sync-settings.png\" alt=\"WebStorm Sync Settings menu\" /></a></p>\n<p>Select the option that works best for you. Then after a minute, you should be able to click on the\nGear again and either Sync your Plugins silently (e.g. install all the plugins that are on your\nother computer and disable plugins that are disabled on your other computer) or choose which plugins\nshould be synced and which should not.</p>\n<h1 id=\"installnodejsandnpmvianvm\">Install NodeJS and NPM via NVM</h1>\n<p>As described in the <a href=\"https://github.com/creationix/nvm#install-script\">NVM docs</a>, in the Linux\nTerminal run:</p>\n<pre><code class=\"bash language-bash\">curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash\n</code></pre>\n<p>Reload your terminal to get access to NVM by running:\n<code>source ~/.bashrc</code></p>\n<p>Now running <code>nvm --version</code> should output <code>0.33.11</code>.</p>\n<p>Install NodeJS LTS (Long Term Support) and the matching version of NPM by running:</p>\n<pre><code class=\"bash language-bash\">nvm install 10\n</code></pre>\n<h1 id=\"setupnodejsinwebstorm\">Setup NodeJS in WebStorm</h1>\n<p>In WebStorm, open <code>File-&gt;Settings-&gt;Languages and Frameworks-&gt;Node.js and NPM</code>. Node and NPM should\nbe automatically detected. Check the box for “Coding assistance for Node.js” and press OK.</p>\n<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>\n<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>\n<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>\n<h1 id=\"runanpmscript\">Run a NPM Script</h1>\n<p>WebStorm makes it easy for you to open your <code>package.json</code> file and run one of the scripts provided\nby the repository.</p>\n<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>\n<h1 id=\"installyarn\">Install Yarn</h1>\n<p>Many Angular projects now require Yarn.</p>\n<p>The easy way is to do <code>npm i -g yarn</code>, but you can also use the following steps taken from the\n<a href=\"https://yarnpkg.com/lang/en/docs/install/#debian-stable\">Yarn Install docs for Debian</a>:</p>\n<p>Add Yarn’s public GPG key and repository to Debian’s package manager by running the following in\nyour Linux Terminal:</p>\n<pre><code class=\"bash language-bash\">curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -\n\necho \"deb https://dl.yarnpkg.com/debian/ stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list\n</code></pre>\n<p>In your Linux Terminal, install yarn:</p>\n<pre><code class=\"bash language-bash\">sudo apt-get update &amp;&amp; sudo apt-get install --no-install-recommends yarn\n</code></pre>\n<p>Check the installation was successful by running <code>yarn --version</code> which should output a version\nsimilar to <code>1.12.3</code>.</p>\n<p>Similar to above, WebStorm will prompt you to run <code>yarn install</code> when you open a new project that\nuses Yarn.</p>\n<h1 id=\"conclusion\">Conclusion</h1>\n<p>Please note that the steps above for WebStorm are nearly identical if you are installing IntelliJ\nIDEA or many of the other JetBrains IDEs.</p>\n<p>I hope that this post is useful to some intrepid developers who are ready to get productive with\ntheir Pixelbooks! Please leave comments if you run into any issues or if something doesn’t work,\nand I will try to update this post.</p>\n<hr />\n<p>If you haven’t checked it out yet, <a href=\"https://devfestflorida.org/\">DevFest Florida</a> is happening at\nDisney World’s Contemporary Resort on January 19th. The\n<a href=\"https://devfestflorida.org/speakers/\">list of speakers</a> is really impressive. Tickets for students\nand professors are only $99 (plus fees) and general tickets are $175 (plus fees).</p>\n<blockquote>\n  <p>If you are interested, <strong>I am happy to offer readers 25% off of general ticket prices using\n<a href=\"https://www.eventbrite.com/e/devfest-florida-orlando-tickets-48558589047?discount=PRENTICE#tickets\">this link</a></strong>!\n  I hope to see some of you there.</p>\n</blockquote>\n<hr />\n<h1 id=\"references\">References</h1>\n<p>Some information for this post was taken from the helpful\n<a href=\"https://www.reddit.com/r/Crostini/\">Crostini community on Reddit</a>.</p>\n<p>I was also able to get Gimp 2.10.x installed thanks to the\n<a href=\"https://www.reddit.com/r/chromeos/comments/988zw8/quick_question_how_to_add_gimp/\">ChromeOS community on Reddit</a>.</p>",
            "url": "https://devintent.com/blog/2018-11-24-using-a-pixelbook-for-angular-development.md",
            "title": "Using a Pixelbook for Angular Development",
            "summary": "Step-by-step instructions for setting up WebStorm, Git, NodeJS, NVM, and Yarn for web development with Angular.",
            "date_modified": "2018-11-24T00:00:00.000Z",
            "tags": [
                "chrome",
                "angular",
                "webstorm"
            ]
        },
        {
            "id": "blog/2018-11-18-using-a-pixelbook-with-a-docking-station-and-extended-monitors.md",
            "content_html": "<p>I have a new <a href=\"https://store.google.com/product/google_pixelbook\">Google Pixelbook</a> on the way, and\nI’m trying to figure out my docking station solution.</p>\n<p><a href=\"/large-images/pixelbook-usbc.jpg\"><img src=\"/large-images/pixelbook-usbc.jpg\" alt=\"Google Pixelbook\" /></a></p>\n<p><a href=\"https://support.google.com/pixelbook/forum/AAAASyb5yQ4JmN5Lh97N0o\">This old, locked support forum post</a>\nmentions the <a href=\"http://a.co/d/8hXVQmz\">Dell D6000 dock</a> which people have had some luck with. There\nappears to be an issue where the dock will lose connection with the monitors every couple of hours.\nThis seems to be commonly reported by users of Dell docks (across reviews of many of their existing\nUSB-C docks). I’m not sure if any of those posters using the D6000 were able to solve this issue\nor not.</p>\n<p><a href=\"https://kmyers.me/blog/computers/the-ultimate-chromebook-pixelbook-desk-setup/\">Keith Meyers’ blog</a>\nmentions successfully using the Pixelbook along with the\n<a href=\"https://amzn.to/2GSi09X\">Plugable USB 3.0 Universal Laptop Docking Station</a>. This is a dock from 2013.</p>\n<p>The <a href=\"http://a.co/d/9DRgz6K\">Plugable USB-C 4K Triple Display Docking Station with Charging Support</a>\nis from 2017 and has 4K@60fps support via DisplayPort. It also supports charging the Pixelbook.</p>\n<p>In the Q&amp;A, the Plugable states that the Pixelbook is fully supported. However, I’d like to hear from\nthe community whether you were able to get this dock working and if you ran into any\nissues.</p>\n<p>Another interesting option is the <a href=\"http://a.co/d/1mz0YaV\">CalDigit USB-C Docking Station</a>. It only\nsupports two monitors, but that is sufficient for me. For two monitors, you need to use\n<a href=\"https://blog.startech.com/post/connecting-multiple-monitors-multi-stream-transport-and-what-it-means-for-you/\">DisplayPort Multi-Stream Transport</a>\nwhich Chrome OS added support for in the Spring of 2018. This means that the DisplayPort port would\ndrive both monitors, and the HDMI port would be unused. Since my monitors are HDMI, I would need to\nuse a MST Hub to split the signal and then DP-&gt;HDMI adapters.</p>\n<p>This CalDigit setup seems a bit involved and possibly slightly risky. I’d love to know if\nanyone has gotten it to work this year.</p>\n<p>Are you using another dock that you’ve found works great for you? Please let me know.</p>",
            "url": "https://devintent.com/blog/2018-11-18-using-a-pixelbook-with-a-docking-station-and-extended-monitors.md",
            "title": "Using a Pixelbook with a docking station and extended monitors",
            "summary": "Research and discussions of using a docking station with a Google Pixelbook.",
            "date_modified": "2018-11-18T00:00:00.000Z",
            "tags": [
                "chrome"
            ]
        },
        {
            "id": "blog/2018-06-28-announcing-the-angularjs-material-v1-1-10-release.md",
            "content_html": "<p>We have released AngularJS Material <code>v1.1.10</code>.</p>\n<p>This release is now available in our\n<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>,\nand 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>\n<p>You can find the details for all releases in our\n<a href=\"https://github.com/angular/material/blob/master/CHANGELOG.md\"><strong>Change Log</strong></a>.</p>\n<h1 id=\"highlights\">Highlights</h1>\n<p><code>v1.1.10</code> should be our most stable release in many months. Here are some highlights:</p>\n<ul>\n<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>\n<li><p>Fixed a memory leak when elements using <code>md-theme</code> are removed from the page</p></li>\n<li><p>Fixed select to support selecting options by typing when the option contains a period (i.e. <code>255.255</code>)</p></li>\n<li><p>Improved dark mode theme support for menu-bar and datepicker</p></li>\n<li><p>Fixed ripple animations getting stuck on iOS in certain situations</p></li>\n<li><p>Fixed a couple layout issues</p></li>\n<li><p>Significant improvements to the project’s documentation including 3 new demos</p></li>\n</ul>\n<p><a href=\"/angularjs-material/md-calendar.png\"><img src=\"/angularjs-material/md-calendar.png\" alt=\"New Calendar Demo\" /></a></p>\n<p><a href=\"/angularjs-material/md-datepicker-moment.png\"><img src=\"/angularjs-material/md-datepicker-moment.png\" alt=\"Moment.js Datepicker Demo\" /></a></p>\n<p>This is a patch release with non-breaking changes (fixes and enhancements).</p>\n<h1 id=\"bugfixes\">Bug Fixes</h1>\n<ul>\n<li><p><strong>chips</strong>: editable chip gets removed after editing</p></li>\n<li><p><strong>chips</strong>: improve ability to receive focus on click</p></li>\n<li><p><strong>chips</strong>: regression where chips model gets out of sync with view</p></li>\n<li><p><strong>chips</strong>: unwanted re-focus of last chip after blur</p></li>\n<li><p><strong>compiler</strong>: remove dependency on AngularJS private API</p></li>\n<li><p><strong>datepicker</strong>: calendar panel theme supports dark mode in multi theme scenario</p></li>\n<li><p><strong>layout</strong>: allow flex-offset to be a child of layout-margin</p></li>\n<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>\n<li><p><strong>menu-bar</strong>: <code>md-menu-bar</code> panel theme supports dark mode themes</p></li>\n<li><p><strong>nav-bar</strong>: missing <code>[disabled]</code> scss selector</p></li>\n<li><p><strong>ripple</strong>: fix iOS Safari stuck ripple issue</p></li>\n<li><p><strong>select</strong>: doesn’t search correctly when pressing period character</p></li>\n<li><p><strong>theming</strong>: <code>md-theme</code> leaks when child elements are removed</p></li>\n</ul>\n<h1 id=\"features\">Features</h1>\n<ul>\n<li><strong>mdMaxlength</strong>: support use with required and <code>ng-trim</code></li>\n</ul>\n<h1 id=\"documentation\">Documentation</h1>\n<ul>\n<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>\n<li><p><strong>dateLocaleProvider</strong>: add missing documentation for <code>isDateComplete()</code> and <code>longDateFormatter()</code></p></li>\n<li><p><strong>virtual-repeat</strong>: fix typos, clean up, and clarifications</p></li>\n<li><p><strong>tabs</strong>: add link to tab docs, clarify the notes about nav-bar</p></li>\n<li><p><strong>select</strong>: clarify the behavior of the multiple attribute</p></li>\n</ul>\n<h1 id=\"contributors\">Contributors</h1>\n<p><strong>Thank you</strong> to the\n<a href=\"https://github.com/angular/material/blob/master/CHANGELOG.md#contributors-1\">contributors</a>,\nespecially the first timers, who helped with the v1.1.10 release:</p>\n<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>",
            "url": "https://devintent.com/blog/2018-06-28-announcing-the-angularjs-material-v1-1-10-release.md",
            "title": "Announcing the AngularJS Material v1.1.10 Release",
            "summary": "Information about the AngularJS Material v1.1.10 Release.",
            "date_modified": "2018-12-22T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        },
        {
            "id": "blog/2018-03-28-eye-tracking-study-finds-problems-with-flat-uis.md",
            "content_html": "<p>You may have read about a\n<a href=\"https://www.nngroup.com/articles/flat-ui-less-attention-cause-uncertainty/\">recent study</a>\nthat came out in early September 2017 by the Nielsen Norman Group. It had a headline grabbing title\nabout how Flat UI designs cause uncertainty in users. The headline alone had product managers\nquestioning their designers and developers.</p>\n<p>However, if you read deeper into the article, you’ll find that the eye tracking research actually\nconfirmed the importance of a number of key UI design guidelines.</p>\n<p>If you are building user interfaces and you haven’t embraced the acronym\n<a href=\"https://www.dailyblogtips.com/crapthe-four-principles-of-sound-design/\"><strong>CRAP</strong></a> yet, then I\nhighly recommend that you look into it.</p>\n<p>It stands for <strong>Contrast</strong>…. your important, interactive UI elements need to stand out.</p>\n<p><strong>Repetition…</strong> consistent UI patterns train user’s brains where to look.</p>\n<p>Then you build a clear visual hierarchy through the use of <strong>Alignment</strong> and <strong>Proximity</strong>.\nThis includes intelligent use of negative space (or whitespace) along with grouping items that\nbelong together near each other.</p>\n<p>This study hits on a key human factors issue. Complex, high density user interfaces cause users\nuncertainty and delay their ability to take action.</p>\n<p>Now let’s take a look at some details of the study and how Material Design is already built to address\nthese challenges.</p>\n<h1 id=\"flatuivsmaterialdesign\">“Flat UI” vs Material Design</h1>\n<p><a href=\"/large-images/flat-ui-example.png\"><img src=\"/large-images/flat-ui-example.png\" alt=\"Example Image\" /></a></p>\n<p>On the left, we see a traditional link with the blue color and underline. The right side shows an\nexample of an ultra-flat UI where positioning is the only signifier that the element may be interactive.</p>\n<p>The eye tracking results showed that users of the flat design would try to click on the header first\nand often ignore the flat button completely because it’s click ability signifiers were too weak.</p>\n<p><a href=\"/large-images/flat-button-example.png\"><img src=\"/large-images/flat-button-example.png\" alt=\"Example Image\" /></a></p>\n<p>Material Design provides a number of different button types to address this type of situation. First\nthere is the flat button. It stands out through the use of a contrast color in addition to\ncapitalization. However, these buttons are not designed to be used for your more important actions.</p>\n<p><a href=\"/large-images/raised-button-example.png\"><img src=\"/large-images/raised-button-example.png\" alt=\"Example Image\" /></a></p>\n<p>In this case, taking the user to your pearl storefront is a primary action.</p>\n<p>Material Design provides raised buttons for the cases where you want a strong click ability signifier,\nand the user’s gaze to be attracted by the color and height of the button.</p>\n<p>In my next post, I’ll discuss the basic concepts of Material Design and try to distill the\nmarketing and design language into something that a developer can make sense of.</p>\n<p>If you don’t want to wait, you can start reading the\n<a href=\"https://material.io/design\">Material Design Specifications</a> now.</p>",
            "url": "https://devintent.com/blog/2018-03-28-eye-tracking-study-finds-problems-with-flat-uis.md",
            "title": "Eye Tracking Study finds problems with Flat UIs",
            "summary": "Discussion of how an eye tracking study's results apply to Material Design.",
            "date_modified": "2018-03-28T00:00:00.000Z",
            "tags": [
                "material-design"
            ]
        },
        {
            "id": "blog/2018-01-28-angularfire2-5-0-0-rc-6-released.md",
            "content_html": "<p>AngularFire2 has released <code>5.0.0-rc.6</code> for apps built with Angular.</p>\n<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>\n<p><img src=\"/icons/firebase-storage-icon.png\" alt=\"Firebase Cloud Storage Icon\" /></p>\n<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>\n<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>\n<p>Full changelog <a href=\"https://github.com/angular/angularfire2/blob/master/CHANGELOG.md#500-rc6-2018-01-26\"><strong>here</strong></a>.</p>\n<h1 id=\"troubleshooting\">Troubleshooting</h1>\n<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>\n<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'.\n  Types of property 'auth' are incompatible.\n    Type '() =&gt; FirebaseAuth' is not assignable to type '() =&gt; Auth'.\n      Type 'FirebaseAuth' is not assignable to type 'Auth'.\n        Types of property 'app' are incompatible.\n          Type 'FirebaseApp' is not assignable to type 'App'.\n            Types of property 'auth' are incompatible.\n              Type '() =&gt; FirebaseAuth' is not assignable to type '() =&gt; Auth'.\n                Type 'FirebaseAuth' is not assignable to type 'Auth'.\n</code></pre>\n<h4 id=\"thenyoucansolvetheissuebythefollowingsteps\">Then you can solve the issue by the following steps</h4>\n<p>Add the new <code>@firebase</code> packages to your <code>package.json</code>:</p>\n<pre><code class=\"json language-json\">\"@firebase/app\": \"0.1.7\",\n\"@firebase/auth\": \"0.3.2\",\n</code></pre>\n<p>Change your <code>firebase</code> import</p>\n<pre><code class=\"ts language-ts\">import * as firebase from 'firebase/app';\n</code></pre>\n<p>to use the new format (with the default export syntax)</p>\n<pre><code class=\"ts language-ts\">import firebase from '@firebase/app';\n</code></pre>\n<p>This may then spit out the following error</p>\n<pre><code class=\"ts language-ts\">error TS2503: Cannot find namespace 'firebase'.\n</code></pre>\n<p>For me, this was caused by setting the following type</p>\n<pre><code class=\"ts language-ts\">phoneRecaptchaVerifier: firebase.auth.RecaptchaVerifier;\n</code></pre>\n<p>You can solve this by using the new <code>@firebase/auth-types</code> package</p>\n<pre><code class=\"ts language-ts\">import { RecaptchaVerifier } from '@firebase/auth-types';\n</code></pre>\n<p>Then just remove the <code>firebase.auth.</code> so that you have the cleaner version</p>\n<pre><code class=\"ts language-ts\">phoneRecaptchaVerifier: RecaptchaVerifier;\n</code></pre>\n<p>Note: when calling a constructor like <code>new firebase.auth.RecaptchaVerifier</code>(), you’ll still need the\n<code>firebase.auth.</code> prefix.</p>",
            "url": "https://devintent.com/blog/2018-01-28-angularfire2-5-0-0-rc-6-released.md",
            "title": "AngularFire2 5.0.0-rc.6 Released",
            "summary": "Details about the AngularFire2 5.0.0-rc.6 release.",
            "date_modified": "2018-01-28T00:00:00.000Z",
            "tags": [
                "firebase",
                "angular"
            ]
        },
        {
            "id": "blog/2017-10-04-why-are-angular-material-styles-duplicated-in-my-project.md",
            "content_html": "<p>This article assumes that you are using SCSS with the <a href=\"https://cli.angular.io/\">Angular CLI</a>.</p>\n<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>\n<h4 id=\"whatdotheseduplicatedstyleslooklike\">What do these duplicated styles look like?</h4>\n<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>\n<p>You can see the <code>.mat-toolbar.mat-primary</code> style at the top. Then you can see it down below once\nmore. This time with the same exact styles (<code>background</code>, <code>color</code>) and values, but all of them\noverridden.</p>\n<p>In this example, there is only 1 duplicate set of styles, but it is very easy to\nsuddenly see 3 duplicate sets or 5 or more! As you might imagine, this can significantly impact your\nbundle size in addition to complicating the styling of your app.</p>\n<p>Now show some examples to showcase how easy it is to get into this situation…</p>\n<h4 id=\"fromtheangularmaterialthemingguidehttpsmaterialangularioguidetheming\">From the <a href=\"https://material.angular.io/guide/theming\">Angular Material Theming Guide</a></h4>\n<p>A typical theme file will look something like this:</p>\n<p><strong>styles.scss</strong>:</p>\n<pre><code class=\"scss language-scss\">@import '~@angular/material/theming';\n// Plus imports for other components in your app.\n\n// Include the common styles for Angular Material. We include this here so that you only\n// have to load a single css file for Angular Material in your app.\n// Be sure that you only ever include this mixin once!\n@include mat-core();\n\n// Define the palettes for your theme using the Material Design palettes available in palette.scss\n// (imported above). For each palette, you can optionally specify a default, lighter, and darker\n// hue.\n$candy-app-primary: mat-palette($mat-indigo);\n$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);\n\n// The warn palette is optional (defaults to red).\n$candy-app-warn: mat-palette($mat-red);\n\n// Create the theme object (a Sass map containing all of the palettes).\n$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);\n\n// Include theme styles for core and each component used in your app.\n// Alternatively, you can import and @include the theme mixins for each component\n// that you are using.\n@include angular-material-theme($candy-app-theme);\n</code></pre>\n<p>Now if this is all you do, you won’t run into problems, even if you ignore most of the comments.</p>\n<p>However, we all know that real production apps need to integrate this code into a much more complex\nsystem. For instance, the full Angular Material theme may not be included in the App Shell (used to\nquickly paint the screen and let users on low bandwidth devices know that your app is bootstrapping).</p>\n<p>In this article, we’ll use <a href=\"https://angular.io\">https://angular.io</a> and its code as an example since\nmany developers look at this <a href=\"https://github.com/angular/angular/tree/4.4.4/aio\">AIO repo</a> and copy\nthe code from it into their own apps.</p>\n<p><strong>ng-io-theme.scss</strong>:</p>\n<pre><code class=\"scss language-scss\">@import '~@angular/material/theming';\n// Plus imports for other components in your app.\n\n// Include the base styles for Angular Material core. We include this here so that you only\n// have to load a single css file for Angular Material in your app.\n@include mat-core();\n\n// Define the palettes for your theme using the Material Design palettes available in palette.scss\n// (imported above). For each palette, you can optionally specify a default, lighter, and darker\n// hue.\n$ng-io-primary: mat-palette($mat-blue, 700, 600, 800);\n$ng-io-accent: mat-palette($mat-red, 700, 600, 800);\n\n// The warn palette is optional (defaults to red).\n$ng-io-warn: mat-palette($mat-red);\n\n// Create the theme object (a Sass map containing all of the palettes).\n$ng-io-theme: mat-light-theme($ng-io-primary, $ng-io-accent, $ng-io-warn);\n\n// Include theme styles for core and each component used in your app.\n// Alternatively, you can import and @include the theme mixins for each component\n// that you are using.\n@include angular-material-theme($ng-io-theme);\n</code></pre>\n<p>There’s a very important comment that has been removed from this version.\n<code>// *Be sure that you only ever include this mixin once!*</code></p>\n<p>Now if you miss that, and you use some other examples like the following, you may start to see\nduplicate styles and even need to resort to <code>!important</code> on many of your styles that target Angular\nMaterial classes like <code>.mat-form-field</code> or <code>.mat-raised-button</code>.</p>\n<p>I have run into apps with these issues, and it has resulted in 500 kB to 1.5 MB of bloat in the\ndeveloper build of the site. In production builds the impact is smaller, but every kB counts when\nshooting for great <a href=\"https://www.webpagetest.org/\">WebPageTest</a> or\n<a href=\"https://developers.google.com/web/tools/lighthouse/\">Lighthouse</a> scores!</p>\n<p><strong>main.scss</strong>:</p>\n<pre><code class=\"scss language-scss\">// import global themes\n@import '~@angular/material/theming';\n@import './ng-io-theme';\n\n// import global variables\n@import './constants';\n\n// import global mixins\n@import './mixins';\n\n// import directories\n@import './0-base/base-dir';\n@import './1-layouts/layouts-dir';\n@import './2-modules/modules-dir';\n</code></pre>\n<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>\n<p><strong>styles.scss</strong>:</p>\n<pre><code class=\"scss language-scss\">/* You can add global styles to this file, and also import other style files */\n@import './styles/ng-io-theme';\n@import './styles/main.scss';\n</code></pre>\n<p>You can see here that <code>styles.scss</code> is including <code>ng-io-theme.scss</code> as well. Then including\n<code>main.scss</code> which also includes <code>@include mat-core();</code>. There is another include here that is\ngetting duplicated as well, <code>@include angular-material-theme($ng-io-theme);</code>.</p>\n<p>The AIO repo uses considerably more (custom scripts, rollup, etc.) than just the Angular CLI to\nbundle and deploy their application. I wasn’t able to determine exactly how they avoid duplicate\nAngular Material styles with this setup, but I did verify that there are not any duplicate Angular\nMaterial styles on the production site.</p>\n<h4 id=\"howshouldidothisinmyapp\">How should I do this in my app?</h4>\n<p>You probably want to stick closer to the Angular CLI only approach for your own apps as long as you\ncan. So I’ll provide an example to use in that case.</p>\n<p><strong>styles.scss</strong>:</p>\n<pre><code class=\"scss language-scss\">@import './styles/theme';\n\n// Include the base styles for Angular Material core. We include this here so that you only\n// have to load a single css file for Angular Material in your app.\n// Be sure that you only ever include this mixin once!\n@include mat-core();\n\n// Include theme styles for core and each component used in your app.\n// Alternatively, you can import and @include the theme mixins for each component that you are using.\n@include angular-material-theme($app-theme);\n\nhtml {\n...\n</code></pre>\n<p>This is the <code>src/styles.scss</code> file found in Angular CLI projects with SCSS enabled.</p>\n<ul>\n<li><p>Styles in this file are applied globally without any <code>ViewEncapsulation</code>.</p></li>\n<li><p>This file is included in your app only once via the <code>.angular-cli.json</code> file via\n<code>“styles”: [“styles.scss”]</code>.</p></li>\n<li><p>You should not import this file into any other SCSS file.</p></li>\n<li><p>The Angular Material <code>@include</code> statements should be in this file.</p></li>\n</ul>\n<p><strong>Note:</strong> If you are using an App Shell for your app, the Angular Material <code>@include</code> statements\nare probably in another file. Just make sure that it is only included once.</p>\n<p>However, this file is free to include other SCSS files like your <code>src/styles/_theme.scss</code> found below</p>\n<p><strong>_theme.scss</strong>:</p>\n<pre><code class=\"scss language-scss\">@import '~@angular/material/theming';\n\n// Define the palettes for your theme using the Material Design palettes available in palette.scss\n// (imported above). For each palette, you can optionally specify a default, lighter, and darker hue.\n$app-primary: mat-palette($mat-teal, 700, 100, 900);\n$app-accent: mat-palette($mat-orange);\n\n// The warn palette is optional (defaults to red).\n$app-warn: mat-palette($mat-red);\n\n// Create the theme object (a Sass map containing all of the palettes).\n$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn);\n</code></pre>\n<p>In this file we define the <code>$app-theme</code> variable that is later used in <code>src/styles.scss</code>.</p>\n<p><strong>Note:</strong> We’re using a feature of SCSS here that is called “Partials”. You can find out more about\nthem in <a href=\"https://stackoverflow.com/a/25251042/633107\">this StackOverflow answer</a> or in\n<a href=\"http://sass-lang.com/guide\">the official SASS docs</a>. Note that the <code>_</code> in the filename is very\nimportant here and changes the behavior of SASS.</p>\n<p>Now this file can be imported in many places in your app to give you access to variables like\n<code>$app-accent</code> for use in a statement like the following without duplicating styles.</p>\n<p><strong>app.component.scss</strong>:</p>\n<pre><code class=\"scss language-scss\">@import '../../styles/theme';\n\n.noRecordsContainer {\n  padding: 48px;\n  background-color: mat-color($app-accent, 50);\n  width: 100%;\n}\n\n.errorMessageContainer {\n  padding: 48px;\n  background-color: mat-color($app-warn, 50);\n  width: 100%;\n}\n</code></pre>\n<p>This lets you use your Material Design palette in your custom components. In this case, we’re using\nthe lightest accent color (<code>50</code>) as the background of the container which provides a message about\nthe empty search result set. We’re also using the lightest accent color of the warn palette as the\nbackground color of our error panel.</p>\n<p>These are just two very simple examples of the powerful capabilities of using SCSS along with the\nAngular Material Theming system. Find our more in their\n<a href=\"https://material.angular.io/guide/theming-your-components\">guide to theming your own components</a>.</p>\n<h4 id=\"summary\">Summary</h4>\n<ul>\n<li><p>Be careful of how you set up SCSS in your Angular Material and Angular CLI project. It can lead to\nbloat and styling complications.</p></li>\n<li><p>Follow the architecture above to eliminate duplicate styles if you have them</p></li>\n<li><p>Brush up on the <a href=\"http://sass-lang.com/guide\">basics of SASS</a> and the capabilities of the\n<a href=\"https://material.angular.io/guide/theming-your-components\">Angular Material Theming system</a></p></li>\n<li><p>Keep leveraging these great tools to build amazing high performance web applications with solid UX!</p></li>\n</ul>\n<p>I hope that you find this helpful. If you would like to see more Angular Material content, please\nlet me know.</p>\n<p>There will be some great presentations next week (Oct 10–12th) at\n<a href=\"https://angularmix.com\">AngularMix</a> in Orlando, FL USA. I’ll be presenting\n“Delight your Organization with <a href=\"https://material.io/guidelines/material-design/\">Material Design</a>”\non 10/12. There will be many other talks including Angular’s new Component Dev Kit (CDK), which\nAngular Material leverages, and Angular CLI’s new DevKit and schematics.</p>\n<p>Tickets are still available, and you can get \\$100 off with the code <code>MIXPRENTICE</code>! They include an\nafter party at the Wizarding World of Harry Potter in Universal Studios Orlando. I hope to see you\nthere!</p>",
            "url": "https://devintent.com/blog/2017-10-04-why-are-angular-material-styles-duplicated-in-my-project.md",
            "title": "Why are Angular Material styles duplicated in my project?",
            "summary": "Instructions for troubleshooting duplication of styles caused by theming configuration.",
            "date_modified": "2017-10-04T00:00:00.000Z",
            "tags": [
                "angular-material",
                "material-design",
                "angular"
            ]
        },
        {
            "id": "blog/2017-03-24-angular-v4-final-and-angular-cli-v1-final-released.md",
            "content_html": "<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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<p>For most projects not using Angular Universal, it’s just that easy to upgrade from Angular v2 to Angular v4!</p>\n<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>\n<h4 id=\"torecapthemajorfeatures\">To recap the major features</h4>\n<ul>\n<li><p>Animations pulled out of core for performance, separation of concerns</p></li>\n<li><p>*ngIf supports and else syntax</p></li>\n<li><p>*ngFor supports an as syntax to assign local variables</p></li>\n<li><p>Angular Universal is now officially part of Angular core</p></li>\n<li><p>TypeScript 2.1+ support</p></li>\n<li><p>Improved template error messages</p></li>\n</ul>\n<h1 id=\"angularcliv1\">Angular CLI v1</h1>\n<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>\n<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>\n<p><a href=\"/large-images/angular-cli-promo.png\"><img src=\"/large-images/angular-cli-promo.png\" alt=\"Angular CLI Example\" /></a></p>\n<h1 id=\"troubleshooting\">Troubleshooting</h1>\n<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>\n<p>If you see warnings about typing checking being required when linting via the CLI, just update your link command to the following:</p>\n<pre><code class=\"json language-json\">\"lint\": \"ng lint --type-check\"\n</code></pre>\n<p>I also ran into issues with the CLI’s production builds due to template validation.</p>\n<ul>\n<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>\n<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>\n</ul>\n<pre><code class=\"ts language-ts\">Type 'string' is not assignable to type 'boolean'\n</code></pre>\n<p>I’m waiting for some feedback before opening bugs for these last two issues.</p>\n<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>",
            "url": "https://devintent.com/blog/2017-03-24-angular-v4-final-and-angular-cli-v1-final-released.md",
            "title": "Angular v4 Final and Angular CLI v1 Final Released!",
            "summary": "Details about the Angular v4 and CLI v1 Final releases.",
            "date_modified": "2017-03-24T00:00:00.000Z",
            "tags": [
                "angular-cli",
                "angular"
            ]
        },
        {
            "id": "blog/2016-12-20-state-of-angular-universal-and-aot.md",
            "content_html": "<p>I’ve spent a good deal of the last week looking at\n<a href=\"https://github.com/angular/universal\">Angular Universal</a> and Ahead of Time (AOT) compilation.\nUntil now, I had been waiting to dig into them because it was clear they were still in the\nexperimental/alpha stages.</p>\n<p>However, I decided that I want to update the <a href=\"https://www.devintent.com\">DevIntent website</a> from\nAngular <code>1.5.7</code> to the latest version of Angular over the Christmas break!</p>\n<p>Since this is a marketing website, I need it to be super fast, especially on mobile, and have\nexcellent SEO! I’m also using this as a testing ground for some work on an upcoming client project.</p>\n<h1 id=\"currentwebsitestatus\">Current website status</h1>\n<p><i>Times listed for No throttling / Regular 3G.</i></p>\n<ul>\n<li><p>36 requests</p></li>\n<li><p>1.2 MB</p></li>\n<li><p>459ms / 3760ms DOMContentLoaded</p></li>\n<li><p>920ms / 13850ms Load</p></li>\n</ul>\n<p>This is fairly typical of a smaller Angular 1.5.x application that is using a few libraries\n(Angular Material, Font Awesome, etc.) and is hosted on Firebase Hosting. It’s fine on desktop with\nbroadband internet, but <strong>not good enough on a mobile 3G device</strong>.</p>\n<h1 id=\"bustouttheangularcli\">Bust out the Angular-CLI</h1>\n<p>My first choice is generally the Angular-CLI because I believe in what they are doing to make Angular\nmore approachable to new users. I use it as much as I can so that I can provide feedback, open bug\nreports, and even submit PRs.</p>\n<p>The first step was to see if Universal and AOT was working yet in the CLI. I found that they were\nboth working, just not together. The Angular-CLI <a href=\"https://github.com/angular/angular-cli/issues/1050\">does not support</a>\nAngular Universal. It does support AOT, but there are around\n<a href=\"https://github.com/angular/angular-cli/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20aot%20\">63 open issues</a>\nrelated to AOT.</p>\n<p>There is a <a href=\"https://github.com/devCrossNet/angular-cli\">separate fork</a> for a version of the CLI that\nsupports Universal, but it <a href=\"https://github.com/devCrossNet/angular-cli/issues/13\">doesn’t support AOT</a>.\nIt appears that they created this fork because the Angular-CLI team didn’t have the resources to\nsupport Universal.</p>\n<h1 id=\"graboneofthehotseedprojects\">Grab one of the hot seed projects</h1>\n<p>From the latest presentations that I’ve seen at conferences, I knew that there were a number of great\nAngular seeds out there.</p>\n<p>The first one I looked at was <a href=\"https://github.com/mgechev/angular-seed\">angular-seed</a> from\nMinko Gechev. It is really well-known, has 3,344+ stars, and supports AOT, Docker, etc. Unfortunately\nit doesn’t support <a href=\"https://github.com/mgechev/angular-seed/issues/1566\">Angular Universal</a> or\n<a href=\"https://github.com/mgechev/angular-seed/issues/1552\">Webpack</a>. After using Webpack with the\nAngular-CLI, I decided that I don’t want to use another bundler in my non-Angular-CLI projects.</p>\n<p>I checked into <a href=\"https://github.com/angular/universal-starter\">Universal Starter</a> from the Angular\nUniversal team. It uses Webpack and has basic support for AOT. But it is really minimal and doesn’t\ninclude <a href=\"https://github.com/angular/universal-starter/issues/259\">support for SASS/SCSS</a>. I decided\nthat I might come back to it.</p>\n<p><a href=\"https://github.com/AngularClass/angular2-webpack-starter\">Angular2-Webpack-Starter</a> from\nAngularClass was another that caught my eye since it obviously supported Webpack, but it also had\na lot of the other stuff ready to go. This included Router, HTTP, Forms, Hot Module Reload (HMR),\nAsync/Lazy Routes, Material Design, and tests! It also has a great list of guides and tips like\n<a href=\"https://github.com/AngularClass/angular2-webpack-starter/issues/136\">setting up SASS/SCSS</a>.\nUnfortunately, it doesn’t yet support\n<a href=\"https://github.com/AngularClass/angular2-webpack-starter/issues/885\">AOT compilation</a> or\n<a href=\"https://github.com/AngularClass/angular2-webpack-starter/issues/576\">Angular Universal</a>.</p>\n<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">Found a number of seeds w/\n<a href=\"https://twitter.com/hashtag/AngularUniversal?src=hash&amp;ref_src=twsrc%5Etfw\">#AngularUniversal</a>\nsupport, 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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<h1 id=\"finallypickingaseed\">Finally picking a seed</h1>\n<p>I settled on giving Anthony’s (qdouble)\n<a href=\"https://github.com/qdouble/angular-webpack2-starter\">fork of angular2-webpack-starter</a> a shot. It\ncombines all the great stuff from the original angular2-webpack-starter with support for AOT and\nUniversal! One thing I quickly noticed was that the project is stuck on an older version (<code>v2.1</code>) of\nAngular (latest is <code>v2.3</code>).</p>\n<p>After a lot of research, it became obvious that changes to Angular core in v2.2 and v2.3 broke\nAngular Universal. Apparently the Angular core team has realized that this is a problem.</p>\n<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">But I just saw this\n<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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<p>Because of this, they decided a couple weeks ago to move key pieces of Angular Universal into the\nAngular core. Unfortunately, a number of key people have been on vacation since this decision\nwas made. So we’re stuck in this state where using Angular Universal means staying on Angular <code>v2.1</code>.</p>\n<p>This also means that support for Angular Universal in a new version of Angular will have to wait for\nat least v4 which just entered <code>beta.0</code>.</p>\n<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">Angular 4.0.0-beta.0 is out. You&#39;re\nwondering why it&#39;s Angular 4? Read about the reasoning behind here:\n<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>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n<h1 id=\"measuringthebenefits\">Measuring the benefits</h1>\n<p>The main purpose of the chosen seed/starter is performance (i.e. Angular Universal, Webpack 2, and\nAOT compilation). I checked the README for some stats for nerds (i.e. perf goodies) but sadly found\nnone. Thus, I set to gathering some performance stats on the current build of the starter.</p>\n<ul>\n<li>Times listed for No throttling / Regular 3G.</li>\n</ul>\n<h4 id=\"devmode\">Dev Mode</h4>\n<blockquote>\n  <p>npm start</p>\n</blockquote>\n<ul>\n<li>29 requests</li>\n<li>5.8 MB</li>\n<li>1300ms / 66000ms DOMContentLoaded</li>\n<li>1350ms / 66000ms load</li>\n</ul>\n<h4 id=\"universal\">Universal</h4>\n<blockquote>\n  <p>npm run universal</p>\n</blockquote>\n<ul>\n<li>16 requests</li>\n<li>363 KB</li>\n<li>928ms / 4480ms DOMContentLoaded</li>\n<li>973ms / 5020ms load</li>\n</ul>\n<h4 id=\"aotmode\">AOT mode</h4>\n<blockquote>\n  <p>npm run compile + npm run prodserver</p>\n</blockquote>\n<ul>\n<li>16 requests</li>\n<li>301 KB</li>\n<li>432ms / 3530ms DOMContentLoaded</li>\n<li>495ms / 3930ms load</li>\n</ul>\n<h4 id=\"universalaot\">Universal + AOT</h4>\n<blockquote>\n  <p>npm run universal:aot or npm run compile:universal+ npm run prodserver</p>\n</blockquote>\n<ul>\n<li>16 requests</li>\n<li>392 KB</li>\n<li>494ms / 4410ms DOMContentLoaded</li>\n<li>535ms / 5030ms load</li>\n</ul>\n<h4 id=\"testsranon\">Tests Ran on</h4>\n<ul>\n<li><p>Chrome 57.0.2951.0 canary (64-bit)</p></li>\n<li><p>Cache disabled</p></li>\n<li><p>MacBook Pro (Retina, 15-inch, Mid 2014)</p></li>\n<li><p>2.8 GHz Intel Core i7</p></li>\n<li><p>16 GB 1600 MHz DDR3</p></li>\n<li><p>OS X El Capitán 10.11.6 (15G1212)</p></li>\n<li><p>NodeJS 6.7.0</p></li>\n</ul>\n<h1 id=\"analysis\">Analysis</h1>\n<p>Now I know that Universal and AOT are still undergoing a lot of breaking changes and needed\nimprovements, but I found it a little odd that the combination (Universal + AOT) was slower than the\nbuild with AOT alone.</p>\n<p>Since the angular-cli isn’t supporting Universal + AOT yet, I was looking to find a solid seed for\nUniversal, AOT, Webpack 2, Material 2, SCSS, etc. and this one seems to be the closest that I can\nfind which isn’t significantly broken.</p>\n<p>With the numbers above, I was wondering if I should even bother with Universal at this point.\nThen I thought, well Universal should help get that initial paint a lot faster. But on any network\nwith 3G+, the time between initial paint and interactivity is under 50ms and isn’t even noticeable.\nIf I drop down to Regular 2G, then I do see the initial DOM loaded for about 2s before JavaScript\ntakes control and the page is re-rendered and fully ready for interaction.</p>\n<p>Perhaps part of this issue is that the app doesn’t have an appShell (it’s just a white “Loading…”\npage), but either way I’m not sure I should go to the extra trouble of running a NodeJS server\nfor Universal at this point. I could just host a client-only app in Firebase Hosting using their\nEdge CDN w/ AOT and maybe that would be even faster than the numbers above.</p>\n<p>SEO is something that I really need, but I’m not convinced that Universal will work properly here\nand deliver the desired results. There’s some\n<a href=\"https://github.com/angular/universal-starter/issues/287\">possible hacks</a> discussed in the\nuniversal-starter project where the meta tags can be manipulated. However, Angular’s new\n<a href=\"https://github.com/angular/angular/pull/12322\">Meta Service</a> just landed in Angular <code>v4-beta.0</code>\nthanks to Dzmitry Shylovich! Unfortunately Universal isn’t compatible with the latest versions of\nAngular yet.</p>\n<h1 id=\"tldr\">TL;DR</h1>\n<p>It appears that I should just stick with AOT compilation and wait until Universal gets better\nsupport from the Angular core team (in progress, no ETA).</p>\n<p>Thankfully the chosen <a href=\"https://github.com/qdouble/angular-webpack2-starter\">starter</a> makes that a\nwell-supported option in addition to supporting these configurations used in the benchmarks above.\nThis is what enabled the ability to gather these numbers using different approaches, while keeping\nthe code-base exactly the same. Thanks to <a href=\"https://github.com/qdouble\">Anthony</a> for the hard work\non this starter and for sharing what’s been working for him on his projects!</p>",
            "url": "https://devintent.com/blog/2016-12-20-state-of-angular-universal-and-aot.md",
            "title": "What’s the state of Angular Universal and AOT?",
            "summary": "The state of Angular Universal and AOT as of the end of 2016.",
            "date_modified": "2016-12-20T00:00:00.000Z",
            "tags": [
                "universal",
                "angular"
            ]
        },
        {
            "id": "blog/2016-10-22-upgrade-from-angular-2-rc4-to-final-with-angular-cli.md",
            "content_html": "<p><em>I’ve completed the RC4 => <code>2.1.2</code> upgrade for one proprietary app and one\n<a href=\"https://github.com/gdg-x/nexus\">open source app</a>. Even with experience, this process is far from\nefficient or problem-free with the various libraries, modules, and systems breaking or otherwise\naffecting each other.</em></p>\n<p><em>It’s clear the Angular 2 Release Candidates were actually Alphas and what we’re using now in\n<code>2.1.1</code> is Beta. You could say that the Angular Core is in Release Candidate state currently, but\nthe ecosystem of semi-mandatory modules that make up the platform are mostly in some form of Alpha\nor Beta.</em></p>\n<h1 id=\"letsgetstarted\">Let’s get started</h1>\n<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>\n<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>\n<p>Note that there is an updated guide here:\n<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>\n<p><em>I also submitted a <a href=\"https://github.com/angular/angular-cli/pull/2765\">PR</a> to improve the grammar of\nthis upgrade warning message.</em></p>\n<p>The first step of this helpful guide is to make sure that you are up to Angular RC6 or greater. So\nyou would then find that you need to upgrade from Angular RC4 to the latest which includes the major\nbreaking change of <a href=\"https://angular.io/docs/ts/latest/guide/ngmodule.html\">ngModules</a> announced in\n<a href=\"http://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html\">this blog post</a>.\nThis blog post announcing Angular RC5 includes a really helpful link to a migration guide.\nUnfortunately, that migration guide\n(<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>)\nis a <strong><code>404</code></strong> on the Angular.io docs site.</p>\n<h1 id=\"nowthetaskistofindamigrationguidethatworksforrc4tofinal\">Now the task is to find a migration guide that works for RC4 to final</h1>\n<p>There was a\n<a href=\"https://www.reddit.com/r/Angular2/comments/4x11z6/angular_2_rc4_to_rc5_migration_guide/\">Reddit</a>\ndiscussing this lost migration guide, but it doesn’t point to a new location.</p>\n<p>There is\n<a href=\"http://stackoverflow.com/questions/39559327/update-angular-2-from-rc4-to-final-release\">StackOverflow question</a>\nthat poses this exact question, but it’s first suggested solution appears to be the most time\nintensive option… review the changelogs for RC5, RC6, RC7, and final for breaking changes and\nthen make adjustments to your project. The second option here is one that I have been considering,\ngenerate a new project with the latest angular-cli <code>beta.19</code> and then pull that configuration into\nyour existing project.</p>\n<p>After quite a bit of looking, I didn’t really find something that I was happy with. A few guides hit\nabout 25% of what I needed, but I couldn’t find anything that was much more complete.</p>\n<h1 id=\"getuptospeedwiththeconceptsfirst\">Get up to speed with the concepts first</h1>\n<p>I highly suggest reading the following before starting:</p>\n<p>The first is the\n<a href=\"http://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html\">Angular team blog post</a>\nthat covers the reasons why ngModule exists and how it helps you.</p>\n<p>Then the <a href=\"https://angular.io/docs/ts/latest/guide/ngmodule.html\">official docs on ngModule</a>\ncover some key patterns like having a\n<a href=\"https://angular.io/docs/ts/latest/guide/ngmodule.html#core-module\">Core Module</a> and\n<a href=\"https://angular.io/docs/ts/latest/guide/ngmodule.html#shared-module\">Shared Module</a>. It also covers\n<a href=\"https://angular.io/docs/ts/latest/guide/ngmodule.html#lazy-load\">lazy loading modules</a>.</p>\n<h1 id=\"startwithasinglengmodule\">Start with a single ngModule</h1>\n<p>This step involves just creating a single module and adding everything to it. This makes sense for\nsmall to medium-sized projects. If your project is already large, you’ll want to move on to the next\nstep.</p>\n<p>Basically this step just involves using the docs links above to create your AppModule and plumb\neverything together.</p>\n<h4 id=\"awaywiththeboilerplate\">Away with the boilerplate!</h4>\n<p>After you’ve got an ngModule, you’ll need a lot less boilerplate. Unfortunately, you (or angular-cli)\nalready wrote it, so you’ll have to go and remove it now. This includes changing all of your\ncomponents by removing their directives, providers, pipes, and lots and lots of imports that aren’t\nneeded anymore.</p>\n<h1 id=\"createasharedmodule\">Create a Shared Module</h1>\n<p>Use the <a href=\"https://angular.io/docs/ts/latest/guide/ngmodule.html#shared-module\">docs</a> on creating a\nShared Module and move your application-wide services and common Angular modules (FormsModule,\nRouterModule, etc.) into this new SharedModule.</p>\n<h1 id=\"evaluateyourprojectformodularity\">Evaluate your project for modularity</h1>\n<p>Now you’ll want to think about your project and find out if it makes sense to break up specific\nroutes into lazily loaded modules. Ideally, your module that is bootstrapped at the root of your\napp should be as lean as possible. Once you’ve identified these modules, it’s time to create them\nand start setting up the\n<a href=\"https://angular.io/docs/ts/latest/guide/ngmodule.html#lazy-load\">lazy loading in the router</a>.</p>\n<h1 id=\"migrateangularcli\">Migrate Angular-CLI</h1>\n<p>OK, now you’ve setup ngModules and updated your package.json to use <code>@angular/xxx: 2.1.2</code>, you\nare ready to proceed with the\n<a href=\"https://github.com/angular/angular-cli/wiki/Upgrading-from-Beta.10-to-Beta.14\">angular-cli migration guide</a>.\n<strong>Carefully</strong> follow the guide, and you will be about 90% of the way there.</p>\n<p>Many people noticed that their favicon and 404 pages weren’t showing up in dist/ after upgrading.\nThe community filed numerous bugs, but in <code>beta.19</code> this was fixed. Make the changes below to take\nadvantage of this new feature that allows specifying an array of assets.</p>\n<p><strong>angular-cli.json</strong> (old)</p>\n<pre><code class=\"json language-json\">\"assets\": \"assets\",\n</code></pre>\n<p><strong>angular-cli.json</strong> (new)</p>\n<pre><code class=\"json language-json\">\"assets\": [\n  \"assets\",\n  \"elements.html\",\n  \"404.html\",\n  \"favicon.ico\",\n  \"manifest.webapp\",\n  \"icons\"\n],\n</code></pre>\n<p>Obviously the contents of this array will be specific to your application.</p>\n<h1 id=\"migrateangularmaterial2\">Migrate Angular Material2</h1>\n<p>Their <a href=\"https://github.com/angular/material2/blob/master/GETTING_STARTED.md\">getting started guide</a>\nprovides the minimal level of help required to get this working. This has changed quite a bit from\nwhat was found in the RC5 blog post. There is now a single MaterialModule that you need to load.</p>\n<p><strong>src/app/app.module.ts</strong></p>\n<pre><code class=\"ts language-ts\">import { MaterialModule } from '@angular/material';\n\n@NgModule({\n  imports: [MaterialModule.forRoot()],\n</code></pre>\n<p>If you are using any of their sliders, you’ll need to import hammer.js with the new angular-cli process.</p>\n<p><strong>angular-cli.json</strong></p>\n<pre><code class=\"json language-json\">{\n  \"scripts\": [\"../node_modules/hammerjs/hammer.js\"]\n}\n</code></pre>\n<p>Additionally, material2 now has a theming system which you will need to configure for the styling\nof your UI components to look good (i.e. not be mostly grey). See their theming guide\n<a href=\"https://github.com/angular/material2/blob/master/docs/theming.md\">here</a> to set this up.</p>\n<h1 id=\"migratefirebase\">Migrate Firebase</h1>\n<p>If you are using the Firebase SDK (required for many features like Firebase Storage that aren’t yet\nsupported in AngularFire2) then the way that you load that library has changed in the angular-cli.</p>\n<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>\n<p><strong>angular-cli.json</strong></p>\n<pre><code class=\"json language-json\">{\n  \"scripts\": [\"../node_modules/firebase/firebase.js\"]\n}\n</code></pre>\n<h1 id=\"upgradeangularfire2\">Upgrade AngularFire2</h1>\n<p>Their <a href=\"https://github.com/angular/angularfire2/blob/master/docs/1-install-and-setup.md#4-setup-ngmodule\">docs</a>\nare quite helpful, but they only covered about 95% of what I needed to do. That last 5% was pretty\npainful as what I got working in angular-cli <code>beta.17</code> needed more tweaking with <code>beta.19</code>.</p>\n<p>For just using AngularFire2 without Firebase Auth, you can do this:</p>\n<p><strong>src/app/app.module.ts</strong></p>\n<pre><code class=\"ts language-ts\">import { AngularFireModule } from 'angularfire2';\n\nconst firebaseConfig = {\n  apiKey: '&lt;your-key&gt;',\n  authDomain: '&lt;your-project-authdomain&gt;',\n  databaseURL: '&lt;your-database-URL&gt;',\n  storageBucket: '&lt;your-storage-bucket&gt;'\n};\n\n@NgModule({\n  imports: [\n    BrowserModule,\n    AngularFireModule.initializeApp(firebaseConfig)\n  ],\n</code></pre>\n<p>If you’re using Firebase Auth, you’ll need a bit more. They cover this in their\n<a href=\"https://github.com/angular/angularfire2/blob/master/docs/5-user-authentication.md#configure-application-in-bootstrap\">Auth docs</a>.</p>\n<p><em>I submitted a <a href=\"https://github.com/angular/angularfire2/pull/628\">PR</a> to help make\nthese docs a little more straightforward.</em></p>\n<p><strong>src/app/app.module.ts</strong></p>\n<pre><code class=\"ts language-ts\">import { AngularFireModule, AuthProviders, AuthMethods } from 'angularfire2';\n\nconst myFirebaseConfig = {\n  apiKey: '&lt;your-key&gt;',\n  authDomain: '&lt;your-project-authdomain&gt;',\n  databaseURL: '&lt;your-database-URL&gt;',\n  storageBucket: '&lt;your-storage-bucket&gt;',\n}\n\nconst myFirebaseAuthConfig = {\n  provider: AuthProviders.Google,\n  method: AuthMethods.Redirect\n}\n\n@NgModule({\n  imports: [\n    BrowserModule,\n    AngularFireModule.initializeApp(myFirebaseConfig, myFirebaseAuthConfig)\n  ],\n</code></pre>\n<p>**Troubleshooting\n**I needed to do a bit more here to deal with some TypeScript issues. Their\n<a href=\"https://github.com/angular/angularfire2/blob/master/docs/1-install-and-setup.md#troubleshooting\">existing docs</a>\nhere seemed to be designed for an older version of the angular-cli. I needed to remove\n<code>@types/firebase</code> from my <code>package.json</code> and use the typedefs from the Firebase SDK.</p>\n<p><strong>src/tsconfig.json</strong></p>\n<pre><code class=\"json language-json\">\"files\": [\n  \"../node_modules/firebase/firebase.d.ts\"\n]\n</code></pre>\n<p><em>If you are on the new AngularFire2 beta.6, this step is not needed since these typedefs are included\nin AngularFire2. Adding them again here will cause many duplicate type errors.</em></p>\n<h1 id=\"upgradeangular2googlemaps\">Upgrade Angular2-Google-Maps</h1>\n<p>The <a href=\"https://angular-maps.com/docs/getting-started.html#angular2-google-maps-setup\">docs</a> here are\nquite comprehensive and once I followed them, everything seemed to just work. The main change is\nrelated to ngModule.</p>\n<p><em>They also fixed some pesky bugs in the latest v0.15.0 release.</em></p>\n<p><strong>src/app/app.module.ts</strong></p>\n<pre><code class=\"ts language-ts\">import { AgmCoreModule } from 'angular2-google-maps/core';\n\n@NgModule({\n  imports: [\n    BrowserModule,\n    AgmCoreModule.forRoot({\n      apiKey: 'YOUR_KEY'\n    })\n  ],\n</code></pre>\n<h1 id=\"upgradeangular2polymer\">Upgrade Angular2-Polymer</h1>\n<p>The Vaadin team has done a lot of the tough work to streamline this process. Their documentation can\nbe found <a href=\"https://vaadin.com/docs/-/part/elements/angular2-polymer/ng-cli-webpack.html\">here</a>.</p>\n<p><em>As part of this process, I sent them a <a href=\"https://github.com/vaadin/angular2-polymer/pull/101\">PR</a> to\ncorrect their README’s link to these docs.</em></p>\n<p>One of the key changes here is the way that bootstrapping the Web Components polyfill is\naccomplished due to changes to the angular-cli. This includes creating a <strong>main-polymer.ts</strong> file\nwhich kicks off the bootstrapping of your Angular application after the <strong>WebComponentsReady</strong> event\nis fired.</p>\n<p><strong>src/main-polymer.ts</strong></p>\n<pre><code class=\"ts language-ts\">document.addEventListener('WebComponentsReady', () =&gt; {\n  // Load Angular app\n  require('./main.ts');\n});\n</code></pre>\n<p>Then you need to update angular-cli’s config to use this new main-polymer.ts as your app’s entry point.</p>\n<p><strong>angular-cli.json</strong></p>\n<pre><code class=\"json language-json\">\"main\": \"main-polymer.ts\",\n</code></pre>\n<p>Another key change from the angular-cli is that loading the <strong>webcomponents-lite.min.js</strong> file is\nnow easier. I also decided to get it from NPM instead of Bower.</p>\n<p><strong>angular-cli.json</strong></p>\n<pre><code class=\"json language-json\">{\n  \"scripts\": [\"../node_modules/webcomponents.js/webcomponents-lite.js\"]\n}\n</code></pre>\n<h1 id=\"fixissueswithbasicwebcomponents\">Fix issues with Basic Web Components</h1>\n<p>I found that the key here was to require the Basic Web Component scripts in the <strong>main-polymer.ts</strong>\nfile defined as part of the Angular2-Polymer configuration above. These web components don’t have\ntype definitions for TypeScript and importing their\n<a href=\"https://github.com/basic-web-components/basic-web-components/#installing-components-via-npm\">ES6 modules</a>\nwas a nightmare.</p>\n<p><strong>src/main-polymer.ts</strong></p>\n<pre><code class=\"ts language-ts\">document.addEventListener('WebComponentsReady', () =&gt; {\n  // Load basic web components\n  require('../node_modules/basic-arrow-selection');\n  require('../node_modules/basic-carousel');\n  require('../node_modules/basic-page-dots');\n\n  // Load Angular app\n  require('./main.ts');\n});\n</code></pre>\n<p>This worked somewhat, but still resulted in errors since the angular-cli doesn’t have an ES6 loader\nconfigured (separate from the TypeScript loader) and they don’t allow for customization of the\nWebpack configuration. This ES6 still ran OK on the latest Firefox, Chrome, and Safari, but it failed\non IE11.</p>\n<p>Due to this, I ended up removing Basic Web Components from my project and using\n<a href=\"https://ng-bootstrap.github.io/#/getting-started\">ngBootstrap’s</a>\n<a href=\"https://ng-bootstrap.github.io/#/components/carousel\">Carousel</a> instead.</p>",
            "url": "https://devintent.com/blog/2016-10-22-upgrade-from-angular-2-rc4-to-final-with-angular-cli.md",
            "title": "Upgrade from Angular 2.RC4 to final with Angular-CLI",
            "summary": "Details about the Angular 2.0.0-rc.5 release.",
            "date_modified": "2016-10-22T00:00:00.000Z",
            "tags": [
                "angular-cli",
                "angular"
            ]
        },
        {
            "id": "blog/2016-09-14-configuring-an-angularjs-app-for-production.md",
            "content_html": "<p>When running in production mode, your app should do the following:</p>\n<pre><code class=\"js language-js\">myApp.config([\n  '$compileProvider',\n  '$logProvider',\n  function ($compileProvider, $logProvider) {\n    $compileProvider.debugInfoEnabled(false);\n    $logProvider.debugEnabled(false);\n  },\n]);\n</code></pre>\n<p>Note that this is in addition to whatever else your app needs to do in its <code>.config()</code> function.\nFor this to be fully effective, you should use Angular’s <code>$log</code> service instead of <code>console.log()</code>\nthroughout your app.</p>\n<p>As Ben Nadel noted, if your app is doing element.scope() anywhere, it will no longer work after\n<code>$compileProvider.debugInfoEnabled(false)</code> is called.</p>\n<p><a href=\"/large-images/angularjs-horizontal-logo.png\"><img src=\"/large-images/angularjs-horizontal-logo.png\" alt=\"AngularJS Logo\" /></a></p>",
            "url": "https://devintent.com/blog/2016-09-14-configuring-an-angularjs-app-for-production.md",
            "title": "Configuring an AngularJS app for production",
            "summary": "Tips for configuring AngularJS applications for production.",
            "date_modified": "2016-09-14T00:00:00.000Z",
            "tags": [
                "angularjs"
            ]
        },
        {
            "id": "blog/2016-08-10-angular-2-rc-5-is-out.md",
            "content_html": "<p>It contains <strong>18 breaking changes</strong>, over <strong>40 new features</strong>, and <strong>80 bug fixes</strong>.</p>\n<p>RC 5 brings with it the significant new ngModule feature along with updates to forms, the router\n(Lazy Loading), material design, and more!</p>\n<p>This is the first RC of the new router. You can find out more about the router in Victor Savkin’s\nnew <a href=\"https://vsavkin.com/announcing-angular-2-router-book-2de3c2822f7c#.viylihqxo\">e-book</a>.</p>\n<p><a href=\"/icons/angular.svg\"><img src=\"/icons/angular.svg\" alt=\"Angular Icon\" /></a></p>\n<p>The associated Angular team blog post is located here:\n<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>\n<p>The migration guide used to be found in the Angular 2 docs\n<a href=\"https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html\">here</a> but it has been removed.\nIf you need help with upgrading from the RCs, please see\n<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>\n<p>The more detailed Changelog can be reviewed here:\n<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>",
            "url": "https://devintent.com/blog/2016-08-10-angular-2-rc-5-is-out.md",
            "title": "Angular 2 rc.5 is out!",
            "summary": "Details about the Angular 2.0.0-rc.5 release.",
            "date_modified": "2016-08-10T00:00:00.000Z",
            "tags": [
                "angular"
            ]
        },
        {
            "id": "blog/2016-07-15-angularjs-material-1-1-0-rc-x-privatization-of-styles-reverted.md",
            "content_html": "<p>If you are an <a href=\"https://material.angularjs.org/\">AngularJS Material</a> 1.x user, then you might\nhave noticed that, while trying out the 1.1.0 release candidates, many of your CSS fixes and\nworkarounds were broken.</p>\n<p>You may have worked around this problem (I know I've spoken to and see many people doing this)\nby changing your styles to target the new \"private\" styles (i.e. the <strong>_md-visually-hidden</strong>\nclass on <code>md-tabs</code>' <code>md-tabs-dummy-wrapper</code>) introduced in 1.1.0 RC.</p>\n<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>\n<p>I cautioned a number of people against this, pointing out that these are meant to be private\nstyles which will see unannounced breaking changes.</p>\n<p>Unfortunately, it turns out that these changes were far too disruptive and in some cases there\nwas no work around outside of using the private styles. So these private style changes have\nall been reverted in master via this commit. These changes will be in the next 1.1.0-RC.6\nbuild.</p>\n<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>\n<p>If you have already updated your entire application to rely on these private styles, then\nunfortunately, you will need to revert those changes as well in order to move to the final\n1.1.0 release.</p>\n<p>Note that this does not remove all private styles. There remain some styles, that existed\nprior to 1.1.0-RC1, that are still preceded with an underscore (\"_\"). These styles remain\nprivate and should not be used as breaking changes to them will not be announced.</p>\n<h2 id=\"thegoodnbspnews\">The Good&nbsp;News</h2>\n<p>If your project is on the latest stable release (<a href=\"https://material.angularjs.org/1.0.9/\">1.0.9</a>),\nthen your upgrade path to 1.1.0 should now be a bit smoother when 1.1.0 final lands.</p>\n<p>Additionally, if you are trying out <a href=\"https://material.angular.io/\">Angular Material</a>,\nyou should note that they are planning to include similarly denoted private styles.</p>\n<p>Please read <a href=\"https://groups.google.com/forum/#!msg/ngmaterial/mLJrRW9qrLA/C_Ni3LSrBQAJ\">this post</a>\nfor additional details and to ask questions.</p>",
            "url": "https://devintent.com/blog/2016-07-15-angularjs-material-1-1-0-rc-x-privatization-of-styles-reverted.md",
            "title": "AngularJS Material 1.1.0-RC.X Privatization of Styles Reverted",
            "summary": "Discussion of the decision to revert the privatization of styles in AngularJS Material 1.1.0.",
            "date_modified": "2016-07-15T00:00:00.000Z",
            "tags": [
                "angularjs-material"
            ]
        },
        {
            "id": "blog/2016-06-28-responsive-ui-angularjs-material.md",
            "content_html": "<p>When I presented this material in 2015, the Google Design team was calling it Adaptive UI. It has since been renamed in the\n<a href=\"https://material.io/design/\">Material Design Specification</a> to\n<a href=\"https://material.io/design/layout/responsive-layout-grid.html\">Responsive UI</a>. Note that, while the phrase uses the word\n\"responsive\", this is different from the Responsive Design from the recent past.</p>\n<iframe src=\"https://docs.google.com/presentation/d/e/2PACX-1vTxCK5LgapdJIXWomiPX1taogayrq_6GU7snmHQtlISnXZX61UMpYiHMlH7AGIZVby2U2CDX_bPpC1W/embed?start=false&loop=false&delayms=60000\"\n        frameborder=\"0\" width=\"796\" height=\"477\" allowfullscreen=\"true\" mozallowfullscreen=\"true\" webkitallowfullscreen=\"true\"></iframe>\n<p><strong>Google defines Responsive UI as:</strong></p>\n<blockquote>\n  <p>Responsive layouts in material design adapt to any possible screen size. This UI guidance includes a flexible grid that ensures\n  consistency across layouts, breakpoint details about how content reflows on different screens, and a description of how an app can\n  scale from small to extra-large screens.</p>\n</blockquote>\n<p>Similar to Responsive Design, the system uses breakpoints which match up with the screen width of various devices.</p>\n<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>\n<p>The Material Design site has some <a href=\"https://material.io/design/layout/responsive-layout-grid.html#grid-behavior\">great examples</a> of\nthe UI grid. They include animated images to demonstrate how the grid reacts to changes in screen width.</p>\n<p>For me, the most interesting and powerful part of Responsive UI with Material Design are the UI Patterns. They demonstrate how to\napply the breakpoints, grid, and surface behaviors to real-world UI design challenges.</p>\n<p>These patterns include</p>\n<ul>\n<li>Reveal</li>\n<li>Transform</li>\n<li>Reflow</li>\n<li>Expand</li>\n<li>Position</li>\n</ul>\n<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.\nOne of these tools, the exciting \"<a href=\"https://material.io/resources/resizer/\">Resizer</a>\", was previewed at the Polymer Summit in 2015.</p>\n<p>Video here:</p>\n<iframe width=\"796\" height=\"440\" src=\"https://www.youtube.com/embed/YiiXKoLYLMo\" frameborder=\"0\"\n        allow=\"accelerometer; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n<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>\n<p>For more in depth details, discussion, and links, please check out\n<a href=\"https://docs.google.com/presentation/d/1cLYWG-_mW92kezTI1JLYfi9kNH9wu2-SIpeNqyArlQw/edit?usp=sharing\">the slides</a> from this\npresentation.</p>",
            "url": "https://devintent.com/blog/2016-06-28-responsive-ui-angularjs-material.md",
            "title": "Responsive UI with AngularJS Material 1.x",
            "summary": "Responsive UI guidance and tooling for Material Design and AngularJS Material.",
            "date_modified": "2020-02-03T00:00:00.000Z",
            "tags": [
                "angularjs-material",
                "angularjs"
            ]
        }
    ]
}