@WidgetComponent

nm-edit-attributes

File

src/app/shared/widgets/edit-attributes/edit-attributes.component.ts

Implements

OnDestroy

Metadata

providers EditAttributeService
selector nm-edit-attributes
styleUrls edit-attributes.component.scss
templateUrl ./edit-attributes.component.html

Index

Widget inputs
Widget outputs
Properties
Methods

Constructor

constructor(_widgetframeService: WidgetframeService, _editAttributeService: EditAttributeService, _halService: HalService, _notificationService: CustomNotificationService, validationService: ValidationService, translateService: TranslateService)
Parameters :
Name Type Optional
_widgetframeService WidgetframeService no
_editAttributeService EditAttributeService no
_halService HalService no
_notificationService CustomNotificationService no
validationService ValidationService no
translateService TranslateService no

Methods

Private attributeChanged
attributeChanged(attribute: Attribute)
Parameters :
Name Type Optional
attribute Attribute no
Returns : void
Protected configureWidget
configureWidget(configuration: WidgetConfig)
Decorators : WidgetConfigure
Parameters :
Name Type Optional
configuration WidgetConfig<EditAttributesConfiguration> no
Returns : void
emitLookupLoaded
emitLookupLoaded(attribute: )
Parameters :
Name Optional
attribute no
Returns : boolean
markSendUnchanged
markSendUnchanged()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
onLookupLoaded
onLookupLoaded(data: , attribute: )
Parameters :
Name Optional
data no
attribute no
Returns : void
resetWidget
resetWidget()
Returns : any
setBoxWidth
setBoxWidth(index: )
Parameters :
Name Optional
index no
Returns : string
trackByFn
trackByFn(index: , item: )
Parameters :
Name Optional
index no
item no
Returns : any
Public trackByIdentifier
trackByIdentifier(idx: , attribute: )
Parameters :
Name Optional
idx no
attribute no
Returns : any
Private validateAttributes
validateAttributes()
Returns : void

Properties

Public _editAttributeService
_editAttributeService: EditAttributeService
Type : EditAttributeService
Private _emitLookupLoaded
_emitLookupLoaded:
Default value : false
Public _halService
_halService: HalService
Type : HalService
Public _id
_id: string
Type : string
Decorators : WidgetId
Public _notificationService
_notificationService: CustomNotificationService
Type : CustomNotificationService
Public _widgetframeService
_widgetframeService: WidgetframeService
Type : WidgetframeService
Public action
action:
Default value : new Subject<any>()
Decorators : WidgetOutput

Emits action.

Public addFields
addFields:
Default value : new Subject<Attribute[]>()
Decorators : WidgetInput

Takes a list of attributes as inputs and adds them to the list

Public additionalDescriptionTooltipIcon
additionalDescriptionTooltipIcon: string
Type : string
attributeRows
attributeRows: QueryList<EditAttributeComponent>
Type : QueryList<EditAttributeComponent>
Decorators : ViewChildren
Public attributes
attributes: Attribute[]
Type : Attribute[]
Public attributesInput
attributesInput:
Default value : new Subject<any>()
Decorators : WidgetInput

List of attributes to be displayed. it's another alternatives for the uri.

Public boxWidth
boxWidth: string
Type : string
Public changedAttributes
changedAttributes:
Default value : <any>{}
Public changedAttributesOutput
changedAttributesOutput:
Default value : new Subject<any>()
Decorators : WidgetOutput

Emits changed attributes.

Public cols
cols: any[]
Type : any[]
Public configuration
configuration: WidgetConfig<EditAttributesConfiguration>
Type : WidgetConfig<EditAttributesConfiguration>
Decorators : WidgetConfiguration
Public copyContentButton
copyContentButton: boolean
Type : boolean
Default value : false
Public displayValueAssets
displayValueAssets: boolean
Type : boolean
Default value : true
Public editLayout
editLayout: string
Type : string
Default value : "list"
Private emitLookupLoadedAttributes
emitLookupLoadedAttributes: any[]
Type : any[]
Public inline
inline: boolean
Type : boolean
Default value : false
Public inputLink
inputLink: string
Type : string
Public lastChangedAttributeOutput
lastChangedAttributeOutput:
Default value : new Subject<any>()
Decorators : WidgetOutput

Emits last changed attribute.

Public lookupLoadedOutput
lookupLoadedOutput:
Default value : new Subject<any>()
Decorators : WidgetOutput

Emits when lookup field is loaded.

Public productLevel
productLevel: string
Type : string
Default value : ""
Public productNo
productNo:
Public productNoForEdit
productNoForEdit:
Default value : new Subject<any>()
Decorators : WidgetInput

Product No. to be updated after changes done on attributes.

Public reload
reload:
Default value : new Subject<any>()
Decorators : WidgetInput

Reload channel.

Public removeFields
removeFields:
Default value : new Subject<string[]>()
Decorators : WidgetInput

Takes a list of strings as input and will remove the attributes with that identifier if found

Public resetWidgets
resetWidgets:
Default value : new Subject<any>()
Decorators : WidgetInput

Reset widget data.

Public selectedDataLocale
selectedDataLocale:
Default value : new ReplaySubject<any>(1)
Decorators : WidgetInput

Selected data locale channel triggeres when locale changed.

Public selectedDataLocaleString
selectedDataLocaleString:
Public selectedProductLevel
selectedProductLevel:
Default value : new Subject<any>()
Decorators : WidgetInput

Selected product level. it's displayed as a header for widget in case we aren't in inline mode.

Public showDescriptionTooltips
showDescriptionTooltips: boolean
Type : boolean
Public showValidation
showValidation: boolean
Type : boolean
Public sub
sub:
Public targets
targets:
Default value : new ReplaySubject<any>(1)
Decorators : WidgetInput
Public targetsInput
targetsInput: []
Type : []
Default value : []
Public unsubscribe
unsubscribe:
Default value : NgUnsubscribe.create()
Public uri
uri:
Default value : new Subject<any>()
Decorators : WidgetInput

Uri to load attributes.

Public valid
valid:
Default value : new Subject<boolean>()
Decorators : WidgetOutput
Public value
value:
Default value : new Subject<Attribute[]>()
Decorators : WidgetInput

This will search for attributes with the existing identifier and replace the value with the one from the input. This will allow to keep the order and only change the value. If you want to modifiy the value of meta-attribute use parent@child as identifier

Public withBorder
withBorder: boolean
Type : boolean
Default value : true
import {
  combineLatest as observableCombineLatest,
  Subject,
  ReplaySubject,
} from "rxjs";

import {
  map,
  mergeMap,
  takeUntil,
  onErrorResumeNext,
  distinctUntilChanged,
  filter,
} from "rxjs/operators";
import { Component, OnDestroy, QueryList, ViewChildren } from "@angular/core";
import { WidgetframeService } from "../widgetframe/widgetframe.service";
import { getOrDefault, WidgetConfig } from "../widget.configuration";
import {
  WidgetComponent,
  WidgetConfiguration,
  WidgetConfigure,
  WidgetId,
  WidgetInput,
  WidgetOutput,
} from "../widget.metadata";
import { NgUnsubscribe } from "../../ng-unsubscribe";

import * as uriTemplates_ from "uri-templates";
import { Attribute } from "../../components/edit-attribute/attribute";
import { EditAttributeService } from "../../components/edit-attribute/edit-attribute.service";

import { HalService } from "../../components/hal/index";
import { CustomNotificationService } from "../../components/notification/customnotification.service";
import { TranslateService } from "@ngx-translate/core";
import { flatCopy } from "../../components/util/util.service";
import { BaseConfiguration } from "../widgetframe/widgetframe.component";
import { ValidationService } from "../../components/validation/validation.service";
import { EditAttributeComponent } from "../../components/edit-attribute";

const uriTemplates = uriTemplates_;
export interface EditAttributesConfiguration extends BaseConfiguration {
  /**
   * Enables/Disables inline mode. @default(false)
   */
  inline?: boolean;

  /**
   * Enables/Disables image (asset) for lookup options. @default(true)
   */
  "display-value-assets"?: boolean;

  /**
   * Emits when lookup loaded. @default(false)
   */
  emitLookupLoaded?: boolean;

  /**
   * Shows/Hides description tooltips on attribute. @default(false)
   * attribute required object key 'descriptionTooltip' and content type of string
   */
  showDescriptionTooltips?: boolean;

  /**
   * Changes additional description tooltip icons. @default(info)
   */
  additionalDescriptionTooltipIcon?: string;

  /**
   * List of lookup attributes identifiers to be compared when the lookup attribute is loaded .
   */
  emitLookupLoadedAttributes?: any[];

  /**
   * Shows/Hides copy content button. It is used to copy field data.
   * To show this button : value should be true and attribute isn't ('BOOLEAN' ,'META' ,'COMPOSITION_AMOUNT' ,'COMPOSITION_PERCENT').
   *  @default(false)
   */
  copyContentButton?: boolean;

  /**
   * List of attribute identifiers that need to be marked as unchanged.
   */
  "send-unchanged"?: string[];

  /**
   * Edit layout. its possible values are : ['list' , 'textarea']. @default('list')
   */
  "edit-layout"?: string;

  /**
   * Action name to subscribe on.
   */
  "action-name"?: string;

  /**
   * Context. Used by content-management-app to spasifay which context is executed.
   * Its possible values :['' , 'content'] @default('')
   */
  context?: string;

  /**
   * Enables/Disables filter dropdown for attribute.
   */
  filter?: boolean;

  /**
   * Enables/Disables displaying the validation error indicator, if the value is not valid
   */
  "show-validation"?: boolean;
}

@WidgetComponent("nm-edit-attributes")
@Component({
  selector: "nm-edit-attributes",
  templateUrl: "./edit-attributes.component.html",
  styleUrls: ["./edit-attributes.component.scss"],
  providers: [EditAttributeService],
})
export class EditAttributesWidgetComponent implements OnDestroy {
  public cols: any[];
  public attributes: Attribute[];
  public changedAttributes = <any>{};

  public inputLink: string;

  @ViewChildren(EditAttributeComponent)
  attributeRows: QueryList<EditAttributeComponent>;

  @WidgetConfiguration()
  public configuration: WidgetConfig<EditAttributesConfiguration>;

  /**
   * Product No. to be updated after changes done on attributes.
   */
  @WidgetInput()
  public productNoForEdit = new Subject<any>();

  /**
   * Reload channel.
   */
  @WidgetInput()
  public reload = new Subject<any>();

  /**
   * Selected data locale channel triggeres when locale changed.
   */
  @WidgetInput()
  public selectedDataLocale = new ReplaySubject<any>(1);

  /**
   * Emits changed attributes.
   */
  @WidgetOutput("changedAttributesOutput")
  public changedAttributesOutput = new Subject<any>();

  /**
   * Emits last changed attribute.
   */
  @WidgetOutput("lastChangedAttributeOutput")
  public lastChangedAttributeOutput = new Subject<any>();

  /**
   * Emits when lookup field is loaded.
   */
  @WidgetOutput("lookupLoadedOutput")
  public lookupLoadedOutput = new Subject<any>();

  /**
   * Emits action.
   */
  @WidgetOutput("action")
  public action = new Subject<any>();

  @WidgetOutput("valid")
  public valid = new Subject<boolean>();

  @WidgetInput()
  public targets = new ReplaySubject<any>(1);

  /**
   * Selected product level. it's displayed as a header for widget in case we aren't in inline mode.
   */
  @WidgetInput()
  public selectedProductLevel = new Subject<any>();

  /**
   * Reset widget data.
   */
  @WidgetInput()
  public resetWidgets = new Subject<any>();

  /**
   * Uri to load attributes.
   */
  @WidgetInput()
  public uri = new Subject<any>();

  /**
   * List of attributes to be displayed. it's another alternatives for the uri.
   */
  @WidgetInput()
  public attributesInput = new Subject<any>();

  @WidgetId()
  public _id: string;

  /**
   * Takes a list of strings as input and will remove the attributes with that identifier if found
   */
  @WidgetInput()
  public removeFields = new Subject<string[]>();

  /**
   * Takes a list of attributes as inputs and adds them to the list
   */
  @WidgetInput()
  public addFields = new Subject<Attribute[]>();

  /**
   * This will search for attributes with the existing identifier and replace the value with the one from the input.
   * This will allow to keep the order and only change the value.
   * If you want to modifiy the value of meta-attribute use parent@child as identifier
   */
  @WidgetInput()
  public value = new Subject<Attribute[]>();

  public unsubscribe = NgUnsubscribe.create();
  public sub;
  public editLayout: string = "list";
  public boxWidth: string;
  public productNo;
  public selectedDataLocaleString;
  public productLevel: string = "";
  public targetsInput = [];
  public inline: boolean = false;
  public withBorder: boolean = true;
  public copyContentButton: boolean = false;
  public displayValueAssets: boolean = true;
  private _emitLookupLoaded = false;
  private emitLookupLoadedAttributes: any[];
  public showDescriptionTooltips: boolean;
  public additionalDescriptionTooltipIcon: string;
  public showValidation: boolean;

  constructor(
    public _widgetframeService: WidgetframeService,
    public _editAttributeService: EditAttributeService,
    public _halService: HalService,
    public _notificationService: CustomNotificationService,
    private validationService: ValidationService,
    private translateService: TranslateService
  ) {
    this.cols = [
      { field: "description", header: "tab.head.att.name" },
      { field: "value", header: "" },
    ];
  }

  @WidgetConfigure()
  protected configureWidget(
    configuration: WidgetConfig<EditAttributesConfiguration>
  ) {
    this.inline =
      this.configuration.configuration["inline"] !== undefined
        ? this.configuration.configuration["inline"]
        : false;

    this.displayValueAssets =
      this.configuration.configuration["display-value-assets"] !== undefined
        ? this.configuration.configuration["display-value-assets"]
        : true;
    this._emitLookupLoaded = getOrDefault(
      this.configuration.configuration["emitLookupLoaded"],
      false
    );
    this.showDescriptionTooltips = getOrDefault(
      this.configuration.configuration.showDescriptionTooltips,
      false
    );
    this.additionalDescriptionTooltipIcon = getOrDefault(
      this.configuration.configuration.additionalDescriptionTooltipIcon,
      "info_outline"
    );

    this.showValidation = getOrDefault(
      this.configuration.configuration["show-validation"],
      false
    );

    this.withBorder = getOrDefault(
      this.configuration.configuration.withBorder,
      true
    );

    this.emitLookupLoadedAttributes =
      this.configuration.configuration["emitLookupLoadedAttributes"];
    this.copyContentButton = getOrDefault(
      this.configuration.configuration["copyContentButton"],
      false
    );
    this.changedAttributes.values = [];
    this.changedAttributes.targets = [];
    // let href = configuration._links["attributes"]["href"];
    const editLayout = configuration.configuration["edit-layout"];

    if (editLayout) {
      this.editLayout = editLayout;
    }
    // let template = uriTemplates(href);
    this.productNoForEdit
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => (this.productNo = data));

    this.selectedDataLocale
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => {
        this.changedAttributesOutput.next(null);
        this.selectedDataLocaleString = data;
      });

    this.selectedProductLevel
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((productLevel) => {
        this.productLevel = productLevel;
      });

    this.resetWidgets.pipe(takeUntil(this.unsubscribe)).subscribe((data) => {
      this.attributes = [];
      this.changedAttributes.values = [];
      this.changedAttributes.targets = [];
      this.changedAttributesOutput.next(null);
      this.uri.next(" ");
    });

    this.targets.pipe(takeUntil(this.unsubscribe)).subscribe((targetsInput) => {
      this.targetsInput = targetsInput.slice(0);
    });

    this._editAttributeService
      .getAttributeChangedEvent()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((attribute) => {
        this.attributeChanged(attribute);
        //}
      });

    this._halService
      .getActionEvents()
      .pipe(
        filter(
          (event) => event.name === configuration.configuration["action-name"]
        ),
        map((event) => (<any>event).response),
        takeUntil(this.unsubscribe)
      )
      .subscribe((resp) => {
        this.changedAttributes = <any>{};
        this.changedAttributes.values = [];
        this.changedAttributes.targets = [];
        this.changedAttributesOutput.next(null);
        if (resp.message !== undefined) {
          if (resp.level === "ERROR") {
          }
          if (resp.level === "SUCSESS") {
            this.changedAttributes = <any>{};
            this.changedAttributes.values = [];
            this.changedAttributesOutput.next(null);
          }
        }
      });

    let source = observableCombineLatest(
      this.reload.asObservable().pipe(distinctUntilChanged()),
      this.selectedDataLocale.asObservable().pipe(distinctUntilChanged()),
      this.uri.asObservable(),

      function (reloadEvent, selectedDataLocale, uri) {
        let template = uriTemplates(uri);
        let uriParams = {};
        uriParams["data-locale"] = selectedDataLocale;
        uriParams["context"] = configuration.configuration["context"];
        uriParams["locale"] = reloadEvent;
        return template.fill(uriParams);
      }
    ).pipe(
      takeUntil(this.unsubscribe),
      mergeMap((href) =>
        this._widgetframeService
          .getData(href)
          .pipe(onErrorResumeNext(this.resetWidget()))
      ),
      map((res) => <any>res)
    );

    source.subscribe(
      (data) => {
        this.attributes = data["values"];
        this.validateAttributes();
        if (data.hasOwnProperty("_actions")) {
          let template = uriTemplates(data["_actions"].save.href);
          let uriParams = {};
          uriParams["productNo"] = this.productNo;
          data["_actions"].save.href = template.fill(uriParams);

          this.action.next(data["_actions"].save);
        }

        if (this.configuration.configuration["send-unchanged"]) {
          this.markSendUnchanged();
        }
      },
      (error) => {
        console.log(error);
        this.attributes = null;
        this.valid.next(true);
      }
    );

    // alternative to uri input
    this.attributesInput
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((attribute) => {
        this.attributes = attribute;
        this.validateAttributes();
        if (this.configuration.configuration["send-unchanged"]) {
          this.markSendUnchanged();
        }
      });

    this.removeFields.pipe(takeUntil(this.unsubscribe)).subscribe((fields) => {
      this.attributes = this.attributes.filter(
        (entry) => fields.indexOf(entry.identifier) === -1
      );
      this.validateAttributes();
    });

    this.addFields.pipe(takeUntil(this.unsubscribe)).subscribe((fields) => {
      this.attributes.push(...fields);
      this.validateAttributes();
    });

    this.value.pipe(takeUntil(this.unsubscribe)).subscribe((fields) => {
      if (!Array.isArray(fields)) {
        console.error("Input for value must be an array ", fields);
        return;
      }
      fields.forEach((field) => {
        //We are supposed to update a meta attribute
        if (field.identifier.indexOf("@") !== -1) {
          const parentName = field.identifier.substring(
            0,
            field.identifier.indexOf("@")
          );
          const childName = field.identifier.substring(
            field.identifier.indexOf("@") + 1
          );

          const parentIndex = this.attributes.findIndex(
            (entry) => entry.identifier === parentName
          );

          if (parentIndex === -1) {
            console.warn(
              `Cant find attribute with identifier ${parentName}`,
              this.attributes
            );
            return;
          }
          const parentAttribute = this.attributes[parentIndex];
          if (
            !parentAttribute._embedded ||
            !parentAttribute._embedded.attributes
          ) {
            console.warn(
              `Cant find any children in attribute`,
              parentAttribute
            );
            return;
          }
          const child = parentAttribute._embedded.attributes.find(
            (entry) => entry.identifier === childName
          );
          child.source = field.source;
          this.attributes[parentIndex] = flatCopy(parentAttribute);
          this.attributeChanged(this.attributes[parentIndex]);

          return;
        }
        const attributeIndex = this.attributes.findIndex(
          (entry) => entry.identifier === field.identifier
        );
        if (attributeIndex === -1) {
          console.warn(
            `Cant find attribute ${field.identifier}`,
            this.attributes
          );
          return;
        }

        this.attributes[attributeIndex].source = field.source;
        //Create a flatcopy of the attribute to trigger change detection of edit-attribute
        this.attributes[attributeIndex] = flatCopy(
          this.attributes[attributeIndex]
        );
        this.attributeChanged(this.attributes[attributeIndex]);
      });
    });

    this.changedAttributesOutput
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.validateAttributes();
      });
  }

  private attributeChanged(attribute: Attribute) {
    let valid = true;

    if (attribute.type === "COMPOSITION_PERCENT") {
      let total: number = 0;
      for (var source of attribute.source) {
        total += parseInt(source.amount);
      }
      if (total != 100) {
        valid = false;
        this._notificationService.error(
          this.translateService.instant("ERROR"),
          this.translateService.instant("composition.percent.error.message")
        );
      }
    }

    //if (valid) {
    let duplicate = this.changedAttributes.values.filter(
      (item) => item.identifier == attribute.identifier
    );
    if (duplicate.length === 1) {
      if (attribute.type === "META") {
        attribute._embedded.attributes.forEach((metaAttrDef, index) => {
          let duplicateMetaAttrDef = duplicate[0].attributes[index];
          if (duplicateMetaAttrDef.identifier !== metaAttrDef.identifier) {
            duplicateMetaAttrDef = duplicate[0].attributes.find(
              (dupMetaAttrDef) =>
                dupMetaAttrDef.identifier === metaAttrDef.identifier
            );
          }
          duplicateMetaAttrDef.source = metaAttrDef.source;
        });
      } else {
        duplicate[0].source = attribute.source;
      }
    } else {
      this.changedAttributes.values.push(attribute);
    }
    if (this.targetsInput.length > 0) {
      this.changedAttributes.targets = this.targetsInput;
    } else {
      this.changedAttributes.targets = [];
      this.changedAttributes.targets.push({
        level: "product",
        identifier: this.productNo,
      });
    }
    this.changedAttributes["locale"] = this.selectedDataLocaleString;
    this.lastChangedAttributeOutput.next(attribute);
    this.changedAttributesOutput.next(this.changedAttributes);
  }

  resetWidget() {
    return null;
  }

  ngOnDestroy() {
    this.unsubscribe.destroy();
  }

  setBoxWidth(index) {
    return 98 / index + "%";
  }

  trackByFn(index, item) {
    return item.identifiers; // or item.id
  }

  markSendUnchanged() {
    const sendUnchanged = this.configuration.configuration["send-unchanged"];
    let attributesToSendUnchanged = this.attributes.filter(function (
      attribute
    ) {
      return sendUnchanged.indexOf(attribute.identifier) >= 0;
    });
    for (const attribute of attributesToSendUnchanged) {
      attribute.sendUnchanged = true;
    }
  }

  emitLookupLoaded(attribute) {
    if (!this._emitLookupLoaded) {
      return false;
    }

    if (!this.emitLookupLoadedAttributes) {
      return true;
    }
    return (
      this.emitLookupLoadedAttributes.findIndex(
        (v) => v === attribute.identifier
      ) !== -1
    );
  }

  onLookupLoaded(data, attribute) {
    this.lookupLoadedOutput.next({ data, attribute });
  }

  private validateAttributes() {
    if (!this.attributes) {
      this.valid.next(true);
      return;
    }

    this.validationService
      .validateBulkEdit(this.attributes, null)
      .subscribe((errors) => {
        this.valid.next(errors.size == 0);

        this.attributeRows.forEach((row) => {
          row._changeDetectorRef.markForCheck();
        });
      });
  }

  public trackByIdentifier(idx, attribute) {
    return attribute.identifier;
  }
}
<nm-widgetframe
  *ngIf="!inline"
  [header]="configuration.configuration['header']"
  [withBorder]="withBorder"
  [configuration]="configuration"
  widgetId="{{ _id }}"
>
  <div slot="title" class="nm-widgetframe__title">
    {{ configuration.configuration["title"] | translate }}
    <span *ngIf="productLevel.length > 0"
      >&nbsp;({{ productLevel | translate }})</span
    >
    <nm-help-icon
      *ngIf="configuration.configuration['infoText']"
      [info-text]="configuration.configuration['infoText'] | translate"
      [info-title]="configuration.configuration['title'] | translate"
      [info-placement]="'left'"
      [wiki-link]="configuration.configuration['wikiLink']"
    ></nm-help-icon>
  </div>
  <div
    slot="content"
    class="nm-widgetframe__content"
    *ngIf="attributes !== null"
  >
    <div class="nm-attribute-list" *ngIf="editLayout === 'list'">
      <div *ngFor="let attribute of attributes; trackBy: trackByIdentifier">
        <div class="nm-attribute-list-elements">
          <div class="nm-attribute-list-description">
            <nm-ellipsis [content]="attribute.description"></nm-ellipsis>
          </div>
          <div
            class="nm-attribute-list-filter"
            *ngIf="configuration.configuration['filter']"
          >
            <nm-edit-attribute-filter
              [attribute]="attribute"
              [editAttributeService]="_editAttributeService"
            ></nm-edit-attribute-filter>
          </div>
          <div class="nm-attribute-list-value">
            <nm-edit-attribute
              [attribute]="attribute"
              [emitLookupLoaded]="emitLookupLoaded(attribute)"
              (lookupLoaded)="onLookupLoaded($event, attribute)"
              [copyContentButton]="copyContentButton"
              [editLayout]="editLayout"
              [editAttributeService]="_editAttributeService"
              [displayValueAssets]="displayValueAssets"
              [additionalDescriptionTooltipIcon]="
                additionalDescriptionTooltipIcon
              "
              [showDescriptionTooltips]="showDescriptionTooltips"
              [showValidation]="showValidation"
            ></nm-edit-attribute>
          </div>
        </div>
      </div>
    </div>

    <div
      class="nm-attribute-list textarea-layout"
      *ngIf="editLayout === 'textarea'"
    >
      <div *ngFor="let attribute of attributes; trackBy: trackByIdentifier">
        <nm-edit-attribute
          [attribute]="attribute"
          [floatingLabel]="attribute.description"
          [emitLookupLoaded]="emitLookupLoaded(attribute)"
          (lookupLoaded)="onLookupLoaded($event, attribute)"
          [editAttributeService]="_editAttributeService"
          [editLayout]="editLayout"
          [boxWidth]="boxWidth"
          [showValidation]="showValidation"
        ></nm-edit-attribute>
      </div>
    </div>
  </div>
</nm-widgetframe>

<div *ngIf="inline">
  <div slot="title" class="nm-widgetframe__title">
    {{ configuration.configuration["title"] | translate }}
  </div>
  <div
    slot="content"
    class="nm-widgetframe__content"
    *ngIf="attributes !== null"
  >
    <div class="nm-attribute-list" *ngIf="editLayout === 'list'">
      <div *ngFor="let attribute of attributes; trackBy: trackByIdentifier">
        <div class="nm-attribute-list-elements">
          <div class="nm-attribute-list-description">
            <nm-ellipsis [content]="attribute.description"></nm-ellipsis>
          </div>
          <div
            class="nm-attribute-list-filter"
            *ngIf="configuration.configuration['filter']"
          >
            <nm-edit-attribute-filter
              [attribute]="attribute"
              [editAttributeService]="_editAttributeService"
            ></nm-edit-attribute-filter>
          </div>
          <div class="nm-attribute-list-value">
            <nm-edit-attribute
              [attribute]="attribute"
              [emitLookupLoaded]="emitLookupLoaded(attribute)"
              (lookupLoaded)="onLookupLoaded($event, attribute)"
              [copyContentButton]="false"
              [editLayout]="editLayout"
              [editAttributeService]="_editAttributeService"
              [displayValueAssets]="displayValueAssets"
              [additionalDescriptionTooltipIcon]="
                additionalDescriptionTooltipIcon
              "
              [showDescriptionTooltips]="showDescriptionTooltips"
              [showValidation]="showValidation"
            ></nm-edit-attribute>
          </div>
        </div>
      </div>
    </div>

    <div
      class="nm-attribute-list textarea-layout"
      *ngIf="editLayout === 'textarea'"
    >
      <div *ngFor="let attribute of attributes; trackBy: trackByIdentifier">
        <nm-edit-attribute
          [attribute]="attribute"
          [emitLookupLoaded]="emitLookupLoaded(attribute)"
          (lookupLoaded)="onLookupLoaded($event, attribute)"
          [editAttributeService]="_editAttributeService"
          [editLayout]="editLayout"
          [boxWidth]="boxWidth"
          [showValidation]="showValidation"
        ></nm-edit-attribute>
      </div>
    </div>
  </div>
</div>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""