I am pretty new to Angular, and I am trying to implement a button in my search/filter bar that will expand the mat-expansion-panel on click, but the panels are housed in a different component and I am not sure of the structure for this.
Button HTML:
<input *ngIf="!(isMobile$ | async) && (isOnline$ | async)"
#filterTextInput
id="filter-text-input"
class="numeric-input"
type="text"
[value]="itemFilterText$ | async"
autocomplete="off"
placeholder="{{'HEADER.SEARCH.PLACEHOLDER' | translate}}"
attr.aria-label="{{'HEADER.SEARCH.PLACEHOLDER' | translate }}"
(keyup.enter)="searchForValue(searchString.value)" />
<button mat-raised-button (click)="togglePanel">Open</button>
Here is the TS file where the functionality should be placed:
import { Component, OnInit, Output, EventEmitter, ViewChildren, QueryList, ElementRef, ChangeDetectionStrategy } from '@angular/core';
import { Worksheet, StorageArea, WorksheetItem, CountableItem, CountingUnit, ConversionUnit } from 'src/app/models';
import { StorageAreaUtilsService } from 'src/app/services/storage-area-utils.service';
import { Store } from '@ngrx/store';
import { AppState } from 'src/app/store/reducers';
import { first, filter, map, flatMap } from 'rxjs/operators';
import { SetStorageAreaExpandStatus, PatchStorageArea, GetAllCustomItemDataAttempt } from 'src/app/store/actions/worksheets.actions';
import { combineLatest, Observable } from 'rxjs';
import { PageEvent, MatPaginator } from '@angular/material';
import { InventoryConstants } from 'src/app/inventory-constants';
import { GetMeasurementUnitsAttempt } from 'src/app/store/actions/addItems.actions';
import { InventoryValueService } from 'src/app/services/inventory-value.service';
@Component({
selector: 'app-storage-area-item-panel',
templateUrl: './storage-area-item-panel.component.html',
styleUrls: ['./storage-area-item-panel.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StorageAreaItemPanelComponent implements OnInit {
worksheet$ = this.store.select(state => {
return state.worksheets.worksheets[state.worksheets.selected];
});
currentLang$ = this.store.select(state => state.layout.language);
isMobile$ = this.store.select(state => state.layout.isMobile);
inventoryItems$ = this.store.select(state => state.inventoryItems.inventoryItems);
itemFilterText$ = this.store.select(state => state.worksheets.itemFilterText);
assignedStorageAreas$: Observable<StorageArea[]>;
unAssignedStorageArea$: Observable<StorageArea>;
pricingPermissions = InventoryConstants.INVENTORY_ROLE_PERMISSIONS.pricing;
standardUnits$ = this.store.select(state => state.addItems.measurementUnits).pipe(
map(units => {
return units.filter(unit => unit.measurementType === 'weight');
})
);
customItemData$ = this.store.select(state => state.worksheets.customItemData);
standardCountingUnits$ = this.store.select(state => state.worksheets.countingUnits);
customCountingUnits$ = this.customItemData$.pipe(
map(data => {
const itemUnits: CountingUnit[] = [];
data.forEach(datum => {
datum.countingUnits.forEach(unit => {
if (unit.custom) {
itemUnits.push({
itemId: datum.itemId,
unit: { unitType: 'CUSTOM', unitId: unit.custom.id } as ConversionUnit,
customUnit: unit
} as CountingUnit);
}
});
});
return itemUnits;
}));
countingUnits$ = combineLatest(this.standardCountingUnits$, this.customCountingUnits$).pipe(
map(response => {
return [].concat(...response);
}));
@Output() afterExpand = new EventEmitter();
storageAreaPaging: { [s: string]: number };
@ViewChildren('storageAreaPaginator')
paginators: QueryList<MatPaginator>;
@ViewChildren('storageAreaPaginatorIndexPlaceholder')
paginatorsDOM: QueryList<ElementRef>;
constructor(
private store: Store<AppState>,
private storageAreaUtils: StorageAreaUtilsService,
private inventoryValueService: InventoryValueService
) {
this.storageAreaPaging = {};
}
ngOnInit() {
this.store.dispatch(new GetMeasurementUnitsAttempt());
this.store.dispatch(new GetAllCustomItemDataAttempt());
this.expandPanels();
this.assignedStorageAreas$ = this.storageAreaUtils.getStorageAreasMinusUnassigned(this.worksheet$);
this.unAssignedStorageArea$ = this.storageAreaUtils.getUnassignedStorageArea(this.worksheet$);
}
onLastItemEnter(storageArea?: StorageArea) {
const pageSize = 10;
if (storageArea) {
let pageIndex = this.storageAreaPaging[storageArea.id] / pageSize;
if (!pageIndex) {
pageIndex = 0;
}
if ((pageIndex + 1) * pageSize < storageArea.worksheetItems.length) {
this.storageAreaPaging[storageArea.id] = (pageIndex + 1) * pageSize;
const paginatorIndex = this.paginatorsDOM.toArray().findIndex(element => {
return element.nativeElement.id === `paginator-${storageArea.id}`;
});
const paginator = this.paginators.toArray()[paginatorIndex];
paginator.nextPage();
}
} else {
this.unAssignedStorageArea$.pipe(first()).subscribe(unassigned => {
let pageIndex = this.storageAreaPaging[unassigned.id] / pageSize;
if (!pageIndex) {
pageIndex = 0;
}
if ((pageIndex + 1) * pageSize < unassigned.worksheetItems.length) {
this.storageAreaPaging[unassigned.id] = (pageIndex + 1) * pageSize;
const paginator = this.paginators.toArray()[0];
paginator.nextPage();
}
});
}
}
onPageClick(event: PageEvent, storageAreaId?: string) {
if (storageAreaId) {
this.storageAreaPaging[storageAreaId] = event.pageIndex * event.pageSize;
} else {
this.unAssignedStorageArea$.pipe(first()).subscribe(unassigned => {
this.storageAreaPaging[unassigned.id] = event.pageIndex * event.pageSize;
});
}
}
getCurrentPageByStorageAreaId(storageAreaId: string, offsetToAdd: number = 0) {
return this.storageAreaPaging[storageAreaId] ? this.storageAreaPaging[storageAreaId] + offsetToAdd : 0 + offsetToAdd;
}
getTranslation(name: string) {
return this.storageAreaUtils.getTranslation(name);
}
getRowItemCount(storageArea: StorageArea) {
return this.storageAreaUtils.getRowItemCount(storageArea);
}
getWorksheetId(): Observable<string> {
return this.worksheet$.pipe(
filter(ws => !!ws),
map((ws: Worksheet) => ws.id)
);
}
// expands the first panel with items if desktop, expands all if mobile
expandPanels() {
combineLatest(this.isMobile$, this.worksheet$).pipe(
filter(([isMobile, ws]) => {
if (ws && ws.storageAreas) {
return true;
} else {
return false;
}
}),
first()
).subscribe(([isMobile, ws]) => {
if (isMobile) {
ws.storageAreas.forEach((area: StorageArea) => {
if (area.expandStatus !== true) {
this.store.dispatch(new SetStorageAreaExpandStatus({ status: true, areaId: area.id }));
}
});
} else if (ws.storageAreas) {
const firstStorageAreaWithRowItems: StorageArea = ws.storageAreas.find(stArea => {
return stArea.worksheetItems.length > 0;
});
if (firstStorageAreaWithRowItems
&& firstStorageAreaWithRowItems.expandStatus !== true) {
this.store.dispatch(new SetStorageAreaExpandStatus({ status: true, areaId: firstStorageAreaWithRowItems.id }));
}
}
});
}
fireSetStorageAreaExpandStatus(event: Event, area: StorageArea) {
if (area !== null) {
this.store.dispatch(new SetStorageAreaExpandStatus({
status: !area.expandStatus,
areaId: area.id
}));
} else if (area === null) {
this.unAssignedStorageArea$
.pipe(first()).subscribe(unassigned => {
this.store.dispatch(new SetStorageAreaExpandStatus({
status: !unassigned.expandStatus,
areaId: unassigned.id
}));
});
}
}
/** Filters general items to only the items contained in the given storage area
* @param area: the storage area to filter by
*/
filterInventoryItemsByArea(area: StorageArea): Observable<{ [s: string]: CountableItem }> {
return this.inventoryItems$.pipe(
filter(() => !!area && !!area.worksheetItems),
map((items) => {
return Object.keys(items)
.filter(id => {
return area.worksheetItems.some(rowItem => rowItem.itemId === id);
})
.reduce((acc, id) => {
acc[id] = items[id];
return acc;
}, {});
})
);
}
filterStorageAreaItemsByFilterText(area: StorageArea): Observable<WorksheetItem[]> {
return combineLatest(this.itemFilterText$, this.inventoryItems$, this.currentLang$)
.pipe(
map(([text, invItems, lang]) => {
if (area.worksheetItems) {
return this.getSortedWorksheetItems(area).filter(workItem => {
const countableItem = invItems[workItem.itemId];
if (countableItem) {
if (countableItem.Item) {
// the item exists and contains the search text in the name, brand, or item SKU
return ((countableItem.Item.description
.find(localValue => localValue.languageCode === lang) !== undefined
&& countableItem.Item.description
.find(localValue => localValue.languageCode === lang).value
&& countableItem.Item.description
.find(localValue => localValue.languageCode === lang).value.toLowerCase().includes(text.toLowerCase()))
|| (countableItem.Item.brand
.find(localValue => localValue.languageCode === lang) !== undefined
&& countableItem.Item.brand
.find(localValue => localValue.languageCode === lang).value
&& countableItem.Item.brand
.find(localValue => localValue.languageCode === lang).value.toLowerCase().includes(text.toLowerCase()))
|| workItem.itemId.includes(text));
} else if (countableItem.customItem) {
return (countableItem.customItem.description.toLowerCase().includes(text.toLowerCase())
|| countableItem.customItem.supplierId.toLowerCase().includes(text.toLowerCase())
|| workItem.itemId.includes(text));
} else if (countableItem.generalItem) {
return (countableItem.generalItem.description.toLowerCase().includes(text.toLowerCase())
|| workItem.itemId.includes(text));
}
} else { // Item info is missing...
return workItem.itemId.includes(text);
}
});
} else {
return [];
}
})
);
}
panelOpenState: boolean = false;
togglePanel() {
this.panelOpenState = !this.panelOpenState
}
If more of the code is needed le