I want to open the primeng accordion using a button that is placed in its custom header and i dont want the accordion to open if i click anywhere else. i am using primeng 11-lts version and this is my code for the header of accordion-
<ng-template pTemplate="header">
<span class="flex w-full justify-content-between">
<div class="flex align-items-center">
<p-avatar image="{{ profileimage }}" [size]="showDetails ? 'xlarge' : 'large'" class="ml-5"> </p-avatar>
<div class="ml-5 flex flex-column">
<span class="font-normal white-space-nowrap text-2xl"
>{{ farmerdetail != null ? (farmerdetail.custom_id && farmerdetail.custom_id.id_number ? farmerdetail.custom_id.id_number : farmerdetail.unique_id) : '---' }}
</span>
<span class="font-semibold white-space-nowrap text-3xl">{{ farmerdetail != null ? farmerdetail.firstname : '---' }} {{ farmerdetail != null ? farmerdetail.lastname : '---' }}</span>
</div>
</div>
<div class="flex align-items-center">
<button pButton type="button" class="p-button-outlined" [icon]="showDetails ? 'pi pi-eye-slash' : 'pi pi-eye'" iconPos="left" [label]="showDetails ? 'Hide Details' : 'View Details'"></button>
</div>
</span>
</ng-template>
i tried using (click)="$event.stopPrapagation()" on <span class="flex w-full justify-content-between">
but then the accordion is never opening even if i click on the view details button
To solve this issue, you first need to understand how event propagation happens through the document -
when you click on an element, the click goes from the document to all the way to the lower most element (where the click happened) which is the target element , this is called event capturing, from here the event again goes back to the top , this is called event bubbling. in the event bubbling phase the event handlers(that you put in html or in script using false as third argument of addEventListener) are triggered.
Therefore , knowing the above knowledge we can think of two ways -
so using the first solution we can do -
angular + js -
@ViewChild('accordionTab', { static: false }) accordionTab;
@ViewChild('viewDetails', { static: false }) viewDetails;
ngAfterViewInit() {
this.accordionTab.accordion.el.nativeElement.childNodes[0].childNodes[0].childNodes[0].childNodes[0].addEventListener(
'click',
(e) => {
if (e.target == this.viewDetails.nativeElement || e.target == this.viewDetails.nativeElement.children[0] || e.target == this.viewDetails.nativeElement.children[1]) {
this.showDetails = !this.showDetails;
} else {
e.stopPropagation();
}
},
true
);
}
html -
<p-accordionTab #accordionTab>
<button pButton type="button" class="p-button-outlined" [icon]="showDetails ? 'pi pi-eye-slash' : 'pi pi-eye'" iconPos="left" [label]="showDetails ? 'Hide Details' : 'View Details'" #viewDetails></button>
here , in the above code you will have to mindful if you are using *ngFor to create multiple accordions, then you will have to see how to adjust the logic. Also in the above code we are going to 4th child of accordion tab as the 4th child is the header element in primeng accordion, if you don't put the event listener on the fourth child but any child before the fourth child or the accordion tab itself, then the buttons in accordion content part will not trigger.
the second solution is to put a event.stopPropagation() on the topmost element of your header template so that the click does not reach the anchor element of primeng accordion during event bubbling phase and put a function at the click handler on your desired button which has logic to click the parent of your topmost element (which would be the anchor tag). html -
<span class="flex w-full justify-content-between" (click)="$event.stopPropagation()">
<button
pButton
type="button"
class="p-button-outlined"
[icon]="showDetails ? 'pi pi-eye-slash' : 'pi pi-eye'"
iconPos="left"
[label]="showDetails ? 'Hide Details' : 'View Details'"
(click)="this.accordionTab.accordion.el.nativeElement.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].click()"
></button>
in the above code i am accessing the anchor tag from the accordionTab element by putting #accordionTab on p-accordion-tab and using viewchild to take the reference. in this case make sure to remove the padding of the anchor element in the accordion so that user is not able to directly click the anchor element in the accordion header.
in both the above cases you can repeat the same steps to add more buttons and other logic in your accordion header