Tech Blog

Consuming and Creating Reusable Cloud App Components

Angular supports a rich component model which allows us to consume and create reusable libraries. In this post, we’ll first show how to use a component to select entities, and then we’ll walk through how we built the component.

Using the Select Entities Component

We’ve started with a brand new Cloud App. Following the instructions in the component’s readme file, we install the component using the npm command:

$ npm install eca-components --save

And then we add a reference to the component in our app.module.ts file:

import { SelectEntitiesModule } from 'eca-components';

...

@NgModule({
  imports: [
  ...
    SelectEntitiesModule,
  ],

Now we’re ready to use the component in our main component files. In main.component.ts, we add an array to hold the selected entities:

selectedEntities = new Array<Entity>();

Now in our main.component.html page, we add a reference to the select entities element, passing in the variable created in the previous step:

<eca-select-entities
[(selected)]="selectedEntities"
>
</eca-select-entities>

Finally, we add a button and function to clear the list:

@ViewChild(SelectEntitiesComponent) selectEntitiesComponent: SelectEntitiesComponent;

clear() {
  this.selectedEntities = [];
  this.selectEntitiesComponent.clear();
}

Now we have a working multi-select list:

Building a Shared Component

There are good tutorials on the web for creating Angular libraries, including from the official Angular site and from other developers. We followed these tutorials to build our library project. The project has the following structure:

├── ./LICENSE
├── ./README.md
├── ./angular.json
├── ./docs
├── ./ng-package.json
├── ./package-lock.json
├── ./package.json
├── ./src
│   ├── ./src/public-api.ts
│   └── ./src/select-entities
│   ├── ./src/select-entities/components
│   │   ├── ./src/select-entities/components/index.ts
│   │   ├── ./src/select-entities/components/select-entities
│   │   │   ├── ./src/select-entities/components/select-entities/select-entities.component.html
│   │   │   ├── ./src/select-entities/components/select-entities/select-entities.component.scss
│   │   │   └── ./src/select-entities/components/select-entities/select-entities.component.ts
│   │   └── ./src/select-entities/components/select-entity
│   │   ├── ./src/select-entities/components/select-entity/select-entity.component.html
│   │   ├── ./src/select-entities/components/select-entity/select-entity.component.scss
│   │   └── ./src/select-entities/components/select-entity/select-entity.component.ts
│   ├── ./src/select-entities/i18n.ts
│   ├── ./src/select-entities/select-entities.module.ts
│   └── ./src/select-entities/truncate.pipe.ts
├── ./tsconfig.json
├── ./tsconfig.prod.json
└── ./tslink.json

We’ve set up the project to support multiple components. In this case we’ve put the select-entities directory under the src directory. The main configuration files (angular.json, tsconfig.json, tslink.json) are at the root.

After building and testing the component in a regular Cloud App, we moved the code over to the shared library. A few notes are worth pointing out. We reference additional modules in the app.module.json file and include them as peerDependencies  and as devDependencies in the root package.json file:

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MaterialModule } from '@exlibris/exl-cloudapp-angular-lib';
import { TranslateModule } from '@ngx-translate/core';
import { SelectEntitiesComponent } from './select-entities.component';

@NgModule({
  declarations: [ SelectEntitiesComponent ],
  imports: [ 
    MaterialModule, 
    FormsModule, 
    CommonModule,
    TranslateModule
  ],
  exports: [ SelectEntitiesComponent ]
})
export class SelectEntitiesModule { }

In order to support translations, we define our strings in an i18n.ts file. Then in the component’s onInit method, we get a reference to the Cloud App’s translation service, wait for the translations to be loaded, and then call the setTranslation method with merge set to true. This adds our translations to the app’s and allows our component’s strings to be displayed in the user’s language.

ngOnInit() {
  /* Once app translations are loaded, merge with component strings */
  this.translate.getTranslation('en').pipe(take(1)).subscribe(() => {
    Object.entries(i18n).forEach(([k, v]) => this.translate.setTranslation(k, v, true));
  });
}

Once we’ve tested our component, we published it to npm by running npm publish from within the project’s dist folder. Now it’s available for others to use in their projects.

The code for this project can be found in its Github repository. We hope this inspires you to build components for yourself and others to use. If you do, please add an exlcloudapps keyword in the package.json so it can be found on npm.

Leave a Reply