projects/congarevenuecloud/elements/src/lib/product-configuration/product-configuration.component.ts
Product configuration component is used to show the hierarchical view of the configurations for a given product or cart line item.
This component is responsible for loading configuration of product
import { ProductConfigurationModule } from '@congarevenuecloud/elements';
@NgModule({
imports: [ProductConfigurationModule, ...]
})
export class AppModule {}```typescript
<apt-product-configuration
[product]="product.Id"
[relatedTo]="parent"
[accordion]="true"
></apt-product-configuration>
| selector | apt-product-configuration |
| styleUrls | ./product-configuration.component.scss |
| templateUrl | ./product-configuration.component.html |
Properties |
Methods |
Inputs |
constructor(cdr: ChangeDetectorRef, productOptionService: ProductOptionService, cartItemService: CartItemService, secondaryCartService: SecondaryCartService, primaryCartService: CartService, productConfigurationService: ProductConfigurationService, araiService: AppliedRuleActionInfoService, productService: ProductService, alertService: AlertService, assetService: AssetService)
|
|||||||||||||||||||||||||||||||||
|
Parameters :
|
| accordion |
Type : boolean
|
Default value : true
|
|
Flag to determine whether the accordion is expanded or collapsed. |
| discovery |
Type : string
|
Default value : null
|
|
This flag is of type string and can have values like 'productDetailsPage' or 'cartItemDetailsPage'. EX: discovery = 'productDetailsPage;cartItemDetailsPage' If 'productDetailsPage' is set, it allows configuring the product before adding it to the cart. If 'productDetailsPage' is not set, the component will only show a READ-ONLY version with the default configuration and this is the default behaviour. Similarly, If 'cartItemDetailsPage' is set, it allows configuring the item before updating the bundle. If 'cartItemDetailsPage' is not set, configuring before updating the bundle is not allowed. 'CartItemDetailsPage' It's a work in progress. Therefore, configure before update the bundle is not supported. |
| product |
Type : string | Product
|
|
The primitive id of the product to render the configuration or the product record. |
| relatedTo |
Type : CartItem
|
|
The primitive id of the parent product line item that should be used to render the configuration. |
| assignCartItems | ||||||||||||||||
assignCartItems(component: ProductOptionComponent, parentBundleNumber: number, cartItems: Array
|
||||||||||||||||
|
This method traverses the component and its children, assigning the cart items to their corresponding components.
Parameters :
Returns :
void
|
| getAllComponents | ||||||||
getAllComponents(view: ConfigurationView)
|
||||||||
|
This method returns a list of option product See ConfigurationView for more details on the structure and fields required.
Parameters :
Returns :
Array<ProductOptionComponent>
an array of option products associated with the provided view. |
| getComponentArray | ||||||||
getComponentArray(component: ProductOptionComponent)
|
||||||||
|
Method returns a flat array of components and their children of the product option.
Parameters :
Returns :
Array<ProductOptionComponent>
|
| getProductOptionComponent | ||||||||||||
getProductOptionComponent(productId: string, view: ConfigurationView)
|
||||||||||||
|
Method returns an instance of the product option component for the specified product ID. See ConfigurationView for more details on the structure and fields required.
Parameters :
Returns :
ProductOptionComponent
|
| isTriggeringProduct | ||||||||||||||||
isTriggeringProduct(rules: Array<AppliedRuleActionInfo>, componentId: string, bundleProduct: CartItem)
|
||||||||||||||||
|
This function checks if a given component ID triggers any of the given rules.
Only considers rules with an
Parameters :
Returns :
boolean
|
| toggleOption | |||||||||||||||||||||||||||||||||||
toggleOption(component: ProductOptionComponent, group: ProductOptionGroup, reference: string, view: ConfigurationView, evt?: any, showLoader: boolean)
|
|||||||||||||||||||||||||||||||||||
|
This method allows you to add or remove options for a product. See ConfigurationView for more details on the structure and fields required.
Parameters :
Returns :
void
|
| attributeChanged |
Type : boolean
|
Default value : false
|
|
Flag determines changes in attribute. |
| cart$ |
Type : Observable<Cart>
|
|
Cart$ holds Observable of cart |
| collapseAll |
Type : boolean
|
Default value : true
|
|
Controls the collapse of all configuration accordions. |
| onConfigChange |
Type : boolean
|
Default value : false
|
|
Flag determines config change. |
| productQuantity |
Type : number
|
Default value : 1
|
|
Holds quantity of the product. |
| readOnly |
Type : boolean
|
Default value : false
|
| searchText |
Type : string
|
Default value : null
|
|
Search query to filter configuration. |
| view$ |
Type : BehaviorSubject<ConfigurationView>
|
Default value : new BehaviorSubject<ConfigurationView>(null)
|
|
The view object used to hold information for rendering the view, of type ConfigurationView. |
<div class="card">
<div class="card-body">
<ng-container *ngIf="(view$ | async) as view; else loading">
<ng-container *ngIf="view?.product?.OptionGroups?.length > 0 || view?.product?.HasAttributes && view?.product?.AttributeGroups?.length > 0
; else empty">
<div>
<div class="d-flex justify-content-between mb-2">
<form
class="input-group input-group-sm col-lg-2 col-md-4 col-sm-9 col-9 d-flex align-items-center pl-0">
<div class="input-group-append position-absolute">
<button class="btn btn-link">
<i class="fas fa-search"></i>
</button>
</div>
<input type="search" class="form-control"
placeholder="{{'COMMON.SEARCH_CONFIGURATION' | translate}}" [(ngModel)]="searchText"
name="searchText" (ngModelChange)="searchChange()">
</form>
<div>
<button class="btn btn-link px-2" [disabled]="accordion"
(click)="accordion = true; collapseAll = false;">
<i class="fa fa-angle-double-up fa-lg" title="Collapse All"></i>
</button>
<button class="btn btn-link pl-2 pr-0" [disabled]="!accordion"
(click)="accordion = false; collapseAll = true;">
<i class="fa fa-angle-double-down fa-lg" title="Expand All"></i>
</button>
</div>
</div>
<div class="accordion" id="optionAccordion">
<ng-container *ngIf="view?.product?._metadata?.item?.AttributeValue">
<apt-product-attribute [product]="view.product" [relatedTo]="relatedTo"
[(productAttributeValue)]="view.product._metadata.item.AttributeValue"
(productAttributeValueChange)="onAttributeChange($event, view)" [readOnly]="readOnly"
container="optionAccordion" (attributeValueChange)="handleAttributeValueChange($event)"
[accordion]="accordion" [collapseAll]="collapseAll">
</apt-product-attribute>
</ng-container>
<ng-container *ngIf="view?.product?.HasOptions && view?.product?.OptionGroups?.length > 0">
<div class="card border"
*ngFor="let productOptionGroup of view?.product?.OptionGroups; let optionIndex = index; trackBy: trackById"
[hidden]="productOptionGroup.get('hide')">
<ng-container *ngIf="!productOptionGroup?.IsHidden">
<div [id]="'ac' + productOptionGroup.Id" class="accordion">
<div class="card-header px-2 py-1">
<h2 class="mb-0 d-flex justify-content-between align-items-center">
<button class="btn btn-link chevron" type="button"
data-toggle="collapse"
[attr.data-target]="'#a' + productOptionGroup.Id"
[attr.aria-expanded]="((optionIndex + view?.product?.AttributeGroups?.length === 0 || productOptionGroup._metadata.expand) && collapseAll) || !accordion ? 'true' : 'false'">
{{productOptionGroup?.OptionGroup?.Label}}
</button>
<apt-alert [record]="productOptionGroup"
message="ERROR.OPTION_GROUP.ERROR" layout="inline"
[showAlertWithAction]="false"
*ngIf="!readOnly && productOptionGroup?.ModifiableType !== 'Fixed'">
</apt-alert>
</h2>
</div>
<div [id]="'a' + productOptionGroup.Id" class="collapse"
[class.show]="((optionIndex + view?.product?.AttributeGroups?.length === 0 || productOptionGroup._metadata.expand) && collapseAll) || !accordion"
[attr.data-parent]="'#ac' + productOptionGroup.Id">
<div class="card-body">
<div
*ngIf="productOptionGroup?.IsPicklist && productOptionGroup.MaxOptions === 1 && productOptionGroup.MinOptions === 1">
<ng-template [ngTemplateOutlet]="picklistTemplate"
[ngTemplateOutletContext]="{componentList: productOptionGroup?.Options, parent: productOptionGroup.Id, group: productOptionGroup, picklistIndex: optionIndex}">
</ng-template>
</div>
<div *ngIf="!productOptionGroup?.IsPicklist">
<ng-template [ngTemplateOutlet]="productOptionGroupTemplate"
[ngTemplateOutletContext]="{optionGroupList: productOptionGroup?.ChildOptionGroups, parent: productOptionGroup.Id}">
</ng-template>
<div class="pl-3">
<ng-template [ngTemplateOutlet]="componentListTemplate"
[ngTemplateOutletContext]="{componentList: productOptionGroup?.Options, parent: productOptionGroup.Id, group: productOptionGroup, optionIndex: optionIndex}">
</ng-template>
</div>
</div>
</div>
</div>
</div>
</ng-container>
</div>
</ng-container>
</div>
<ng-template #productOptionGroupTemplate let-optionGroupList="optionGroupList" let-parent="parent"
let-parentProduct="parentProduct">
<div class="accordion" [id]="parent">
<div *ngFor="let subProductOptionGroup of optionGroupList; let categoryIndex = index; let l = last; let f = first; trackBy: trackById"
class="mb-3">
<ng-container *ngIf="!subProductOptionGroup?.IsHidden">
<h5 class="d-flex justify-content-between align-items-center border-bottom">
<button class="btn btn-link chevron" type="button" data-toggle="collapse"
[attr.data-target]="'#' + parent + '-' + subProductOptionGroup.Id"
[attr.aria-expanded]="((subProductOptionGroup._metadata.expand) && collapseAll) || !accordion ? 'true' : 'false'">
{{subProductOptionGroup?.OptionGroup?.Label}}
</button>
<apt-alert message="ERROR.OPTION_GROUP.ERROR" layout="inline"
[record]="subProductOptionGroup" [showAlertWithAction]="false"
*ngIf="!readOnly && subProductOptionGroup?.ModifiableType !== 'Fixed'"></apt-alert>
</h5>
<div [id]="parent + '-' + subProductOptionGroup.Id"
class="collapse pl-lg-4 pl-md-4 pl-sm-2 pl-2" [attr.data-parent]="'#' + parent"
[class.show]="((subProductOptionGroup._metadata.expand) && collapseAll) || !accordion">
<div class="mt-4"
*ngIf="subProductOptionGroup?.IsPicklist && subProductOptionGroup.MaxOptions === 1 && subProductOptionGroup.MinOptions === 1">
<ng-template [ngTemplateOutlet]="picklistTemplate"
[ngTemplateOutletContext]="{componentList: subProductOptionGroup?.Options, parent: subProductOptionGroup.Id, group: subProductOptionGroup, picklistIndex: categoryIndex}">
</ng-template>
</div>
<div *ngIf="!subProductOptionGroup?.IsPicklist">
<ng-template [ngTemplateOutlet]="componentListTemplate"
[ngTemplateOutletContext]="{componentList: subProductOptionGroup?.Options, parent: parent + '-' + subProductOptionGroup.Id, group: subProductOptionGroup, optionIndex: categoryIndex}">
</ng-template>
</div>
</div>
</ng-container>
</div>
</div>
</ng-template>
<ng-template #componentListTemplate let-componentList="componentList" let-parent="parent"
let-group="group" let-optionIndex = "optionIndex">
<ng-container
*ngIf="componentList?.length > 0 || group?.ChildOptionGroups?.length > 0; else cLoading">
<ng-container class="custom-border-bottom"
*ngFor="let component of componentList; let f = first; let l = last; trackBy: trackById; let componentListIndex = index;">
<div class="option" *ngIf="!component.get('hidden')" [class.border-bottom]="!l"
[hidden]="component.get('hide')">
<ng-template
*ngIf="component?.ComponentProduct?._metadata?.item?.AssetLineItem?.PriceType === 'One Time'"
[ngTemplateOutlet]="readOnlyComponent" [ngTemplateOutletContext]="{
component: component,
parent: parent,
selected: isOptionSelected(component),
cartItem: component?.ComponentProduct?._metadata?.item,
group: group, readOnlyIndex: optionIndex,
}"></ng-template>
<ng-template
*ngIf="component?.ComponentProduct?._metadata?.item?.AssetLineItem?.PriceType !== 'One Time'"
[ngTemplateOutlet]="componentTemplate" [ngTemplateOutletContext]="{
component: component,
parent: parent,
selected: isOptionSelected(component),
cartItem: component?.ComponentProduct?._metadata?.item,
group: group,
componentIndex: optionIndex,
componentListIndex: componentListIndex}">
</ng-template>
</div>
</ng-container>
</ng-container>
<ng-template #cLoading>
<div class="d-flex justify-content-center pt-5">
<apt-dots></apt-dots>
</div>
</ng-template>
</ng-template>
<ng-template #picklistTemplate let-componentList="componentList" let-parent="parent"
let-group="group" let-picklistIndex = "picklistIndex">
<ng-container
*ngIf="componentList?.length > 0 || group?.ChildOptionGroups?.length > 0; else cLoading">
<ng-select [items]="componentList" class="optionPicklist"
placeholder="{{'PRODUCT_DETAILS.SELECT_ONE_OPTION' | translate}}"
labelForId="group.Id+'-'+ parent.Id" [(ngModel)]="group._metadata.componentName"
(ngModelChange)="isPicklistChangeValue($event, group, view)" [disabled]="readOnly"
bindLabel="ComponentProduct.Name" [virtualScroll]="true">
<ng-template ng-option-tmp let-item="item" let-index="index">
<div class="d-flex py-2"
[ngClass]="{'border-bottom': index !== componentList?.length-1}">
<div class="d-flex flex-grow-1">
<div class="d-flex cr-popover-container">
<div class="image-container d-flex justify-content-center">
<img [src]="item?.ComponentProduct?.IconId | image" height="50">
</div>
</div>
<div class="mx-3">
<p class="m-0 font-weight-bold d-flex">{{item?.ComponentProduct?.Name}}
</p>
<small
class="d-block desc">{{item?.ComponentProduct?.Description}}</small>
</div>
</div>
<div class="width-picklist-fixed border-left d-flex">
<div class="form-group col">
<label>{{'COMMON.PRICE' | translate}}</label>
<h5 class="pt-1">
<apt-price [record]="item?.ComponentProduct"
[type]="'list'"></apt-price>
</h5>
</div>
</div>
</div>
</ng-template>
</ng-select>
<ng-template *ngIf="group._metadata.componentName" [ngTemplateOutlet]="componentTemplate"
[ngTemplateOutletContext]="{
component: group._metadata?.optionSelected,
parent: group.Id,
selected: !!group._metadata.componentName,
cartItem: group._metadata?.optionSelected?.ComponentProduct?._metadata?.item,
group: group,
isPicklist: true,
componentIndex: picklistIndex,
componentListIndex: picklistIndex
}"></ng-template>
</ng-container>
<ng-template #cLoading>
<div class="d-flex justify-content-center pt-5">
<apt-dots></apt-dots>
</div>
</ng-template>
</ng-template>
<ng-template #readOnlyComponent let-component="component" let-parent="parent"
let-cartItem="cartItem" let-group="group" let-selected="selected"
let-readOnlyIndex = "readOnlyIndex">
<div class="d-flex py-2">
<div class="d-flex flex-grow-1">
<div class="d-flex">
<div class="mr-2">
<i class="fa fa-check-square-o fa-lg"></i>
</div>
<div class="image-container d-flex justify-content-center">
<img [src]="component?.ComponentProduct?.IconId | image" height="50">
</div>
</div>
<div class="mx-3">
<p class="m-0 font-weight-bold">{{component?.ComponentProduct?.Name}}</p>
<small class="d-block desc">{{component?.ComponentProduct?.Description}}</small>
</div>
</div>
<div class="width-fixed border-left d-flex">
<div class="form-group col">
<label>{{'COMMON.PRICE' | translate}}</label>
<h5 class="pt-1">
<apt-price [record]="component?.ComponentProduct" [quantity]="1"
[type]="'list'"></apt-price>
</h5>
</div>
<div class="form-group col">
<label for="qty">{{'COMMON.QTY' | translate}}</label>
<input type="number" min="0" class="form-control form-control-sm text-center"
[disabled]="true" id="qty" [value]="cartItem?.Quantity" name="quantity">
</div>
</div>
</div>
<div class="pl-lg-3" [hidden]="!selected">
<ng-container
*ngIf="component?.ComponentProduct?._metadata?.item && component?.ComponentProduct?.HasAttributes">
<apt-product-attribute [product]="component.ComponentProduct"
[relatedTo]="component.ComponentProduct._metadata.item"
[container]="parent + '-' + component.Id" lineType="Option"
[(productAttributeValue)]="component.ComponentProduct._metadata.item.AttributeValue"
(productAttributeValueChange)="onAttributeChange($event, view)"
[readOnly]="readOnly" (attributeValueChange)="handleAttributeValueChange($event)"
[accordion]="accordion" [collapseAll]="collapseAll"></apt-product-attribute>
</ng-container>
<ng-template *ngIf="component?.ComponentProduct?._metadata?.item?.Id"
[ngTemplateOutlet]="productOptionGroupTemplate"
[ngTemplateOutletContext]="{optionGroupList: component?.ComponentProduct?.OptionGroups, parent: parent + '-' + component.Id, parentProduct: component?.ComponentProduct}">
</ng-template>
</div>
</ng-template>
<ng-template #componentTemplate let-component="component" let-parent="parent"
let-selected="selected" let-cartItem="cartItem" let-group="group" let-isPicklist="isPicklist"
let-componentListIndex = "componentListIndex" let-componentIndex = "componentIndex">
<div class="d-lg-flex d-md-flex py-lg-2 py-md-2 py-sm-3 py-3">
<div class="d-flex flex-grow-1">
<div class="d-flex cr-popover-container">
<div class="custom-control custom-checkbox"
*ngIf="!component?._metadata?.processing; else spinner">
<input type="checkbox" class="custom-control-input"
[(ngModel)]="component._metadata.isDirty" [id]="parent + '-' + component.Id"
[checked]="selected"
(ngModelChange)="toggleOption(component, group, parent, view, component?._metadata?.disabled)"
[disabled]="group?._metadata?.summary?.disabled || component?._metadata?.disabled || group.ModifiableType === 'Fixed' || readOnly">
<label class="custom-control-label"
[for]="parent + '-' + component.Id"> </label>
</div>
<ng-template #spinner><apt-spinner class="pr-1 mr-2"
[large]="false"></apt-spinner></ng-template>
<div
class="image-container col-auto row-auto p-0 justify-content-center d-lg-block d-md-block d-sm-none d-none">
<img [src]="component?.ComponentProduct?.IconId | image" height="50">
</div>
</div>
<div class="mx-lg-3 mx-md-3 mx-sm-0 mx-0" [ngClass]="{'pl-2': selected}">
<p class="m-0 font-weight-bold d-flex">{{component?.ComponentProduct?.Name}}
<i *ngIf='!readOnly && component?.IsRequired'
class="fa fa-asterisk text-danger fa-xs" aria-hidden="true"></i>
<apt-popover *ngIf="!readOnly" [placement]="'right'" [constraintRules]="isTriggeringProduct(component?.ComponentProduct?._metadata?.rules, component?.ComponentProduct?.Id, view?.product?._metadata?.item)
? component?.ComponentProduct?._metadata?.rules : null"
[outsideClick]="false"
[isClose]="component?.ComponentProduct?._metadata?.hidePopover">
<i role="button" class="fas fa-info-circle ml-2 text-primary"
*ngIf="isTriggeringProduct(component?.ComponentProduct?._metadata?.rules, component?.ComponentProduct?.Id, view?.product?._metadata?.item)"></i>
</apt-popover>
</p>
<small class="d-block desc">{{component?.ComponentProduct?.Description}}</small>
<apt-alert [record]="component" message="ERROR.OPTION_GROUP.ERROR" layout="inline"
[showAlertWithAction]="false"
*ngIf="!readOnly && productOptionGroup?.ModifiableType !== 'Fixed'">
</apt-alert>
</div>
</div>
<div class="border-left d-lg-flex d-md-flex d-sm-none d-none px-3 py-4"
*ngIf="selected && cartItem">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"
[(ngModel)]="cartItem.IsOptional" [id]="cartItem.Id"
[checked]="cartItem.IsOptional"
(ngModelChange)="changeItemToOptional($event, cartItem, component)">
<label class="custom-control-label pl-1 pt-1"
[for]="cartItem.Id">{{'PRODUCT_DETAILS.IS_OPTIONAL' | translate}}</label>
</div>
</div>
<div class="d-lg-none d-md-none d-sm-flex d-flex pl-4 ml-1 py-2"
*ngIf="selected && cartItem">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"
[(ngModel)]="cartItem.IsOptional" [id]="cartItem.Id"
[checked]="cartItem.IsOptional"
(ngModelChange)="changeItemToOptional($event, cartItem, component)">
<label class="custom-control-label pl-1 pt-1"
[for]="cartItem.Id">{{'PRODUCT_DETAILS.IS_OPTIONAL' | translate}}</label>
</div>
</div>
<div class="width-fixed border-left d-lg-flex d-md-flex d-sm-none d-none">
<div class="form-group col">
<label>{{'COMMON.PRICE' | translate}}</label>
<h5 class="pt-1" [id]="'item-price-' + componentIndex + '-' + componentListIndex">
<ng-container
*ngIf="!component?.ComponentProduct?._metadata?.item?.NetPrice; else itemPrice">
<apt-price [record]="component?.ComponentProduct"
[type]="'list'"></apt-price>
</ng-container>
<ng-template #itemPrice>
<span>{{component?.ComponentProduct?._metadata?.item?.NetPrice |
localCurrency | async}}</span>
</ng-template>
</h5>
</div>
<div class="form-group col">
<label for="qty">{{'COMMON.QTY' | translate}}</label>
<i role="button" class="fas fa-info-circle ml-2 text-primary"
[tooltip]="'COMMON.QUANTITY_NOT_MODIFIABLE' | translate"
*ngIf="!readOnly && ((selected && !component?.IsModifiable) || group?.ModifiableType === 'Fixed')"></i>
<input type="number" [min]="component?.IsRequired ? 1 : 0"
class="form-control form-control-sm text-center"
*ngIf="cartItem; else disabledInput"
[disabled]="!selected || group?.ModifiableType === 'Fixed' || !component?.IsModifiable"
id="qty" placeholder="1" name="quantity"
(change)="emitChange(view); changeItemQuantity(cartItem, component)"
[(ngModel)]="!selected ? 0 : cartItem.Quantity">
<ng-template #disabledInput>
<input type="number" min="0" class="form-control form-control-sm text-center"
[disabled]="true" id="qty" placeholder="1" name="quantity">
</ng-template>
</div>
</div>
<div class="width-fixed d-lg-none d-md-none d-sm-block d-block pl-3">
<div class="form-group col">
<label>{{'COMMON.PRICE' | translate}}</label>
<h5 class="pt-1" [id]="'item-price-sm-' + componentIndex + '-' + componentListIndex">
<ng-container
*ngIf="!component?.ComponentProduct?._metadata?.item?.NetPrice; else itemPrice">
<apt-price [record]="component?.ComponentProduct"
[type]="'list'"></apt-price>
</ng-container>
<ng-template #itemPrice>
<span>{{component?.ComponentProduct?._metadata?.item?.NetPrice |
localCurrency | async}}</span>
</ng-template>
</h5>
</div>
<div class="form-group col">
<label for="qty">{{'COMMON.QTY' | translate}}</label>
<i role="button" class="fas fa-info-circle ml-2 text-primary"
[tooltip]="'COMMON.QUANTITY_NOT_MODIFIABLE' | translate"
*ngIf="!readOnly && ((selected && !component?.IsModifiable) || group?.ModifiableType === 'Fixed')"></i>
<input type="number" [min]="component?.IsRequired ? 1 : 0"
class="form-control form-control-sm text-center"
*ngIf="cartItem; else disabledInput"
[disabled]="!selected || group?.ModifiableType === 'Fixed' || !component?.IsModifiable"
id="qty" placeholder="1" name="quantity"
(change)="emitChange(view); changeItemQuantity(cartItem, component)"
[(ngModel)]="!selected ? 0 : cartItem.Quantity">
<ng-template #disabledInput>
<input type="number" min="0" class="form-control form-control-sm text-center"
[disabled]="true" id="qty" placeholder="1" name="quantity">
</ng-template>
</div>
</div>
</div>
<div class="pl-lg-3 pl-md-0 pl-sm-0 pl-0" [hidden]="!selected">
<ng-container
*ngIf="component?.ComponentProduct?._metadata?.item && component?.ComponentProduct?.HasAttributes">
<apt-product-attribute [product]="component.ComponentProduct"
[relatedTo]="component.ComponentProduct._metadata.item"
[container]="parent + '-' + component.Id" lineType="Option"
[(productAttributeValue)]="component.ComponentProduct._metadata.item.AttributeValue"
(productAttributeValueChange)="onAttributeChange($event, view)"
[readOnly]="readOnly" (attributeValueChange)="handleAttributeValueChange($event)"
[accordion]="accordion" [collapseAll]="collapseAll"></apt-product-attribute>
</ng-container>
<ng-template *ngIf="component?.ComponentProduct?._metadata?.item?.Id"
[ngTemplateOutlet]="productOptionGroupTemplate"
[ngTemplateOutletContext]="{optionGroupList: component?.ComponentProduct?.OptionGroups, parent: 'ad' + parent + '-' + component.Id, parentProduct: component?.ComponentProduct}">
</ng-template>
</div>
</ng-template>
</div>
</ng-container>
<ng-template #empty>
<div class="d-flex justify-content-center flex-column align-items-center py-5 my-5">
<i class="fa fa-cog fa-5x text-primary xl text-faded"></i>
<div class="mt-4">{{'CONFIGURATION.NO_CONFIGURATION' | translate}}</div>
</div>
</ng-template>
</ng-container>
<ng-template #loading>
<div class="d-flex justify-content-center py-5">
<apt-dots></apt-dots>
</div>
</ng-template>
</div>
</div>
./product-configuration.component.scss
.accordion {
.cr-popover-container {
min-width: 10%;
}
.image-container {
width: 64px;
img {
max-height: 50px;
max-width: 64px;
}
}
.form-group {
margin-bottom: 0;
}
input {
max-width: 70px;
}
.custom-control {
margin-top: -3px;
}
.width-fixed {
min-width: 14rem;
}
.desc {
max-height: 40px;
overflow-y: hidden;
}
.card {
overflow: visible;
}
}
.search {
min-width: 300px;
}
apt-cr-popover {
.custom-checkbox {
input[type="checkbox"][disabled] {
+ label {
pointer-events: none;
}
}
}
}
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
/* IE10+ CSS styles go here */
apt-product-configuration
div.accordion
div.card
div.option
div.py-2
div.mx-3 {
margin-left: 3rem;
}
}
.input-group-append {
z-index: 1;
}
.input-group {
input {
border-radius: 0.3rem;
padding-left: 2rem !important;
z-index: 0;
}
}