Search code examples
node.jshandlebars.jsexpress-handlebarshbs

Drop down menu always displays 1st option after page processing instead of processed option, Node JS, Express-Handlebars


When I select an option and click the submit button, the view is rendered again, the query is fine but instead of the drop down menu displaying the submitted option, it's actually always displaying the 1st option.

Here's all the code from node js,

let dsPhim=[];
let dsPC=[];

class lichChieu{
   // GET[]/lichchieu/them
    async themLichChieu(req,res){
        try {
            const queryPhim = 'SELECT * FROM Phim WHERE hienThi=1 AND trangThai=1';
            const queryPC = 'SELECT * FROM PhongChieu WHERE trangThai=1';
    
            connection.query(queryPhim,(err,resultsPhim)=>{

                dsPhim=resultsPhim;
                connection.query(queryPC,(err,resultPC)=>{
                    dsPC=resultPC;
                    res.render('showtimes/themLichChieu', {
                        title: 'Thêm Lịch Chiếu Phim',
                        listPhim: dsPhim,
                        listPC: dsPC
                    });
                })
            })
            
        } catch (err) {
            console.error('Lỗi', err.message);
        }
                
    }
    // POST[]/lichchieu/them/luu
    async luuLichChieu(req, res) {  
        let notificationErr=[];
        let notificationSuccess=[];      
        const ngayChieu = req.body.ngayChieu;
        const caChieu = req.body.caChieu;
        const giaPhim = req.body.giaPhim;
        const idPhongChieu = req.body.idPhongChieu;
        const idPhim = req.body.idPhim;
        
        const checkQuery=`SELECT COUNT(*) AS count FROM lichchieu WHERE caChieu=? and ngayChieu=? and idPhongChieu=?`;
        const checkValues=[caChieu,ngayChieu,idPhongChieu];
        

        connection.query(checkQuery,checkValues,(errCheck,checkResult)=>{
            if(checkResult[0].count>0){
                notificationErr.push({err:'Ca chiếu trong ngày này đã có lịch chiếu'});
                res.render('showtimes/themLichChieu', {
                    title: 'Thêm Lịch Chiếu Phim',
                    listPhim:dsPhim,
                    listPC:dsPC,
                    notificationErr:notificationErr,
                    ngayChieu: req.body.ngayChieu,
                    caChieu: req.body.caChieu,
                    giaPhim: req.body.giaPhim,
                    idPhongChieu: req.body.idPhongChieu,
                    idPhim: req.body.idPhim,
                }); 
             

            }else{
                const insertQuery = `INSERT INTO LichChieu (ngayChieu, caChieu, giaPhim, ngayThem, hienThi, idPhongChieu, idPhim)
                VALUES (?, ?, ?, ?, ?, ?, ?)`;

                const insertValues = [
                    ngayChieu,
                    caChieu,
                    giaPhim,
                    new Date(),
                    1, 
                    idPhongChieu,
                    idPhim
                ];                
            
                connection.query(insertQuery, insertValues, (err, results) => {
                    if (err) {
                        console.error('Lỗi', err.message);
                        notificationErr.push({err: err.message});
                        res.render('showtimes/themLichChieu', {
                            title: 'Thêm Lịch Chiếu Phim',
                            listPhim:dsPhim,
                            listPC:dsPC,
                            notificationErr:notificationErr,
                            ngayChieu: req.body.ngayChieu,
                            caChieu: req.body.caChieu,
                            giaPhim: req.body.giaPhim,
                            idPhongChieu: req.body.idPhongChieu,
                            idPhim: req.body.idPhim,
                        }); 
                        
                    } else {
                        notificationSuccess.push({success:"Thêm lịch chiếu thành công"})
                        res.render('showtimes/themLichChieu', {
                            title: 'Thêm Lịch Chiếu Phim',
                            notificationSuccess: notificationSuccess,
                            listPhim:dsPhim,
                            listPC:dsPC,
                            ngayChieu: req.body.ngayChieu,
                            caChieu: req.body.caChieu,
                            giaPhim: req.body.giaPhim,
                            idPhongChieu: req.body.idPhongChieu,
                            idPhim: req.body.idPhim,
                        });     
                         
                               
                     }
                     const updateQuery=`UPDATE Phim SET trangThai=2 WHERE idPhim=?`;
                     const idPhim=[req.body.idPhim];
                     connection.query(updateQuery,[idPhim],(errUpdate,updateResults)=>{
                        if(errUpdate){
                            console.error('Lỗi update trạng thái phim',errUpdate.message)
                            return;
                        }
                        console.log('Cập nhật trạng thái phim thành công')
                     })



                });

            }
        })
    }
  

And this is the code to import helper handlebar

  handlebars.engine({
    defaultLayout: 'main',
    extname: '.hbs',
    layoutsDir: __dirname + '\\src\\views\\layouts\\',
    partialsDir: __dirname + '\\src\\views\\',
    helpers: {
      sum: (a, b) => a + b,
      formatDate:(date) => moment(date).format('MM/DD/YYYY'),
      paginate: paginateHelper.createPagination,
      formatCurrency: (number, currencyCode) => {
        const formatter = new Intl.NumberFormat('vi-VN', {
          style: 'currency',
          currency: currencyCode,
        });
        return formatter.format(number);
      },
      eq(val1, val2, options) {
        return val1 === val2 ? options.fn(this) : options.inverse(this);
      },

    },
  })
);

This is the form submit

<form action="/lichchieu/them/luu" method="POST" class="container-form-add mx-auto" style="max-width: 900px;">
    <div class="row">
        <div class="col-sm-12">
            <div class="mb-3">
                <label class="form-label" for="idPhim">Tên Phim</label>
                <select id="idPhim" name="idPhim" class="form-control">
                    {{#each listPhim}}
                        <option name="{{this.idPhim}}" value="{{this.idPhim}}" {{#eq this.idPhim @root.idPhim}}selected{{/eq}}>{{this.tenPhim}}</option>
                    {{/each}}
                </select>
            </div>
            <div class="mb-3">
                <label class="form-label" for="idPhongChieu">Phòng chiếu</label>
                <select id="idPhongChieu" value="idPhongChieu" name="idPhongChieu" class="form-control">
                    {{#each listPC}}
                    <option name="{{this.idPhongChieu}}" value="{{this.idPhongChieu}}" >{{this.tenPhongChieu}}</option>                        
                    {{/each}}
                </select>
            </div>
            <div class="mb-3">
                <label class="form-label" for="caChieu">Ca Chiếu</label>
                <select id="caChieu" name="caChieu" value="{{caChieu}}" class="form-control">
                    <option name="" value="Ca 1: 8-10h">Ca 1: 8-10h</option>
                    <option name="" value="Ca 2: 13h-15h">Ca 2: 13h-15h</option>
                    <option name="" value="Ca 3: 16-19h30">Ca 3: 16-19h30</option>
                    <option name="" value="Ca 4: 20-23h">Ca 4: 20-23h</option>                        

                </select>
            </div>                              
            <div class="mb-3">
                <label class="form-label" for="showDate">Ngày chiếu</label>
                <input class="form-control" value="{{ngayChieu}}" name="ngayChieu" required name="ngayChieu" id="ngayChieu" type="date" data-date="" data-date-format="DD MMMM YYYY"  aria-describedby="helpId" />
            </div>
            <div class="mb-3">
                <label class="form-label" for="price">Giá phim</label>
                <input class="form-control" value="{{giaPhim}}" required type="number" name="giaPhim" id="giaPhim" aria-describedby="helpId" />
            </div>
        </div>
    </div>
    <div class="text-center">
        <button class="btn btn-primary" type="submit" style="padding: 10px; min-width: 400px; font-weight: bold; margin: 10px;">Thêm mới</button>
    </div>
</form>

I want when I first render this view and select an item from the drop-down list and submit the form to render the view again, that the item that I have submitted will show on the drop-drown list as selected, not the default item. Thank you for helping me, have a great day.


Solution

  • You would need to add the selected attribute to the option that corresponds to the value of idPhim that the user has sent to your server in the body of the POST request.

    The first thing we would need is a custom Handlebars helper that will allow us to compare two values and render a branch of template only if those values are equal. Where exactly this helper should go will depend on your configuration and initialization of express-handlebars, but it would look something like this:

    helpers: {
      eq(val1, val2, options) {
        return val1 === val2 ? options.fn(this) : options.inverse(this);
      }
    }
    

    Next, we will update our template to make use of this new helper. It looks from your post that we already have the submitted value as idPhim in our template data. What we need to be careful of is avoiding confusion between the idPhim that belongs to the current object in our listPhim iteration and the idPhim on the root template data object that was assigned the value of req.body.idPhim. To access the latter, we could use a path prefix, as in ../idPhim, to step-up a context level; but, in this case, I will use the @root data-variable, because I think it is more explicit and therefore will help clarify:

    <option
      name="{{this.idPhim}}"
      value="{{this.idPhim}}"
      {{#eq this.idPhim @root.idPhim}}selected{{/eq}}
    >{{this.tenPhim}}</option>
    

    With this addition to our template, the item in listPhim whose idPhim is equal to @root.idPhim will have the selected attribute added to its <option> output, thereby making it the selected value when the page is rendered by the user's web browser.