I'm working with this 3rd party dropdown - primereact - and it's component primereact/multiselect ... I need everything to work exactly as the original developer wrote, except a few functions. These functions are not accessible via props. I'm wondering if there is a "best practices" way. The problem with the original code -- there is a bug in the "Select All" checkbox, and I want to change the function of the close icon; it is redundant in my application.
These are the only two options I could think of:
- Copy entire source code of 3rd party item, modify it directly, and then remove the dependency. This kind of feels like stealing to me, though.
- Extend the component and override the functions
Here is the 3rd party source code: https://bit.dev/primefaces/primereact/multiselect/~code#multiselect/MultiSelect.js
and here is my code:
import React from 'react';
import { MultiSelect } from 'primereact/multiselect';
import {customMultiSelectSearchHeader} from './searchSafeMultiSelect.css';
class SearchSafeMultiSelect extends MultiSelect {
constructor(props) {
super(props);
this.state = {
filter: ''
};
// Binds certain functions to NEW class, instead of __proto__
this.hasFilter = this.hasFilter.bind(this);
this.onClick = this.onClick.bind(this);
this.onOptionClick = this.onOptionClick.bind(this);
this.onOptionKeyDown = this.onOptionKeyDown.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onFilter = this.onFilter.bind(this);
this.onCloseClick = this.onCloseClick.bind(this);
this.onToggleAll = this.onToggleAll.bind(this);
}
// Changes icon next to search bar from X to trash can.
originalRenderHeader = this.renderHeader;
renderHeader = (items) => {
const header = this.originalRenderHeader(items);
return (
<div className={customMultiSelectSearchHeader}>
{header}
</div>
);
}
// Makes clicking the Trash (previously X) icon close the dropdown AND clear selection.
onCloseClick = (event) => {
this.hide();
this.updateModel(event.originalEvent, []);
event.preventDefault();
event.stopPropagation();
}
// Fixes bug in dependency - ALL box is checked if all visible options are selected.
isAllChecked = (visibleOptions) => {
if(this.hasFilter()) {
return this.props.value && visibleOptions && visibleOptions.length
&& this.filterOptions(this.props.options).find(visible => this.props.value.indexOf(this.getOptionValue(visible) == -1) == undefined;
}
else {
return this.props.value && this.props.options && (this.props.value.length === this.props.options.length);
}
}
}
export default SearchSafeMultiSelect;
CSS file ./searchSafeMultiSelect.css:
.customMultiSelectSearchHeader button span::before{
content: "\e93d" !important;
}
package.json (sets primereact version to exactly 5.0.1 incase they update, my code should stay the same)
"primereact": "5.0.1",
It works as expected. I am just wondering if I'm doing something taboo over here. I looked up many guides, but didn't see anyone online modifying dependencies this way. That is making me doubt if my approach is safe.
Edit: Yes, I've read many things about "Composition over Inheritance" here, but in the case of 3rd party components, the only way I can change the base's composition is by altering the dependency's source code directly. So, I feel like I'm stuck between 2 bad options -- changing the source code or using inheritance.