Skip to content

Commit 8c3cba9

Browse files
authored
fix(ui5-shellbar): correct search visibility toggle (#11724)
This PR fixes an issue where "delayed" search fields weren’t supported. Instead of attaching events to the search field, in just the onEnterDOM hook they’re now attached refreshed in the the ShellBar's onBeforeRendering hook. A validation check is also added in every handler to ensure that shellbar is not' reacting on already removed search fields. This change improves event handling and adds a test for dynamic search fields.
1 parent 161af0f commit 8c3cba9

File tree

2 files changed

+89
-32
lines changed

2 files changed

+89
-32
lines changed

packages/fiori/cypress/specs/ShellBar.cy.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,39 @@ describe("Slots", () => {
498498
);
499499
cy.get("#shellbar").invoke("prop", "showSearchField").should("equal", false);
500500
});
501+
502+
it("Test search field added after delay still works with events", () => {
503+
cy.mount(
504+
<ShellBar id="shellbar" primaryTitle="Product Title" showNotifications={true}></ShellBar>
505+
);
506+
507+
cy.get("#shellbar").as("shellbar");
508+
509+
// Add search field after a timeout (simulating real-world scenario)
510+
cy.get("@shellbar").then(shellbar => {
511+
setTimeout(() => {
512+
const searchField = document.createElement("ui5-shellbar-search");
513+
searchField.setAttribute("slot", "searchField");
514+
searchField.setAttribute("id", "delayed-search");
515+
shellbar.get(0).appendChild(searchField);
516+
}, 100);
517+
});
518+
519+
// Wait for the search field to be added
520+
cy.get("#delayed-search", { timeout: 1000 }).should("exist");
521+
522+
// Search should now be visible and collapsed
523+
cy.get("#shellbar [slot='searchField']")
524+
.should("exist")
525+
.should("have.prop", "collapsed", true);
526+
527+
// click the searchField to expand it
528+
cy.get("#shellbar [slot='searchField']")
529+
.click()
530+
.should("have.prop", "collapsed", false);
531+
// check shellbar's showSearchField property is also updated
532+
cy.get("@shellbar").invoke("prop", "showSearchField").should("equal", true);
533+
});
501534
});
502535
});
503536

packages/fiori/src/ShellBar.ts

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -553,10 +553,11 @@ class ShellBar extends UI5Element {
553553
_observableContent: Array<HTMLElement> = [];
554554
_autoRestoreSearchField = false;
555555

556+
_onSearchOpenBound = this._onSearchOpen.bind(this);
557+
_onSearchCloseBound = this._onSearchClose.bind(this);
558+
_onSearchBound = this._onSearch.bind(this);
559+
556560
_headerPress: () => void;
557-
onSearchOpen: () => void;
558-
onSearchClose: () => void;
559-
onSearch: () => void;
560561

561562
static get FIORI_3_BREAKPOINTS() {
562563
return [
@@ -600,24 +601,6 @@ class ShellBar extends UI5Element {
600601
}
601602
};
602603

603-
this.onSearchOpen = () => {
604-
if (isPhone()) {
605-
this.setSearchState(true);
606-
}
607-
};
608-
609-
this.onSearchClose = () => {
610-
if (isPhone()) {
611-
this.setSearchState(false);
612-
}
613-
};
614-
615-
this.onSearch = () => {
616-
if (!isPhone() && !this.search?.value) {
617-
this.setSearchState(!this.showSearchField);
618-
}
619-
};
620-
621604
this._handleResize = throttle(() => {
622605
this.menuPopover = this._getMenuPopover();
623606
this.overflowPopover = this._getOverflowPopover();
@@ -631,6 +614,36 @@ class ShellBar extends UI5Element {
631614
}, RESIZE_THROTTLE_RATE);
632615
}
633616

617+
_onSearchOpen(e: Event) {
618+
if (e.target !== this.search) {
619+
this._detachSearchFieldListeners(e.target as HTMLElement);
620+
return;
621+
}
622+
if (isPhone()) {
623+
this.setSearchState(true);
624+
}
625+
}
626+
627+
_onSearchClose(e: Event) {
628+
if (e.target !== this.search) {
629+
this._detachSearchFieldListeners(e.target as HTMLElement);
630+
return;
631+
}
632+
if (isPhone()) {
633+
this.setSearchState(false);
634+
}
635+
}
636+
637+
_onSearch(e: Event) {
638+
if (e.target !== this.search) {
639+
this._detachSearchFieldListeners(e.target as HTMLElement);
640+
return;
641+
}
642+
if (!isPhone() && !this.search?.value) {
643+
this.setSearchState(!this.showSearchField);
644+
}
645+
}
646+
634647
_updateSearchFieldState() {
635648
const spacerWidth = this.shadowRoot!.querySelector(".ui5-shellbar-spacer") ? this.shadowRoot!.querySelector(".ui5-shellbar-spacer")!.getBoundingClientRect().width : 0;
636649
const searchFieldWidth = this.domCalculatedValues("--_ui5_shellbar_search_field_width");
@@ -823,6 +836,9 @@ class ShellBar extends UI5Element {
823836
} else {
824837
this.search.collapsed = !this.showSearchField;
825838
}
839+
840+
this._detachSearchFieldListeners(this.search);
841+
this._attachSearchFieldListeners(this.search);
826842
}
827843
}
828844

@@ -949,27 +965,35 @@ class ShellBar extends UI5Element {
949965
onEnterDOM() {
950966
ResizeHandler.register(this, this._handleResize);
951967

952-
if (isSelfCollapsibleSearch(this.search)) {
953-
this.search.addEventListener("ui5-open", this.onSearchOpen);
954-
this.search.addEventListener("ui5-close", this.onSearchClose);
955-
this.search.addEventListener("ui5-search", this.onSearch);
956-
}
957-
958968
if (isDesktop()) {
959969
this.setAttribute("desktop", "");
960970
}
971+
this._attachSearchFieldListeners(this.search);
961972
}
962973

963974
onExitDOM() {
964975
this.contentItemsObserver.disconnect();
965976
this._observableContent = [];
966977
ResizeHandler.deregister(this, this._handleResize);
978+
this._detachSearchFieldListeners(this.search);
979+
}
967980

968-
if (isSelfCollapsibleSearch(this.search)) {
969-
this.search.removeEventListener("ui5-open", this.onSearchOpen);
970-
this.search.removeEventListener("ui5-close", this.onSearchClose);
971-
this.search.removeEventListener("ui5-search", this.onSearch);
981+
_attachSearchFieldListeners(searchField: HTMLElement | null) {
982+
if (!searchField) {
983+
return;
984+
}
985+
searchField.addEventListener("ui5-open", this._onSearchOpenBound);
986+
searchField.addEventListener("ui5-close", this._onSearchCloseBound);
987+
searchField.addEventListener("ui5-search", this._onSearchBound);
988+
}
989+
990+
_detachSearchFieldListeners(searchField: HTMLElement | null) {
991+
if (!searchField) {
992+
return;
972993
}
994+
searchField.removeEventListener("ui5-open", this._onSearchOpenBound);
995+
searchField.removeEventListener("ui5-close", this._onSearchCloseBound);
996+
searchField.removeEventListener("ui5-search", this._onSearchBound);
973997
}
974998

975999
_handleSearchIconPress() {
@@ -1687,7 +1711,7 @@ class ShellBar extends UI5Element {
16871711
}
16881712
}
16891713

1690-
interface IShellBarSelfCollapsibleSearch {
1714+
interface IShellBarSelfCollapsibleSearch extends UI5Element {
16911715
collapsed: boolean;
16921716
open: boolean;
16931717
}

0 commit comments

Comments
 (0)