jQuery .val() does NOT change value for one select element, but does change value for another select

I’m working on a time submission application for contractors that work on special projects. I have two select elements, projectSelect and payPeriodSelect.

I use JavaScript promise chains to retrieve and load projects and pay periods. The pay period select is populated with options once a project is selected in the project select.

After the user clicks Submit, I save the time entries to the database and update the select option highlight colors, based on the timesheet status (green for approved, red for rejected, gray for submitted). I need to refresh the project and pay period select option lists so that the options are highlighted with the proper color.

In order to do this, I need to call getProjects() and getPayPeriods() again, and programmatically change the value of projectSelect and payPeriodSelect. I am able to change the value of payPeriodSelect with jQuery’s .val() function. However, projectSelect value is set to null when I used the same method. Why does it work for one select but not the other?

The select elements are defined like this:

<select id='projectSelect' class="form-select"></select>
<select id='payPeriodSelect' class="form-select"></select>

The promise chain to load projects gets called when the page first loads:

getProjects()
    .then(data => {
        return loadProjects(data);
    })
    .then(data => {
        $('#projectSelect').change();    // select the default project to display (1st option in list)
    })
    .catch(error => {
        // display error in modal
    });

function loadProjects(projectData) {
    return new Promise((resolve, reject) => {
  
        let select = document.getElementById("projectSelect");
        select.length = 0;
    
        projectData.reduce((previousPromise, project) => {        // map each project object in the array to a new promise
                

                return previousPromise
                    .then(x => getPayPeriods(project.id))
                    .then(payPeriods => {
                        let option = document.createElement("option")

                        if (payPeriods.length) {
                            // if all timesheets for the project have been approved, change highlight color of option to green
                            if (payPeriods.every(payPeriod => payPeriod.approvalStatus)) {
                                option.setAttribute('class', 'approvedColor')
                            }
                            // If all timesheets are rejected, change color to red
                            else if (payPeriods.every(payPeriod => payPeriod.rejectionStatus)) {
                                option.setAttribute('class', 'rejectedColor')
                            }
                            // if all timesheets are submitted, change color to gray
                            else if (payPeriods.every(payPeriod => payPeriod.submissionStatus)) {
                                option.setAttribute('class', 'submittedColor')
                            } 
                        }

                        option.text = project.code + ' - ' + project.name  
                        option.value = project.id
                        select.appendChild(option)

                        select.value = select.options[0].value    // set 1st option's project ID as default value
                        
                        return resolve(true)
                    })     
                    .catch(error => {
                        return reject(error)
                    })
            }, Promise.resolve())       // Promise.resolve() is the initial promise function that starts the chain

        return resolve(true);
    })
}

The change event for the projectSelect and the load pay period functions is shown below:

$('#projectSelect').on('change', function (e) {
    
    $('tr').find("input.timeBox").val("")       // clear timesheet inputs

    let projectId = this.value

    getPayPeriods(projectId)
        .then(data => {
            return loadPayPeriods(data)
        })
        .then(x => {
            $('#payPeriodSelect').trigger('change')
        })
        .catch(error => {
               
        })
})

function loadPayPeriods(data) {
    return new Promise((resolve, reject)=>{

        var select = document.getElementById("payPeriodSelect")
        select.length = 0

        if (!data.length) {
            $('#payPeriodSelect').attr('disabled', true)
            return reject(false)
        }

        // enable dropdown if there are pay periods to load into it
        $('#payPeriodSelect').attr('disabled', false)

        for (let payPeriod of data) {

            let option = document.createElement("option")
            option.text = payPeriod.start_d + ' - ' + payPeriod.end_d
            option.value = payPeriod.start_d + '|' + payPeriod.end_d

            // change pay period option highlight colors based on timesheet status
            if (payPeriod.approval_d) {
                option.setAttribute('class', 'approved')
            } else if (payPeriod.rejection_d) {
                option.setAttribute('class', 'rejected')
            } else if (payPeriod.submission_d) {
                option.setAttribute('class', 'submitted')
            }

            select.appendChild(option) 
        }

        select.value = select.options[0].value
        return resolve(true)
    })     
}

The payPeriodSelect change event:


    $('#payPeriodSelect').on('change', function (e) {
   

                    // get and populate timesheet data for the selected pay period
                    getTimeData(this.value)
                        .then(data=> {
                            return loadTimeData(data)
                        })
                        .then(data => {

                            if (data) {
                                let payPeriodSelect = document.getElementById('payPeriodSelect')

                            
                                if (data.approvalStatus) {
                                    payPeriodSelect.options[payPeriodSelect.selectedIndex].setAttribute('class', 'approvedColor')
                                } else if (data.rejectionStatus) {
                                    payPeriodSelect.options[payPeriodSelect.selectedIndex].setAttribute('class', 'rejectedColor')
                                } else if (data.submissionStatus) {
                                    payPeriodSelect.options[payPeriodSelect.selectedIndex].setAttribute('class', 'submittedColor')
                                }
                            }
   
                        })
                        .then(x => {
                            return calculateTotalTime()
                        })
                        .catch(error => {
          
                        })
                })

The function for submitting time. I get and load projects, and change the values for both select elements. projectSelect value is set to null while payPeriodSelect value is set to the correct value.

$('#submitTol').on('click', function (e) {
    return saveDataToDatabase()
        .then(data => {
            return getProjects()
        })
        .then(data => {
            return loadProjects(data)
        })
        .then(x => {
            return new Promise((resolve, reject) => {
                    $('#projectSelect').val(project.id).change()
                    return resolve(true)
                })
        })
        .then(x => {
            return new Promise((resolve, reject) => {
                    $('#payPeriodSelect').val( payPeriod.start_d + '-' + payPeriod.end_d).change()
                    return resolve(true)
                })
        }
}

Sorry for the heap of code, but I wanted to give some context about how I retrieve and display data in the select elements. I am so confused as to why changing payPeriodSelect‘s value works, but not projectSelect.