Categories
Angular Answers

How to fix *ngIf and *ngFor on same element causing error with Angular?

Sometimes, we want to fix *ngIf and *ngFor on same element causing error with Angular.

In this article, we’ll look at how to fix *ngIf and *ngFor on same element causing error with Angular.

How to fix *ngIf and *ngFor on same element causing error with Angular?

To fix *ngIf and *ngFor on same element causing error with Angular, we can move *ngIf to the ng-container component.

For instance, we write

<ng-container *ngIf="show">
  <div *ngFor="let thing of stuff">
    {{ log(thing) }}
    <span>{{ thing.name }}</span>
  </div>
</ng-container>

to use *ngIf in the ng-container component to show the div only when show is true.

And then we use *ngFor in the div to render the items in the stuff array.

Conclusion

To fix *ngIf and *ngFor on same element causing error with Angular, we can move *ngIf to the ng-container component.

Categories
Angular Answers

How to use an EventEmitter with Angular?

Sometimes, we want to use an EventEmitter with Angular.

In this article, we’ll look at how to use an EventEmitter with Angular.

How to use an EventEmitter with Angular?

To use an EventEmitter with Angular, we can use it to emit an event from the child component to the parent.

For instance, we write

@Component({
  selector: "child",
  template: ` <button (click)="sendNotification()">Notify my parent!</button> `,
})
class Child {
  @Output() notifyParent: EventEmitter<any> = new EventEmitter();

  sendNotification() {
    this.notifyParent.emit("hello parent");
  }
}

to create the notifyParent EventEmitter object.

Then we call notifyParent.emit in the sendNotification method that’s called when we click the button.

Then in the parent component, we write

@Component({
  selector: "parent",
  template: ` <child (notifyParent)="getNotification($event)"></child> `,
})
class Parent {
  getNotification(evt) {
    // Do something with the notification (evt) sent by the child!
  }
}

to listen for the notifyParent event emitted by the child component.

And we get the argument we call emit with in getNotification.

Conclusion

To use an EventEmitter with Angular, we can use it to emit an event from the child component to the parent.

Categories
Angular Answers

How to apply filters to Angular *ngFor?

Sometimes, we want to apply filters to Angular *ngFor.

In this article, we’ll look at how to apply filters to Angular *ngFor.

How to apply filters to Angular *ngFor?

To apply filters to Angular *ngFor, we can apply a filter with the |.

For instance, we write

this.filterArgs = { title: "bar" };
this.items = [{ title: "foo" }, { title: "bar" }, { title: "baz" }];

in our component code.

Then in the template, we write

<li *ngFor="let item of items | myFilter: filterArgs ">
  ...
</li>

to apply the myFilter filter.

Then we create the myFilter filter by writing

import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "myFilter",
  pure: false,
})
export class MyFilterPipe implements PipeTransform {
  transform(items: any[], filter: Object): any {
    if (!items || !filter) {
      return items;
    }
    return items.filter((item) => item.title.includes(filter.title) );
  }
}

to create the MyFilterPipe class that we name as myFilter.

Then we add the transform method in the class.

We return the filtered results that we get after calling filter.

Now the myFilter filter will render the filtered results in the template.

Conclusion

To apply filters to Angular *ngFor, we can apply a filter with the |.

Categories
Angular Answers

How to share the result of an Angular Http network call in Rxjs 5?

Sometimes, we want to share the result of an Angular Http network call in Rxjs 5.

In this article, we’ll look at how to share the result of an Angular Http network call in Rxjs 5.

How to share the result of an Angular Http network call in Rxjs 5?

To share the result of an Angular Http network call in Rxjs 5, we can create our own service.

For instance, we write

@Injectable()
export class HttpCache {
  constructor(private http: Http) {}

  get(url: string): Observable<any> {
    let cached: any;
    if (cached === sessionStorage.getItem(url)) {
      return Observable.of(JSON.parse(cached));
    } else {
      return this.http.get(url).map((resp) => {
        sessionStorage.setItem(url, resp.text());
        return resp.json();
      });
    }
  }
}

to create the HttpCache service class that has the get method.

In get, we check if we stored the response in session storage.

If it is, then we return an observable that has the cached result.

Otherwise, we call this.http.get to make a GET request to the url.

And we call sessionStorage.setItem to store the response once we have it.

Conclusion

To share the result of an Angular Http network call in Rxjs 5, we can create our own service.

Categories
Angular Answers

How to create dynamic template to compile dynamic component with Angular?

Sometimes, we want to create dynamic template to compile dynamic component with Angular.

In this article, we’ll look at how to create dynamic template to compile dynamic component with Angular.

How to create dynamic template to compile dynamic component with Angular?

To create dynamic template to compile dynamic component with Angular, we can use angular-elements.

To install it, we run

npm i @angular/elements

Then we create a service with

import { Injectable, Injector } from "@angular/core";
import { createCustomElement } from "@angular/elements";
import { IStringAnyMap } from "src/app/core/models";
import { AppUserIconComponent } from "src/app/shared";

const COMPONENTS = {
  "user-icon": AppUserIconComponent,
};

@Injectable({
  providedIn: "root",
})
export class DynamicComponentsService {
  constructor(private injector: Injector) {}

  public register(): void {
    Object.entries(COMPONENTS).forEach(([key, component]: [string, any]) => {
      const CustomElement = createCustomElement(component, {
        injector: this.injector,
      });
      customElements.define(key, CustomElement);
    });
  }

  public create(tagName: string, data: IStringAnyMap = {}): HTMLElement {
    const customEl = document.createElement(tagName);

    Object.entries(data).forEach(([key, value]: [string, any]) => {
      customEl[key] = value;
    });

    return customEl;
  }
}

In it, we have the register method that registers the custom components in components.

And then we add the create method to return the custom elements after creating it.

Next, we register our custom component in the component so we can use it within AppComponent.

@Component({
  selector: "app-root",
  template: "<router-outlet></router-outlet>",
})
export class AppComponent {
  constructor(dynamicComponents: DynamicComponentsService) {
    dynamicComponents.register();
  }
}

We inject the dynamicComponents service and call register to use itin AppComponent.

Then we create the dynamic component with

dynamicComponents.create("user-icon", {
  user: {
    //...
  },
});

And then we can use it in our code with

const html = `<div class="wrapper"><user-icon class="user-icon" user='${JSON.stringify(rec.user)}'></user-icon></div>`;
this.content = this.domSanitizer.bypassSecurityTrustHtml(html);

in our component code and with

<div class="comment-item d-flex" [innerHTML]="content"></div>

in the template of the component.

Conclusion

To create dynamic template to compile dynamic component with Angular, we can use angular-elements.