Wednesday, June 17, 2020

Reuse Your Code By Creating Angular Custom Elements

As a developer, you know that reusing code as much as possible is an important premise. This refers to modularization and reusability of your code. HTML5 Web components aim to achieve both things with the creation of custom elements.

One interesting feature about the 6th version of the Angular framework is that it enables developers to create custom elements. Basically, you can create Angular custom elements that are generated from Angular components. The resultant element carries a minified version of the framework.

The way that this is done is with a framework-agnostic approach, and the resultant element can be used in any simple web project without Angular.

The Building Blocks of HTML5 Web Components

Before getting into more details, let's spend a little time getting to know HTML5 web components. Web components is a suite of different technologies allows the developer to create custom elements.

Web components are composed of three parts:

  • Custom elements: a set of JavaScript API that enables to define custom elements and their behavior.
  • Shadow DOM: This refers to the encapsulation of the element code so the styles and scripts defined in our element will be private and won't cause issues with other parts of the app.
  • HTML templates: Using the <template> tag you can write markup that won’t be rendered till is referenced by some Javascript code and then appended to the DOM. This way you can create reusable code.

Let’s focus on the first ones.

What Are Custom Elements?

Elements that are encapsulated, have their own functionality and can be reused in any web app. Version 5 of HTML comes with custom elements that provide a way for developers to define and register their own and fully featured DOM elements. Custom Elements allows web developers to create new custom HTML tags or extend the ones that already exist. The web components API defines a web strategy based on standards to create reusable components just using HTML, CSS, and JavaScript. As a result, you get a more modularized and reusable code and you can reduce the size of your it.

Angular Custom Elements

The Angular component is parsed by the creation API looking for input properties and defines the corresponding attributes for the custom element to be generated. Since HTML does not recognize case distinctions, the API transforms the property names to make them compatible with the custom elements attributes.

For example, the component input @Input() inputName becomes the attribute“input-name” for the custom element.

On the other side, the component outputs are transformed into HTML custom events, using the name of the output as the name of the event.

For example:

@Output() clickEvent = new EventEmitter<string>()

The custom element would generate the event “clickEvent”.
The emitted data will be available in the event’s detail property.

Creating an Example Application

Let’s do an example project to demonstrate how to create a custom element and use it outside an Angular project. For this simple task, I’m going to develop a button component that will register how many times it was clicked, and emit an event every time a new click happens.

The resulting Angular app will output this:

Reuse Your Code By Creating Angular Custom Elements

Add Elements Dependency

To create custom elements with angular you’ll need the @angular/elements package.

ng add @angular/elements

This package exports the method createCustomElement that provides a bridge from Angular's component interface and change detection functionality to the built-in DOM API.

Create a Custom Element

Now let’s create the component that will have the functionality of the custom button.
The component will have all of the source code in one file. The template and the styles together with the typescript definition.

ng g component custom-button --inline-style --inline-template -v Native

ViewEncapsulation.Native property is used to prevent the styles of the component from interfering with other elements. By using this property, the browser’s native implementation of shadow DOM will be used to render the component. A bundle would be generated containing the component class code, the template, and styles in a single file.

Define the Component Properties

For the custom button component we are going to define the following properties:

  • text Input: the text to display inside the button
  • countChanged Output: the function that will handle the event being triggered

custom-button.component.ts

import { Component, OnInit, ViewEncapsulation, Input, Output, EventEmitter } from '@angular/core';

@Component({
selector: 'custom-button',
template: ``,
styles: [`
.btn {
display: inline-block;
font-weight: 400;
text-align: center;
white-space: nowrap;
vertical-align: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border: 1px solid transparent;
padding: .375rem .75rem;
font-size: 1rem;
line-height: 1.5;
border-radius: .25rem;
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
color: #fff;
background-color: #28a745;
border-color: #28a745;
}
.btn:hover {
color: #fff;
background-color: #218838;
border-color: #1e7e34;
cursor: pointer;
}
`],
encapsulation: ViewEncapsulation.Native
})
export class CustomButtonComponent implements OnInit {

@Input() text = 'Custom Button';
@Output() countChanged = new EventEmitter ();
private totalClicks: number = 0;

constructor() { }

ngOnInit() {
}

countClicks() {
this.totalClicks++;
this.countChanged.emit(this.totalClicks);
}

}

Now let's create the code inside the app component to use the custom-button component so we can test that it works ok.

app.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Custom element example app';
count: number = null;

constructor() {}

handleCountChanged($event) {
this.count = $event;
}

}

app.component.html

  
 
 
 
 

Welcome to !

Angular Logo


app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { CustomButtonComponent } from './custom-button/custom-button.component';

@NgModule({
declarations: [
AppComponent,
CustomButtonComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent],
entryComponents: []
})
export class AppModule { }

 

Add the Component to NgModule

Nothing different there that all the components that you have created in the past, but let’s now register the new component in NgModule.

First of all, remove the bootstrap array which has the AppComponent.

Angular will need to compile it so you need to put it on the entryComponent list. And you’ll use the createCustomElement method from the @angular/elements package.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';
import { CustomButtonComponent } from './custom-button/custom-button.component';

@NgModule({
declarations: [
AppComponent,
CustomButtonComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent],
entryComponents: [CustomButtonComponent]
})
export class AppModule {

constructor(private injector: Injector) {
const customButton = createCustomElement(CustomButtonComponent, { injector });
customElements.define('custom-button', customButton);
}

}

Now you can also see the ngDoBootstrap method that is used to tell Angular to use this module for bootstrapping.

Build and Check Output

First of all, let’s create a simple HTML page in order to see the custom element working.

indexTest.html












Then let’s modify our package.json file, particularly the scripts, so you can generate the bundle for the custom element that would be later included in our test page.

package.json

"scripts": {
...
"build": "ng build --prod --output-hashing=none",
"concat": "concat -o output.js ./dist/ExampleApp/runtime.js ./dist/ExampleApp/polyfills.js ./dist/ExampleApp/scripts.js
./dist/ExampleApp/main.js"
...
}

What the --output-hashing=none do is simply to remove the hashes from the names from the generated JavaScript files. Those aren’t needed since you are going to concatenate them to use it only in one file.

The build output would be in the dist folder and you’ll see there 4 files runtime.js, polyfills.js, scripts.js, and main.js. Those are the ones that have all the source code related to our just created custom-button.

In order to use it in your already created indexTest.html page you need to concatenate them so you’ll end up importing just one file (output.js).

For this purpose, you can use the npm package concat.
You can install it with the following command:

npm i concat

Then you only need to run:

npm run build

and

npm run concat

The resulting file called output.js size is only 227,6 kB, nothing bad considering it has Angular included in it.

Finally, you can open your indexTest.html page in your browser in order to see the example with the custom button element working.

Reuse Your Code By Creating Angular Custom Elements

Customization in Angular

As you can see building custom elements with Angular is pretty straight forward. Although at the moment there are some manual things that you need to do, it ends up being a simple task. Also as you can see the size of the output file is quite small, considering that it has Angular dependencies inside of it. Let’s hope that in the future releases this process gets even easier.

New Angular features you didn’t know existed

TL;DR: In this post, you will be introduced to a few new Angular features you might not know about. We will look at the thought process behind them and even some examples on how to get started using them.

Angular

Angular, a JavaScript framework (with almost 44,000 stars on GitHub), is a platform that makes it easy to build applications with the web. Angular combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Angular empowers developers to build applications that live on the web, mobile, or the desktop. It also has the most useful CLI tool for beginners to easily get started.

In this article, you will be introduced to a few Angular features that every Angular developer should know about. Angular is currently in the seventh version, and the next version is expected to be released anytime in May 2019. With this post, you will have a look back at exciting features and also a preview of what is to come in version 8.

Angular Elements

In the sixth version released around this time last year, Angular Elements was released to developers for use. Angular Elements is a new Angular package which you can use to bootstrap Angular components within an existing Angular application by registering them as custom elements. Angular does this by taking your Angular component and compiling it to a web component.

As web components are getting massive acceptance in the JavaScript community, this is a great time to start using them in your Angular projects. Angular elements are reusable as you can use them in other frameworks like React and Vue and also use them in the server-side of your project.

In version 7, the Angular team added support for content projection using web standards for custom HTML element like <slot> in Angular Elements:

@Component({
  selector: 'bla-bla',
  template: `
    <header>
      <slot name="bla-header"></slot>
    </header>
    <slot></slot>`,
  encapsulation: ViewEncapsulation.ShadowDom,
  styles: []
})
export class BlaComponent {
}

With this declared, using slot like this is now possible:

<bla-bla>
  <span slot="bla-header">Angular rocks!</span>
<bla-bla>

Library support

Due to popular demand, the Angular team added schematics support so you can now create and publish new libraries to extend Angular functionality. If you find that you need to solve the same problem in more than one application or you want to share your solution with other developers in a reusable manner, you should be excited about this:

ng generate library <name>

This command will create a library project within your CLI workspace, with options of configuring it for testing and for building. You can learn more about creating libraries with the Angular CLI here.

CLI upgrade: ng add and ng update

In the effort to radically make the CLI tool easier to use and more intuitive, more CLI commands were introduced to Angular CLI in version 6. These commands are very helpful and you should start using them if your Angular version is at version 6 or above.

1. ng add: This CLI command was built to help add new capabilities through packages and features to your project easily with one command. The syntax is:

ng add <package>

It uses your default package manager (yarn or npm) to download new dependencies and also activate the installation scripts to install them so you can use them on the go.

  • Other JavaScript frameworks like Vue have implemented similar CLI add command capabilities inspired by the ng add in the Vue CLI 3.0

2. ng update: This CLI command goes into your package.json file, analyzes it and uses its inbuilt Angular version recommendation system to update the particular package you specify. The syntax looks like this:

ng update <package>

Where the package is the name of your preferred package. The update command does more than update your packages, it also keeps your dependencies in sync and applies needed transforms to your project using yarn or npm.

Data saver updates

In version 7, an efficiency feature was introduced and you now get warnings when your bundle is over 2MB in size when you run the build command. It goes a step further to show error messages when your bundle gets to 5MB in size. You can however personally adjust these error and warnings settings to your own personal bundle size limit by modifying the Angular.json file:

"budgets": [
  {
    "type": "initial",
    "maximumWarning": "2mb",
    "maximumError": "5mb"
  }
]

These budgets settings are similar to them with that can be shown to google chrome users and so get Chrome’s Data Saver features. This is a very great way to keep you both disciplined and accountable to your set bundle size targets.

Angular CDK

Google’s Material.io platform for building web experiences with material design was updated at the time when the sixth version of Angular was released. It now contains a component development kit. The Component Development Kit (CDK) is a set of tools that implement common interaction patterns whilst being un-opinionated about their presentation. It represents an abstraction of the core functionalities found in the Angular Material library, without any styling specific to Material Design. Think of the CDK as a blank state of well-tested functionality upon which you can develop your own bespoke components. Adding the Material setup to your Angular project can be done with a line of command:

ng add @angular/material

The features below were born from the CDK.

Starter components

A couple of out-of-the-box starter components were added to the CDK, as in the sixth Angular version. These components were:

1. Material sidenav: Here we see a starter Angular application which consists of a toolbar and a side navigation. All of the components are fully responsive and are of course built in accordance with material design:
ng generate @angular/material:material-nav  name=my-nav

2. Material dashboard: Here you can generate a starter dashboard template with a command. This dashboard contains dynamic grid list of cards, all design according to material design principles. They are all responsive:

ng generate @angular/material:material-dashboard --name=my-dashboard

3. Material data table: Here you can generate a data table component that is already configured with a data source for both sorting and pagination:

ng generate @angular/material:material-table --name=my-table

You can learn more about the available Angular Material Schematics here.

Virtual scroll

Angular version 7 was released with even more shiny additions to the CDK. The virtual scrolling feature was added to help structure your user interface in such a way that you might not necessarily have to use pagination options anytime you have to display component with a long list of items. The virtual scrolling module achieves exactly that by loading elements unto the DOM and also unloading elements from the DOM by the visible parts of a list as you scroll, this, in turn, provides a great platform for building cooler and faster user experience with large scrollable lists:

import {ChangeDetectionStrategy, Component} from '@angular/core';

/** @title Basic virtual scroll */
@Component({
  selector: 'cdk-virtual-scroll-overview-example',
  styleUrls: ['cdk-virtual-scroll-overview-example.css'],
  templateUrl: 'cdk-virtual-scroll-overview-example.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkVirtualScrollOverviewExample {
  items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
}

TypeScript

.example-viewport {
  height: 200px;
  width: 200px;
  border: 1px solid black;
}

.example-item {
  height: 50px;
}

CSS

You can read more about Virtual Scrolling here.

Drag and drop

Drag and Drop on an example dashboard

Added to the virtual scrolling module is another user interface game-changer called drag and drop. This module brings exciting interactivity in user interface design to life. With the drag and drop, you can have list items get very practically interactive, giving the user the power to drag and drop list items within a single list and even between two lists. It is such a creative feature you should totally check out. The rendering, re-ordering and re-shuffling of list items are all done automatically and dynamically and you can also animate the process:

<div class="example-box" cdkDrag>
  Drag me around
</div>

HTML

import {Component} from '@angular/core';

/**
 * @title Basic Drag&Drop
 */
@Component({
  selector: 'cdk-drag-drop-overview-example',
  templateUrl: 'cdk-drag-drop-overview-example.html',
  styleUrls: ['cdk-drag-drop-overview-example.css'],
})
export class CdkDragDropOverviewExample {}

Typescript

.example-box {
  width: 200px;
  height: 200px;
  border: solid 1px #ccc;
  color: rgba(0, 0, 0, 0.87);
  cursor: move;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  background: #fff;
  border-radius: 4px;
  position: relative;
  z-index: 1;
  transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
              0 2px 2px 0 rgba(0, 0, 0, 0.14),
              0 1px 5px 0 rgba(0, 0, 0, 0.12);
}

.example-box:active {
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
              0 8px 10px 1px rgba(0, 0, 0, 0.14),
              0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

CSS

Personally, common use cases that come to mind are: games and project boards.

Conclusion: Angular 8 is coming!

We have seen the newest and shiniest Angular features out as we wait for the next version. According to the speculative Angular release timeline, the opt-in preview of Angular version 8 will be released in May this year and this is going to be a very symbolic release because the Angular renderer is going to be changed to a new one called Ivy. Ivy promises to bring faster re-build time, improvements with type checking, an easier platform for debugging and most importantly drastically reduced bundle size. Which of these Angular features are you meeting for the first time?

Experience your Angular apps exactly how a user does

Debugging Angular applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Angular state and actions for all of your users in production, try LogRockethttps://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens on your site including network requests, JavaScript errors, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket NgRx plugin logs Angular state and actions to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Angular apps - .


Free hosting web sites and features -2024

  Interesting  summary about hosting and their offers. I still host my web site https://talash.azurewebsites.net with zero cost on Azure as ...