I'm fairly new to using TypeScript, React and Bootstrap modals in general, however I'm pretty confident that I have avoided the most common mistakes like using the same id
and data-bs-target
in multiple places.
Basically I have a dynamic list of accordions. Each accordion has a body which (in this case) contains a list of restaurants. I have a modal which allows the user to edit this list of restaurants when clicking on the 'Edit' button. As you can see in the code below, the value of the button's data-bs-target
has the state constant deckId
which changes accordingly when clicking on any of the accordions. Same goes for the id
of each modal.
Excuse the bad markup below. Also ignore it if there are is a bracket or a tag too much or too little. I edited out a bunch of broken code so I might've accidentally deleted something unintentionally with that.
The accordions:
const DeckList = (list: any[]) => {
var numberToWords = require('number-to-words');
return (
<div className="accordion" id="accordionPanelsCloseEachother">
{/* <div id="myGroup"> */}
<div className="accordion-group">
{list
.sort((a, b) => a.deckLevel > b.deckLevel ? 1 : -1)
.map((d: DeckModel) => {
return (
<div className="accordion-item" key={d.id}
>
<h2 className="accordion-header" >
<button
onClick={() => setDeckId(d.id)}
className="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target={"#" + numberToWords.toWords(d.deckLevel)}
aria-expanded="false"
aria-controls={numberToWords.toWords(d.deckLevel)}
>
Level {d.deckLevel}
</button>
</h2>
<div id={numberToWords.toWords(d.deckLevel)} className="accordion-collapse collapse" data-bs-parent="#accordionPanelsCloseEachother">
<div className="accordion-body">
<div className="row">
<div className="col-sm-4">
<div className="card">
<div className="card-body">
<h5 className="card-title">{intl.formatMessage({ id: 'RESTAURANTS' })}</h5>
{restDeckListNEW.filter(f => f.deckId === d.id).map((r: RestaurantDeckModel) => {
return (
<li key={r.restaurantId}>{r.restaurantName}</li>
)
})}
</div>
<div className="position-absolute bottom-0 end-0 p-7">
<EditRestaurantFunction
intl={intl}
shipId={shipId}
list={list}
deckId={deckId}
filteredRestaurants={filteredRestaurants}
GET_DECK_URL={GET_DECK_URL}
GET_RESTAURANTDECK_URL={GET_RESTAURANTDECK_URL}
setStatusCode={setStatusCode}
statusCode={statusCode}
GET_SHIP_URL={GET_SHIP_URL}
setReloadValue={setReloadValue}
restDeckListNEW={restDeckListNEW}
checkedRestaurantIdList={checkedRestaurantIdList}
setCheckedRestaurantIdList={setCheckedRestaurantIdList}
unCheckedRestaurantIdList={unCheckedRestaurantIdList}
setUnCheckedRestaurantIdList={setUnCheckedRestaurantIdList} />
</div>
</div>
</div>
<div className="col-sm-4">
<div className="card">
<div className="card-body">
<h5 className="card-title">{intl.formatMessage({ id: 'FACILITIES' })}</h5>
{facilityListNEW.filter(f => f.deckLevel === d.deckLevel || f.optXtrDeckLevel === d.deckLevel).map((t: FacilitiesModel) =>
<li key={facilityListNEW.filter(f => f.deckLevel === d.deckLevel).indexOf(t)}>{t.name}</li>
)}
</div>
<div className="position-absolute bottom-0 end-0 p-7">
<button
type='button'
className='btn btn-warning'
data-bs-toggle='modal'
data-bs-target='#kt_modal_edit2'
onClick={() => getDeck(d.id)}
>
{intl.formatMessage({ id: 'EDIT' })}
</button>
</div>
</div>
</div>
<div className="col-sm-4">
<div className="card">
<div className="card-body">
<h5 className="card-title">{intl.formatMessage({ id: 'CABIN_CATEGORY' })}</h5>
{cabinDeckListNEW.filter(f => f.deckId === d.id).map((c: CabinDeckModel) => {
return (
<li key={c.cabinToDeckId}>{c.category + ' - ' + c.description + ' - ' + c.cabinType}</li>
)
})}
</div>
<div className="position-absolute bottom-0 end-0 p-7">
<button
type='button'
className='btn btn-warning'
data-bs-toggle='modal'
data-bs-target='#kt_modal_edit3'
onClick={() => getDeck(d.id)}
>
{intl.formatMessage({ id: 'EDIT' })}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
})}
</div>
</div>
)
}
The modal component w/ button a.k.a. <EditRestaurantFunction />
:
<div className="col-md-auto">
<button
type='button'
className='btn btn-warning'
data-bs-toggle='modal'
data-bs-target={'#editRestaurants' + deckId}
onClick={ifHasThenChecked}
>
{intl.formatMessage({ id: 'EDIT' })}
</button>
</div>
<div className="modal fade" tabIndex={-1} id={'editRestaurants' + deckId}>
<div className="modal-dialog modal-dialog-centered mw-900px">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">{intl.formatMessage({ id: 'EDIT_RESTAURANT_TO_DECK' })}</h5>
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
id='closeButtonEditRestaurantDeck'
>
</button>
</div>
<div className="modal-body py-lg-10 px-lg-10">
<div
ref={stepperRef}
className='stepper stepper-pills stepper-column d-flex flex-column flex-xl-row flex-row-fluid'
id='kt_modal_create_app_stepper'
>
<div className='d-flex justify-content-center justify-content-xl-start flex-row-auto w-100 w-xl-300px'>
<div className='stepper-nav ps-lg-10'>
<div className='stepper-item current' data-kt-stepper-element='nav'>
<div className='stepper-line w-40px'></div>
<div className='stepper-icon w-40px h-40px'>
<i className='stepper-check fas fa-check'></i>
<span className='stepper-number'>1</span>
</div>
<div className='stepper-label'>
<h3 className='stepper-title'>{intl.formatMessage({ id: 'EDIT_RESTAURANT_LIST' })}</h3>
<div className='stepper-desc'>{intl.formatMessage({ id: 'SELECT_RESTAURANTS' })}</div>
</div>
</div>
</div>
</div>
<div className='flex-row-fluid py-lg-5 px-lg-15'>
<Formik
validationSchema={currentSchema}
initialValues={initValues}
onSubmit={submitStep}
>
{({ errors, status, touched }) => (
<Form className='form' noValidate id='kt_modal_create_cabin_benefits_form'>
<div className='current' data-kt-stepper-element='content'>
<div className='w-100'>
<div className='fv-row mb-10'>
<label className='d-flex align-items-center fs-5 fw-bold mb-2'>
<span>{intl.formatMessage({ id: 'RESTAURANTS' })}</span>
<i
className='fas fa-exclamation-circle ms-2 fs-7'
data-bs-toggle='tooltip'
title={intl.formatMessage({ id: 'SELECT_ANY_NUMBER_RESTAURANTS' })}
></i>
</label>
{filteredRestaurants
.map((r: RestaurantDeckModel) => (
<div className="form-check mt-5" key={r.restaurantId} >
<input className="form-check-input" type="checkbox" value="" id={r.restaurantName}
onClick={() => checkRestaurants(r.restaurantId, r.restaurantName)}
/>
<label className="form-check-label" htmlFor="flexCheckDefault">
{r.restaurantName} - {r.restaurantId}
</label>
</div>
))}
</div>
</div>
</div>
<div>
<button
type='submit'
className='btn btn-lg btn-primary me-3'>
<span className='indicator-label'>
{intl.formatMessage({ id: "AUTH.GENERAL.SUBMIT_BUTTON" })}
</span>
</button>
</div>
</Form>
)}
</Formik>
</div>
</div>
</div>
</div>
</div>
</div>
So far I'm able to open the modal for the first accordion, but when I click on any other accordion and then on the 'Edit' button which triggers the modal to appear, it simply doesn't and also doesn't give any error message in the console. What am I doing wrong?
This is my second question ever on stackoverflow, so do let me know if I'm missing anything important in my question!
UPDATE: I figured out via this questions that my modal only shows up if the first accordion is expanded as well besides any other accordion that I might open. If I close the first accordion and open any other accordion, the modal will not appear. In the solution of the referenced question they use jQuery, which is something I'd like to avoid as much as possible.
Any idea how I can fix this issue using my technologies?