projects/congarevenuecloud/elements/src/lib/output-field/output-field.component.ts
Output field component is used to create a label value paired output that can be displayed as an editable field with an optional popover that shows related information about the field.
import { OutputFieldModule } from '@congarevenuecloud/elements';
@ngModule({
imports: [OutputFieldModule, ...]
})
```typescript
<apt-output-field
[record]="quote"
[field]="CreatedDate"
layout="inline"
[editable]="false"
></apt-output-field>
OnChanges
OnDestroy
changeDetection | ChangeDetectionStrategy.OnPush |
encapsulation | ViewEncapsulation.None |
selector | apt-output-field |
styleUrls | ./output-field.component.scss |
templateUrl | ./output-field.component.html |
Inputs |
Outputs |
constructor(aobjectService: AObjectService, elRef: ElementRef, metadataService: MetadataService, apiService: ApiService)
|
|||||||||||||||
Parameters :
|
dateFormat |
Type : string
|
Date format option passed into the date pipe used by date fields |
displayValue |
Type : string
|
The field property to use to render the value for lookup datatype |
editable |
Type : boolean
|
Default value : true
|
Flag to set this field as editable. |
field |
Type : string
|
Field property of the AObject |
label |
Type : string
|
The field to override the string value of label. |
labelClass |
Type : string
|
String of bootstrap classes for additional styling on output field label |
labelOnly |
Type : boolean
|
Default value : false
|
Flag to display only field label |
layout |
Type : "stacked" | "inline"
|
Default value : 'stacked'
|
The layout for the displayed label and value. By default the layout is 'stacked'. |
lookupOptions |
Type : LookupOptions
|
Object to set primary text field, secondary text field, thumbnail field, conditions, filters etc. |
maxCharacterLength |
Type : number
|
Maximum number of characters to show on string type fields. |
record |
Type : AObject
|
An instance of a AObject |
required |
Type : boolean
|
Flag to set this input as required. |
showQuickView |
Type : boolean
|
Default value : false
|
Flag to show the quick view lookup popover for this field. |
showQuickViewFormat |
Type : "normal" | "popover"
|
Default value : 'popover'
|
The property defines the way lookup information is shown. By default it shows as a popover. |
valueClass |
Type : string
|
String of bootstrap classes for additional styling on output field value |
valueOnly |
Type : boolean
|
Default value : false
|
Flag to show only value for this field without any label. |
onChange |
Type : EventEmitter<any>
|
Event emitter is fired upon field value changes. |
<span [class.align-items-baseline]="layout === 'inline'" [class.inline]="layout === 'inline'"
[class.d-flex]="layout === 'inline'" [class.label-only]="labelOnly" *ngIf="view$ | async as view">
<dt [ngClass]="labelClass" class="mutedLabels" id="label" *ngIf="!valueOnly" [class.mt-1]="layout === 'stacked'">
{{view?.label | translate}}
</dt>
<dd *ngIf="!labelOnly" class="m-0 position-relative" [class.px-1]="layout === 'inline'"
[class.py-0]="layout === 'inline'" [class.empty]="!view.value" [ngClass]="valueClass" [ngSwitch]="true">
<ng-container *ngSwitchCase="view.recordMetadata?.DataType.toLowerCase() === 'datetime'">
<span *ngIf="!dateFormat">{{view.value | dateFormat:'DateTimeFormat' | async}}</span>
<span *ngIf="dateFormat">{{view.value | date:getDateFormat(view.metadata)}}</span>
</ng-container>
<ng-container *ngSwitchCase="view.recordMetadata?.DataType.toLowerCase() === 'date'">
<span *ngIf="!dateFormat">{{view.value | dateFormat:'DateFormat' | async}}</span>
<span *ngIf="dateFormat">{{view.value | date:getDateFormat(view.metadata)}}</span>
</ng-container>
<ng-container *ngSwitchCase="view?.recordMetadata?.DataType.toLowerCase() === 'currency'">
<span *ngIf="view?.value; else noData">{{view?.value | localCurrency | async}}
</span>
</ng-container>
<ng-container *ngSwitchCase="view?.recordMetadata?.DataType.toLowerCase() === 'address'">
<apt-address [value]="view?.value" [readonly]="true"></apt-address>
</ng-container>
<ng-container *ngSwitchCase="view?.recordMetadata?.DataType.toLowerCase() === 'double'">
<span>{{view?.value | number:'1.0-' + view.metadata.Scale}}</span>
</ng-container>
<ng-container *ngSwitchCase="view?.recordMetadata?.DataType.toLowerCase() === 'boolean'">
<span [innerHTML]="view?.value ? ('COMMON.YES' | translate) : ('COMMON.NO' | translate)"></span>
</ng-container>
<ng-container
*ngSwitchCase="view?.recordMetadata?.DataType.toLowerCase() === 'lookup' || view?.recordMetadata?.DataType.toLowerCase() === 'string'">
<ng-container *ngIf="view?.recordMetadata?.DataType.toLowerCase() === 'string' && !showQuickView;">
<ng-container [ngTemplateOutlet]="view?.nonTruncatedValue ? popOverTemplate : simple"
[ngTemplateOutletContext]="{view:view}">
</ng-container>
</ng-container>
<ng-container *ngIf="view?.recordMetadata?.DataType.toLowerCase() === 'lookup' && !showQuickView">
<a href="javascript:void(0)" *ngIf="view?.referenceFieldInstance?.Id && view?.titleIsLink; else noLinkReference"
[routerLink]="['/' + view?.route, view?.referenceFieldInstance?.Id]" [innerHTML]="view?.value"
target="_blank"></a>
</ng-container>
<ng-template #noLinkReference>
<span [innerHTML]="view?.value ? view?.value : ('COMMON.NO_DATA' | translate)"></span>
</ng-template>
<ng-container *ngIf="showQuickView">
<ng-container *ngIf="showQuickViewFormat ==='popover'; else normalQuickViewTemplate">
<a [ngClass]="showQuickView ? 'btn-link popoverLink' : ''" #lookupPop="bs-popover"
[popover]="lookupPopTemplate" (click)="handleLookupPopClick()" triggers="" container="body"
containerClass="lookupPopover" [outsideClick]="true" [placement]="onShown()" [innerHTML]="view?.value"></a>
</ng-container>
</ng-container>
</ng-container>
<ng-container *ngSwitchCase="view?.recordMetadata?.DataType.toLowerCase() === 'textarea'">
<ng-container [ngTemplateOutlet]="view?.nonTruncatedValue ? popOverTemplate : simple">
</ng-container>
</ng-container>
<ng-container *ngSwitchDefault>
<ng-container [ngTemplateOutlet]="simple">
</ng-container>
</ng-container>
<i *ngIf="editable && showQuickViewFormat ==='popover'" #pop="bs-popover"
class="fa fa-pencil d-inline-block edit-icon ml-3" [popover]="editable ? popTemplate : null" container="body"
containerClass="editPopover" [outsideClick]="false" (onShown)="hidePopover()"></i>
</dd>
<ng-template #lookupPopTemplate>
<div class="popHeader position-relative p-3 mb-1"
[ngClass]="expanded ? 'bg-dark text-white' : 'bg-white text-dark'">
<div class="titleSection d-flex justify-content-between align-items-baseline">
<ng-container>
<a class="h5 btn-link" href="javascript:void(0)"
*ngIf="view?.referenceFieldInstance?.Id && view?.titleIsLink; else noLinkPopoverTitle"
[routerLink]="['/' + view?.route, view?.referenceFieldInstance?.Id]" [innerHTML]="view?.value"
target="_blank"></a>
</ng-container>
<ng-template #noLinkPopoverTitle>
<h5 [innerHTML]="view?.value"></h5>
</ng-template>
<button aria-label="Close" [ngClass]="{'text-white': expanded}" class="close pull-right" type="button"
(click)="hidePopover()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="fieldSection container-fluid">
<div class="row">
<div *ngFor="let field of view?.popoverFields | slice:0:6" class="col-6 pl-0 d-flex flex-column">
<ng-container
*ngIf="field?.field == 'ShippingAddress' || field?.field == 'BillingAddress'; else popoverFieldData">
<apt-address [value]="view.referenceFieldInstance"
[type]="field.field == 'ShippingAddress'? 'Shipping' : 'Billing'" [label]="field.label"
[readonly]="true"></apt-address>
</ng-container>
<ng-template #popoverFieldData>
<apt-output-field [record]="view?.referenceFieldInstance" [field]="field.field" [label]="field.label"
layout="stacked" [editable]="false" [showQuickView]="false" [displayValue]="field.field">
</apt-output-field>
</ng-template>
</div>
</div>
</div>
<div *ngIf="!expanded"></div>
<div *ngIf="view?.popoverFields?.length > 6"
class="toggleButton position-absolute justify-content-center align-items-center border d-flex"
[ngClass]="hovering ? 'bg-primary' : 'bg-white'" (mouseover)="hovering = true" (mouseout)="hovering = false"
(click)="expanded = !expanded">
<i class="fa"
[ngClass]="{'fa-chevron-up': expanded, 'fa-chevron-down': !expanded, 'text-white': hovering, 'text-primary': !hovering}"
aria-hidden="true"></i>
</div>
</div>
<div *ngIf="expanded" class="expandSection p-3">
<div class="container-fluid">
<div class="row">
<div *ngFor="let field of view?.popoverFields | slice:6" class="col-6 pl-0 d-flex flex-column">
<apt-output-field [record]="view?.referenceFieldInstance" [field]="field.field" [label]="field.label"
layout="stacked" [editable]="false" [showQuickView]="false"></apt-output-field>
</div>
</div>
</div>
</div>
</ng-template>
<ng-template #normalQuickViewTemplate>
<div class="popHeader normal-quick-view mb-1 position-relative">
<div class="fieldSection container-fluid">
<div class="row">
<div *ngFor="let field of view?.popoverFields" class="col-6 pl-0 d-flex flex-column quick-view-label pb-1">
<ng-container
*ngIf="field?.field == 'ShippingAddress' || field?.field == 'BillingAddress'; else popoverFieldData">
<apt-address [value]="view.referenceFieldInstance"
[type]="field.field == 'ShippingAddress'? 'Shipping' : 'Billing'" [label]="field.label"
[readonly]="true"></apt-address>
</ng-container>
<ng-template #popoverFieldData>
<apt-output-field [record]="view?.referenceFieldInstance" [field]="field.field" [label]="field.label"
layout="stacked" [editable]="false" [showQuickView]="false" [displayValue]="field.field">
</apt-output-field>
</ng-template>
</div>
</div>
</div>
</div>
</ng-template>
<ng-template #popTemplate>
<button aria-label="Close" [ngClass]="{'text-white': expanded}" class="close pull-right mr-1" type="button"
(click)="handleHidePop(view)">
<span aria-hidden="true">×</span>
</button>
<form class="p-3" (ngSubmit)="update(view)">
<apt-input-field [(ngModel)]="view.recordInstance[view.field]" [field]="view.field" [entity]="view.recordInstance"
[name]="view.field" [lookupOptions]="lookupOptions"></apt-input-field>
<div class="d-flex justify-content-end">
<button class="btn-link btn" (click)="handleHidePop(view)">{{'COMMON.CANCEL' | translate}}</button>
<button class="btn btn-primary btn-raised" type="submit" [ladda]="loading"
[disabled]="!view.recordInstance[view.field]">{{'COMMON.UPDATE' |
translate}}</button>
</div>
</form>
</ng-template>
<ng-template #popOverTemplate>
<span [popover]="view?.nonTruncatedValue" triggers="mouseenter:mouseleave" container="body">{{view?.value |
safeHtml}}</span>
</ng-template>
<ng-template #simple>
<span
*ngIf="(!!view?.value || ((view?.recordMetadata?.DataType.toLowerCase() === 'int' || view?.recordMetadata?.DataType.toLowerCase() === 'decimal') && view?.value >= 0)); else noData">{{view?.value
| safeHtml}}</span>
</ng-template>
<ng-template #noData>
<span>{{'COMMON.NO_DATA' | translate}}</span>
</ng-template>
<ng-content></ng-content>
</span>
./output-field.component.scss
apt-output-field {
.edit-icon {
cursor: pointer;
opacity: .5;
&:hover {
opacity: 1;
}
}
.popoverLink {
cursor: pointer;
}
.hover:hover {
background-color: lightgray;
cursor: pointer;
position: relative;
i.edit-icon {
display: block;
position: absolute;
right: 2%;
top: 22%;
}
}
apt-input-field {
min-width: 300px;
}
.inline:not(.label-only) {
dt {
white-space: nowrap;
&::after {
content: ":";
margin: 0 2px 0 -2px;
}
}
}
dd.empty::after {
content: "\200b"; // unicode zero width space character
}
dd {
padding-top: 0.469rem;
width: initial;
}
dd {
span {
line-height: 1.25rem;
}
}
}
.lookupPopover {
max-width: unset;
width: 322px;
border-radius: 4px;
.popHeader {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.toggleButton {
right: 20px;
bottom: -17px;
width: 34px;
height: 34px;
border-radius: 50%;
cursor: pointer;
z-index: 5;
i {
font-size: 18px;
}
}
.expandSection {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
max-height: 300px;
overflow-y: auto;
}
}
.editPopover {
min-width: 322px;
}
.quick-view-label {
dt {
margin-top: 1em;
line-height: 1.5;
font-size: 0.75rem;
}
dd {
padding: 0px;
font-size: 0.75rem;
}
}