@@ -36,7 +36,7 @@ export class MultipleSelectInstance {
36
36
protected updateData : any [ ] = [ ] ;
37
37
protected data ?: Array < OptionRowData | OptGroupRowData > = [ ] ;
38
38
protected dataTotal ?: any ;
39
- protected dropElm ! : HTMLDivElement ;
39
+ protected dropElm ? : HTMLDivElement ;
40
40
protected okButtonElm ?: HTMLButtonElement ;
41
41
protected filterParentElm ?: HTMLDivElement | null ;
42
42
protected lastFocusedItemKey = '' ;
@@ -106,6 +106,7 @@ export class MultipleSelectInstance {
106
106
107
107
this . virtualScroll ?. destroy ( ) ;
108
108
this . dropElm ?. remove ( ) ;
109
+ this . dropElm = undefined ;
109
110
this . parentElm . parentNode ?. removeChild ( this . parentElm ) ;
110
111
111
112
if ( this . fromHtml ) {
@@ -433,14 +434,14 @@ export class MultipleSelectInstance {
433
434
434
435
saLabelElm . appendChild ( createDomElement ( 'span' , { textContent : this . formatSelectAll ( ) } ) ) ;
435
436
this . selectAllParentElm . appendChild ( saLabelElm ) ;
436
- this . dropElm . appendChild ( this . selectAllParentElm ) ;
437
+ this . dropElm ? .appendChild ( this . selectAllParentElm ) ;
437
438
}
438
439
439
440
this . ulElm = document . createElement ( 'ul' ) ;
440
441
this . ulElm . role = 'combobox' ;
441
442
this . ulElm . ariaExpanded = 'false' ;
442
443
this . ulElm . ariaMultiSelectable = String ( ! this . options . single ) ;
443
- this . dropElm . appendChild ( this . ulElm ) ;
444
+ this . dropElm ? .appendChild ( this . ulElm ) ;
444
445
445
446
if ( this . options . showOkButton && ! this . options . single ) {
446
447
this . okButtonElm = createDomElement (
@@ -461,8 +462,8 @@ export class MultipleSelectInstance {
461
462
}
462
463
463
464
if ( rows . length > Constants . BLOCK_ROWS * Constants . CLUSTER_BLOCKS ) {
464
- const dropVisible = this . dropElm . style . display !== 'none' ;
465
- if ( ! dropVisible ) {
465
+ const dropVisible = this . dropElm && this . dropElm ? .style . display !== 'none' ;
466
+ if ( ! dropVisible && this . dropElm ) {
466
467
this . dropElm . style . left = '-10000' ;
467
468
this . dropElm . style . display = 'block' ;
468
469
this . dropElm . ariaExpanded = 'true' ;
@@ -511,7 +512,7 @@ export class MultipleSelectInstance {
511
512
}
512
513
updateDataOffset ( ) ;
513
514
514
- if ( ! dropVisible ) {
515
+ if ( ! dropVisible && this . dropElm ) {
515
516
this . dropElm . style . left = '0' ;
516
517
this . dropElm . style . display = 'none' ;
517
518
this . dropElm . ariaExpanded = 'false' ;
@@ -788,13 +789,13 @@ export class MultipleSelectInstance {
788
789
] ) ;
789
790
790
791
this . clearSearchIconElm = this . filterParentElm ?. querySelector ( '.ms-icon-close' ) ;
791
- this . searchInputElm = this . dropElm . querySelector < HTMLInputElement > ( '.ms-search input' ) ;
792
- this . selectAllElm = this . dropElm . querySelector < HTMLInputElement > ( `input[data-name="${ this . selectAllName } "]` ) ;
793
- this . selectGroupElms = this . dropElm . querySelectorAll < HTMLInputElement > (
792
+ this . searchInputElm = this . dropElm ? .querySelector < HTMLInputElement > ( '.ms-search input' ) ;
793
+ this . selectAllElm = this . dropElm ? .querySelector < HTMLInputElement > ( `input[data-name="${ this . selectAllName } "]` ) ;
794
+ this . selectGroupElms = this . dropElm ? .querySelectorAll < HTMLInputElement > (
794
795
`input[data-name="${ this . selectGroupName } "],span[data-name="${ this . selectGroupName } "]` ,
795
796
) ;
796
- this . selectItemElms = this . dropElm . querySelectorAll < HTMLInputElement > ( `input[data-name="${ this . selectItemName } "]:enabled` ) ;
797
- this . noResultsElm = this . dropElm . querySelector < HTMLDivElement > ( '.ms-no-results' ) ;
797
+ this . selectItemElms = this . dropElm ? .querySelectorAll < HTMLInputElement > ( `input[data-name="${ this . selectItemName } "]:enabled` ) ;
798
+ this . noResultsElm = this . dropElm ? .querySelector < HTMLDivElement > ( '.ms-no-results' ) ;
798
799
799
800
const toggleOpen = ( e : MouseEvent & { target : HTMLElement } ) => {
800
801
e . preventDefault ( ) ;
@@ -925,87 +926,91 @@ export class MultipleSelectInstance {
925
926
) ;
926
927
}
927
928
928
- this . _bindEventService . bind (
929
- this . selectGroupElms ,
930
- 'click' ,
931
- ( ( e : MouseEvent & { currentTarget : HTMLInputElement } ) => {
932
- const selectElm = e . currentTarget ;
933
- const checked = selectElm . checked ;
934
- const group = findByParam ( this . data , '_key' , selectElm . dataset . key ) ;
935
-
936
- this . _checkGroup ( group , checked ) ;
937
- this . options . onOptgroupClick (
938
- removeUndefined ( {
939
- label : group . label ,
940
- selected : group . selected ,
941
- data : group . _data ,
942
- children : group . children . map ( ( child : any ) => {
943
- if ( child ) {
944
- return removeUndefined ( {
945
- text : child . text ,
946
- value : child . value ,
947
- selected : child . selected ,
948
- disabled : child . disabled ,
949
- data : child . _data ,
950
- } ) ;
951
- }
929
+ if ( this . selectGroupElms ) {
930
+ this . _bindEventService . bind (
931
+ this . selectGroupElms ,
932
+ 'click' ,
933
+ ( ( e : MouseEvent & { currentTarget : HTMLInputElement } ) => {
934
+ const selectElm = e . currentTarget ;
935
+ const checked = selectElm . checked ;
936
+ const group = findByParam ( this . data , '_key' , selectElm . dataset . key ) ;
937
+
938
+ this . _checkGroup ( group , checked ) ;
939
+ this . options . onOptgroupClick (
940
+ removeUndefined ( {
941
+ label : group . label ,
942
+ selected : group . selected ,
943
+ data : group . _data ,
944
+ children : group . children . map ( ( child : any ) => {
945
+ if ( child ) {
946
+ return removeUndefined ( {
947
+ text : child . text ,
948
+ value : child . value ,
949
+ selected : child . selected ,
950
+ disabled : child . disabled ,
951
+ data : child . _data ,
952
+ } ) ;
953
+ }
954
+ } ) ,
952
955
} ) ,
953
- } ) ,
954
- ) ;
955
- } ) as EventListener ,
956
- undefined ,
957
- 'group-checkbox-list' ,
958
- ) ;
956
+ ) ;
957
+ } ) as EventListener ,
958
+ undefined ,
959
+ 'group-checkbox-list' ,
960
+ ) ;
961
+ }
959
962
960
- this . _bindEventService . bind (
961
- this . selectItemElms ,
962
- 'click' ,
963
- ( ( e : MouseEvent & { currentTarget : HTMLInputElement } ) => {
964
- const selectElm = e . currentTarget ;
965
- const checked = selectElm . checked ;
966
- const option = findByParam ( this . data , '_key' , selectElm . dataset . key ) ;
967
- const close = ( ) => {
968
- if ( this . options . single && this . options . isOpen && ! this . options . keepOpen ) {
969
- this . close ( 'selection' ) ;
963
+ if ( this . selectItemElms ) {
964
+ this . _bindEventService . bind (
965
+ this . selectItemElms ,
966
+ 'click' ,
967
+ ( ( e : MouseEvent & { currentTarget : HTMLInputElement } ) => {
968
+ const selectElm = e . currentTarget ;
969
+ const checked = selectElm . checked ;
970
+ const option = findByParam ( this . data , '_key' , selectElm . dataset . key ) ;
971
+ const close = ( ) => {
972
+ if ( this . options . single && this . options . isOpen && ! this . options . keepOpen ) {
973
+ this . close ( 'selection' ) ;
974
+ }
975
+ } ;
976
+
977
+ if ( this . options . onBeforeClick ( option ) === false ) {
978
+ close ( ) ;
979
+ return ;
970
980
}
971
- } ;
972
981
973
- if ( this . options . onBeforeClick ( option ) === false ) {
974
- close ( ) ;
975
- return ;
976
- }
982
+ this . _check ( option , checked ) ;
983
+ this . options . onClick (
984
+ removeUndefined ( {
985
+ text : option . text ,
986
+ value : option . value ,
987
+ selected : option . selected ,
988
+ data : option . _data ,
989
+ } ) ,
990
+ ) ;
977
991
978
- this . _check ( option , checked ) ;
979
- this . options . onClick (
980
- removeUndefined ( {
981
- text : option . text ,
982
- value : option . value ,
983
- selected : option . selected ,
984
- data : option . _data ,
985
- } ) ,
986
- ) ;
987
-
988
- close ( ) ;
989
- } ) as EventListener ,
990
- undefined ,
991
- 'input-checkbox-list' ,
992
- ) ;
992
+ close ( ) ;
993
+ } ) as EventListener ,
994
+ undefined ,
995
+ 'input-checkbox-list' ,
996
+ ) ;
997
+ }
993
998
994
- if ( this . lastFocusedItemKey ) {
999
+ if ( this . lastFocusedItemKey && this . dropElm ) {
995
1000
// if we previously had an item focused and the VirtualScroll recreates the list, we need to refocus on last item by its input data-key
996
1001
const input = this . dropElm . querySelector < HTMLInputElement > ( `li[data-key=${ this . lastFocusedItemKey } ]` ) ;
997
1002
input ?. focus ( ) ;
998
1003
}
999
1004
1000
- if ( this . options . navigationHighlight ) {
1005
+ if ( this . options . navigationHighlight && this . dropElm ) {
1001
1006
// when hovering an select option, we will also change the highlight to that option
1002
1007
this . _bindEventService . bind (
1003
1008
this . dropElm ,
1004
1009
'mouseover' ,
1005
1010
( ( e : MouseEvent & { target : HTMLDivElement | HTMLLIElement } ) => {
1006
1011
const liElm = ( e . target . closest ( '.ms-select-all' ) || e . target . closest ( 'li' ) ) as HTMLLIElement ;
1007
1012
1008
- if ( this . dropElm . contains ( liElm ) && this . lastMouseOverPosition !== `${ e . clientX } :${ e . clientY } ` ) {
1013
+ if ( this . dropElm ? .contains ( liElm ) && this . lastMouseOverPosition !== `${ e . clientX } :${ e . clientY } ` ) {
1009
1014
const optionElms = this . dropElm ?. querySelectorAll < HTMLLIElement > ( OPTIONS_LIST_SELECTOR ) || [ ] ;
1010
1015
const newIdx = Array . from ( optionElms ) . findIndex ( el => el . dataset . key === liElm . dataset . key ) ;
1011
1016
if ( this . _currentHighlightIndex !== newIdx && ! liElm . classList . contains ( 'disabled' ) ) {
@@ -1145,7 +1150,7 @@ export class MultipleSelectInstance {
1145
1150
}
1146
1151
1147
1152
protected openDrop ( ) {
1148
- if ( this . choiceElm ?. classList . contains ( 'disabled' ) ) {
1153
+ if ( ! this . dropElm || this . choiceElm ?. classList . contains ( 'disabled' ) ) {
1149
1154
return ;
1150
1155
}
1151
1156
this . options . isOpen = true ;
@@ -1343,13 +1348,15 @@ export class MultipleSelectInstance {
1343
1348
this . options . isOpen = false ;
1344
1349
this . parentElm . classList . remove ( 'ms-parent-open' ) ;
1345
1350
this . choiceElm ?. querySelector ( 'div.ms-icon-caret' ) ?. classList . remove ( 'open' ) ;
1346
- this . dropElm . style . display = 'none' ;
1347
- this . dropElm . ariaExpanded = 'false' ;
1348
-
1349
- if ( this . options . container ) {
1350
- this . parentElm . appendChild ( this . dropElm ) ;
1351
- this . dropElm . style . top = 'auto' ;
1352
- this . dropElm . style . left = 'auto' ;
1351
+ if ( this . dropElm ) {
1352
+ this . dropElm . style . display = 'none' ;
1353
+ this . dropElm . ariaExpanded = 'false' ;
1354
+
1355
+ if ( this . options . container ) {
1356
+ this . parentElm . appendChild ( this . dropElm ) ;
1357
+ this . dropElm . style . top = 'auto' ;
1358
+ this . dropElm . style . left = 'auto' ;
1359
+ }
1353
1360
}
1354
1361
this . options . onClose ( reason ) ;
1355
1362
}
@@ -1444,7 +1451,7 @@ export class MultipleSelectInstance {
1444
1451
protected updateSelected ( rows ?: HtmlStruct [ ] ) {
1445
1452
for ( let i = this . updateDataStart ! ; i < this . updateDataEnd ! ; i ++ ) {
1446
1453
const row = this . updateData [ i ] ;
1447
- const inputElm = this . dropElm . querySelector < HTMLInputElement > ( `input[data-key=${ row . _key } ]` ) ;
1454
+ const inputElm = this . dropElm ? .querySelector < HTMLInputElement > ( `input[data-key=${ row . _key } ]` ) ;
1448
1455
if ( inputElm ) {
1449
1456
inputElm . checked = row . selected ;
1450
1457
const closestLiElm = inputElm . closest ( 'li' ) ;
@@ -1471,7 +1478,7 @@ export class MultipleSelectInstance {
1471
1478
1472
1479
if ( this . selectAllElm ) {
1473
1480
this . selectAllElm . ariaChecked = String ( this . isAllSelected ) ;
1474
- const checkboxIconElm = this . dropElm . querySelector ( '.ms-select-all .icon-checkbox-container div' ) ;
1481
+ const checkboxIconElm = this . dropElm ? .querySelector ( '.ms-select-all .icon-checkbox-container div' ) ;
1475
1482
if ( checkboxIconElm ) {
1476
1483
let iconClass = '' ;
1477
1484
if ( this . isAllSelected ) {
@@ -1857,53 +1864,55 @@ export class MultipleSelectInstance {
1857
1864
}
1858
1865
1859
1866
protected adjustDropWidthByText ( ) {
1860
- const parentWidth = this . parentElm . scrollWidth ;
1867
+ if ( this . dropElm ) {
1868
+ const parentWidth = this . parentElm . scrollWidth ;
1861
1869
1862
- // keep the dropWidth/width as reference, if our new calculated width is below then we will re-adjust (else do nothing)
1863
- let currentDefinedWidth : number | string = parentWidth ;
1864
- if ( this . options . dropWidth || this . options . width ) {
1865
- currentDefinedWidth = this . options . dropWidth || this . options . width || 0 ;
1866
- }
1870
+ // keep the dropWidth/width as reference, if our new calculated width is below then we will re-adjust (else do nothing)
1871
+ let currentDefinedWidth : number | string = parentWidth ;
1872
+ if ( this . options . dropWidth || this . options . width ) {
1873
+ currentDefinedWidth = this . options . dropWidth || this . options . width || 0 ;
1874
+ }
1867
1875
1868
- // calculate the "Select All" element width, this text is configurable which is why we recalculate every time
1869
- const selectAllSpanElm = this . dropElm . querySelector < HTMLSpanElement > ( '.ms-select-all span' ) ;
1870
- const dropUlElm = this . dropElm . querySelector ( 'ul' ) as HTMLUListElement ;
1876
+ // calculate the "Select All" element width, this text is configurable which is why we recalculate every time
1877
+ const selectAllSpanElm = this . dropElm . querySelector < HTMLSpanElement > ( '.ms-select-all span' ) ;
1878
+ const dropUlElm = this . dropElm . querySelector ( 'ul' ) as HTMLUListElement ;
1871
1879
1872
- const liPadding = 26 ; // there are multiple padding involved, let's fix it at 26px
1880
+ const liPadding = 26 ; // there are multiple padding involved, let's fix it at 26px
1873
1881
1874
- const selectAllElmWidth = selectAllSpanElm ?. clientWidth ?? 0 + liPadding ;
1875
- const hasScrollbar = dropUlElm . scrollHeight > dropUlElm . clientHeight ;
1876
- const scrollbarWidth = hasScrollbar ? this . getScrollbarWidth ( ) : 0 ;
1877
- let contentWidth = 0 ;
1882
+ const selectAllElmWidth = selectAllSpanElm ?. clientWidth ?? 0 + liPadding ;
1883
+ const hasScrollbar = dropUlElm . scrollHeight > dropUlElm . clientHeight ;
1884
+ const scrollbarWidth = hasScrollbar ? this . getScrollbarWidth ( ) : 0 ;
1885
+ let contentWidth = 0 ;
1878
1886
1879
- this . dropElm . querySelectorAll ( 'li label' ) . forEach ( elm => {
1880
- if ( elm . scrollWidth > contentWidth ) {
1881
- contentWidth = elm . scrollWidth ;
1882
- }
1883
- } ) ;
1887
+ this . dropElm . querySelectorAll ( 'li label' ) . forEach ( elm => {
1888
+ if ( elm . scrollWidth > contentWidth ) {
1889
+ contentWidth = elm . scrollWidth ;
1890
+ }
1891
+ } ) ;
1884
1892
1885
- // add a padding & include the browser scrollbar width
1886
- contentWidth += liPadding + scrollbarWidth ;
1893
+ // add a padding & include the browser scrollbar width
1894
+ contentWidth += liPadding + scrollbarWidth ;
1887
1895
1888
- // make sure the new calculated width is wide enough to include the "Select All" text (this text is configurable)
1889
- if ( contentWidth < selectAllElmWidth ) {
1890
- contentWidth = selectAllElmWidth ;
1891
- }
1896
+ // make sure the new calculated width is wide enough to include the "Select All" text (this text is configurable)
1897
+ if ( contentWidth < selectAllElmWidth ) {
1898
+ contentWidth = selectAllElmWidth ;
1899
+ }
1892
1900
1893
- // if a maxWidth is defined, make sure our new calculate width is not over the maxWidth
1894
- if ( this . options . maxWidth && contentWidth > this . options . maxWidth ) {
1895
- contentWidth = this . options . maxWidth ;
1896
- }
1901
+ // if a maxWidth is defined, make sure our new calculate width is not over the maxWidth
1902
+ if ( this . options . maxWidth && contentWidth > this . options . maxWidth ) {
1903
+ contentWidth = this . options . maxWidth ;
1904
+ }
1897
1905
1898
- // if a minWidth is defined, make sure our new calculate width is not below the minWidth
1899
- if ( this . options . minWidth && contentWidth < this . options . minWidth ) {
1900
- contentWidth = this . options . minWidth ;
1901
- }
1906
+ // if a minWidth is defined, make sure our new calculate width is not below the minWidth
1907
+ if ( this . options . minWidth && contentWidth < this . options . minWidth ) {
1908
+ contentWidth = this . options . minWidth ;
1909
+ }
1902
1910
1903
- // finally re-adjust the drop to the new calculated width when necessary
1904
- if ( currentDefinedWidth === '100%' || + currentDefinedWidth < contentWidth ) {
1905
- this . dropElm . style . width = `${ contentWidth } px` ;
1906
- this . dropElm . style . maxWidth = `${ contentWidth } px` ;
1911
+ // finally re-adjust the drop to the new calculated width when necessary
1912
+ if ( currentDefinedWidth === '100%' || + currentDefinedWidth < contentWidth ) {
1913
+ this . dropElm . style . width = `${ contentWidth } px` ;
1914
+ this . dropElm . style . maxWidth = `${ contentWidth } px` ;
1915
+ }
1907
1916
}
1908
1917
}
1909
1918
0 commit comments