Skip to content

Best Practices

Avoid performance issues

  1. Unsubscribe watch Observables in ngOnDestroy

    @Component({...}) export class AppComponent implements OnInit, OnDestroy { private subs: Subscription = new Subscription(); ngOnInit () { const docSub = this.changedDocumentService .watch(this.fieldName, this.document.documentId) .subscribe(fieldValue => { .... }); this.subs.add(docSub); } ngOnDestroy() { this.subs.unsubscribe(); } }

  2. Use trackBy for ngFor in template file

    <mat-option *ngFor="let option of itemList; trackBy: trackByFn" [value]="option"> {{option}} </mat-option> Define function for trackBy in component ts file: trackByFn(index, item) { return item; //Or return item.name; //Or return index;... }

  3. Cache resources if they are called very often especially in ngFor block

    For example in note-comment, the avatar and time string is calculated every keypress event in the text control. We need to store them in avatarData and dateDate component property then we update them once the input string in the text control’s done.

  4. Convert component using OnPush change detection

    This will be included in the change detection section.

  5. Avoid using keypress/keyup/keydown events for heavy tasks. If possible, use blur instead.

Applying the base class

  1. Do not want the ngOnInit in the base class to take place: Some components have the different initialization behavior so we could override ngOnInit and manually call below functions:
    • this.componentSetupService.setupStandardProperties(component): to init readOnly, elementName, registeredControlName.
    • Call this.subs.add(subscription): insteads of setting up a new subscription and manually unsubscribe it. This is to set up the subscription to the subscription list and it will be automatically unsubscribed in the ngOnDestroy.
    • Supported methods:
      • Call this.dispatchChanged(isInitValue?): to set the value to store
      • Call this.dispatchChanged(isInitValue?): to set the value to store
      • Call this.valueChanged(value): to dispatch the field value change action to store.

Errors? Component not showing? Let’s debug.

Component not showing up: Component failed to register as a custom element Check if the component is registered as a custom element. After you load the template that uses the component, go to the core application’s browser’s console and execute:

customElements.get('sc-chips')

It should return a reference to the custom element. If it’s undefined, then we need to check the following: - Is ScChipsModule imported in the project's app.module.ts? - Do you have a component document for the component? If so, do the names match? - Are the entries in the component document’s vendorLibrariesRel pointing to the correct directory/path? - Check if the component module (ScChipsModule) constructor has calls to convertToCustomElement() in it. It’s the main function that registers the component as a custom element. Refer to step 6 in the previous section on Creating a new component project

Component not showing up: BrowserModule isn’t added to the app.module If you’re importing the component into another project, where the BrowserModule was removed or isn’t imported yet, the component may not show up without logging any errors or warnings. Either import BrowserModule into your component module, like in the ScChipsModule, or in the project’s app.module.ts. The preferred location is at app.module.ts.

Errors: Cannot read property of ... This could be caused by the scripts.js file not getting included in the component document’s vendorLibsRel. The order of the files is also important and scripts.js must not come after main.js since it is usually dependent on scripts.js.

component-error