File

feature-libs/organization/administration/components/shared/form/form.component.ts

Description

Reusable component for creating and editing organization items. The component does not know anything about form specific.

Implements

OnInit OnDestroy

Metadata

changeDetection ChangeDetectionStrategy.OnPush
host {
}
selector cx-org-form
templateUrl ./form.component.html

Index

Properties
Methods
Inputs

Constructor

constructor(itemService: ItemService<T>, messageService: MessageService)
Parameters :
Name Type Optional
itemService ItemService<T> No
messageService MessageService No

Inputs

animateBack
Type : boolean
Default value : true
i18nRoot
Type : string

i18n root for all localizations. The i18n root key is suffixed with either .edit or .create, depending on the usage of the component.

subtitle
Type : string

Methods

back
back(event: MouseEvent, card: CardComponent)
Parameters :
Name Type Optional
event MouseEvent No
card CardComponent<any> No
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
Protected notify
notify(item: T, action: string)
Parameters :
Name Type Optional
item T No
action string No
Returns : void
save
save(form: FormGroup)
Parameters :
Name Type Optional
form FormGroup No
Returns : void
Protected setI18nRoot
setI18nRoot(item: T)
Parameters :
Name Type Optional
item T No
Returns : void

Properties

animateBack
Default value : true
Decorators :
@Input()
disabled$
Default value : this.form$.pipe( switchMap((form) => form.statusChanges), map((status) => status === DISABLED_STATUS) )

To handle the case of receiving a negative response during creation an item

form$
Type : Observable<FormGroup>
Default value : this.itemService.current$.pipe( map((item) => { this.setI18nRoot(item); if (!item) { // we trick the form builder... item = {} as any; } return this.itemService.getForm(item); }) )
i18n
Type : string

i18n key for the localizations.

i18nRoot
Type : string
Decorators :
@Input()

i18n root for all localizations. The i18n root key is suffixed with either .edit or .create, depending on the usage of the component.

Optional subtitle
Type : string
Decorators :
@Input()
import {
  ChangeDetectionStrategy,
  Component,
  Input,
  OnDestroy,
  OnInit,
} from '@angular/core';
import { FormGroup } from '@angular/forms';
import { LoadStatus } from '@spartacus/organization/administration/core';
import { Observable } from 'rxjs';
import { first, map, switchMap, take } from 'rxjs/operators';
import { CardComponent } from '../card/card.component';
import { ItemService } from '../item.service';
import { MessageService } from '../message/services/message.service';

const DISABLED_STATUS = 'DISABLED';

/**
 * Reusable component for creating and editing organization items. The component does not
 * know anything about form specific.
 */
@Component({
  selector: 'cx-org-form',
  templateUrl: './form.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: { class: 'content-wrapper' },
})
export class FormComponent<T> implements OnInit, OnDestroy {
  /**
   * i18n root for all localizations. The i18n root key is suffixed with
   * either `.edit` or `.create`, depending on the usage of the component.
   */
  @Input() i18nRoot: string;

  @Input() animateBack = true;
  @Input() subtitle?: string;

  /**
   * i18n key for the localizations.
   */
  i18n: string;

  form$: Observable<FormGroup> = this.itemService.current$.pipe(
    map((item) => {
      this.setI18nRoot(item);

      if (!item) {
        // we trick the form builder...
        item = {} as any;
      }
      return this.itemService.getForm(item);
    })
  );

  /**
   * To handle the case of receiving a negative response during creation an item
   */
  disabled$ = this.form$.pipe(
    switchMap((form) => form.statusChanges),
    map((status) => status === DISABLED_STATUS)
  );

  constructor(
    protected itemService: ItemService<T>,
    protected messageService: MessageService
  ) {}

  save(form: FormGroup): void {
    this.itemService.key$
      .pipe(
        first(),
        switchMap((key) =>
          this.itemService.save(form, key).pipe(
            take(1),
            map((data) => ({
              item: data.item,
              status: data.status,
              action: key ? 'update' : 'create',
            }))
          )
        )
      )
      .subscribe(({ item, action, status }) => {
        if (status === LoadStatus.SUCCESS) {
          this.itemService.launchDetails(item);
          this.notify(item, action);
        }
        form.enable();
      });
  }

  protected notify(item: T, action: string) {
    this.messageService.add({
      message: {
        key: `${this.i18nRoot}.messages.${action}`,
        params: {
          item,
        },
      },
    });
  }

  protected setI18nRoot(item: T): void {
    // concatenate the i18n root with .edit or .create suffix
    this.i18n = this.i18nRoot + (item ? '.edit' : '.create');
  }

  back(event: MouseEvent, card: CardComponent<any>) {
    if (this.animateBack) {
      card.closeView(event);
    }
  }

  ngOnInit() {
    this.itemService.setEditMode(true);
  }

  ngOnDestroy() {
    this.itemService.setEditMode(false);
  }
}
<form *ngIf="form$ | async as form" (submit)="save(form)">
  <cx-org-card
    #card
    [previous]="false"
    [i18nRoot]="i18n"
    cxOrgItemActive
    [subtitle]="subtitle"
    [cxFocus]="{ autofocus: 'input', refreshFocus: form }"
  >
    <button
      actions
      class="button primary"
      [disabled]="form.disabled || (disabled$ | async)"
    >
      {{ 'organization.save' | cxTranslate }}
    </button>
    <button actions class="link" routerLink="../" type="button">
      <!--
        We leverage the soft-close feature from the split view, so that the animation
        has time to kick in before the router outlet is deleted.
       -->
      <span (click)="back($event, card)">{{
        'organization.cancel' | cxTranslate
      }}</span>
    </button>

    <section main class="details">
      <ng-content select="[main]" ngProjectAs="[main]"></ng-content>
    </section>
  </cx-org-card>
</form>
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""