jquery.seat-charts.js未捕获的TypeError:无法读取未定义

时间:2017-10-13 06:27:07

标签: javascript jquery

我正在使用Jquery Seat图表来预订机票。一切正常,但是当我打电话给一个已经预订座位的功能时,座位的状态不会变为“已经预订”。

我得到'jquery.seat-charts.js未捕获的TypeError:无法读取未定义'错误的属性'status'。

这是我的代码:

function getBookedSeats() {
        jQuery(document).ready(function ($) {
            $.ajax({
                type     : 'get',
                url      : 'bookings/getSelectedSeats',
                data     : 'show_id=<?php echo $show_id ?>',
                success  : function(response) {
                    response1 = JSON.parse(response);
                    $.each(response1.bookings, function (index, booking) {
                        sc.status(booking.seat_id, 'unavailable');
                    });

                }
            });
        });
    }

并且错误获取的是第486行的jquery.seat-chart.js。

jquery.seat-chart.js之

(function($) {

//'use strict'; 

$.fn.seatCharts = function (setup) {

    //if there's seatCharts object associated with the current element, return it
    if (this.data('seatCharts')) {
        return this.data('seatCharts');
    }

    var fn       = this,
        seats    = {},
        seatIds  = [],
        legend,
        settings = {
            animate : false, //requires jQuery UI
            naming  : {
                top    : true,
                left   : true,
                getId  : function(character, row, column) {
                    return row + '_' + column;
                },
                getLabel : function (character, row, column) {
                    return column;
                }

            },
            legend : {
                node   : null,
                items  : []
            },
            click   : function() {

                if (this.status() == 'available') {
                    return 'selected';
                } else if (this.status() == 'selected') {
                    return 'available';
                } else {
                    return this.style();
                }

            },
            focus  : function() {

                if (this.status() == 'available') {
                    return 'focused';
                } else  {
                    return this.style();
                }
            },
            blur   : function() {
                return this.status();
            },
            seats   : {}

        },
        //seat will be basically a seat object which we'll when generating the map
        seat = (function(seatCharts, seatChartsSettings) {
            return function (setup) {
                var fn = this;

                fn.settings = $.extend({
                    status : 'available', //available, unavailable, selected
                    style  : 'available',
                    //make sure there's an empty hash if user doesn't pass anything
                    data   : seatChartsSettings.seats[setup.character] || {}
                    //anything goes here?
                }, setup);

                fn.settings.$node = $('<div></div>');

                fn.settings.$node
                    .attr({
                        id             : fn.settings.id,
                        role           : 'checkbox',
                        'aria-checked' : false,
                        focusable      : true,
                        tabIndex       : -1 //manual focus
                    })
                    .text(fn.settings.label)
                    .addClass(['seatCharts-seat', 'seatCharts-cell', 'available'].concat(
                        //let's merge custom user defined classes with standard JSC ones
                        fn.settings.classes, 
                        typeof seatChartsSettings.seats[fn.settings.character] == "undefined" ? 
                            [] : seatChartsSettings.seats[fn.settings.character].classes
                        ).join(' '));

                //basically a wrapper function
                fn.data = function() {
                    return fn.settings.data;
                };

                fn.char = function() {
                    return fn.settings.character;
                };

                fn.node = function() {
                    return fn.settings.$node;                       
                };

                /*
                 * Can either set or return status depending on arguments.
                 *
                 * If there's no argument, it will return the current style.
                 *
                 * If you pass an argument, it will update seat's style
                 */
                fn.style = function() {

                    return arguments.length == 1 ?
                        (function(newStyle) {
                            var oldStyle = fn.settings.style;

                            //if nothing changes, do nothing
                            if (newStyle == oldStyle) {
                                return oldStyle;
                            }

                            //focused is a special style which is not associated with status
                            fn.settings.status = newStyle != 'focused' ? newStyle : fn.settings.status;
                            fn.settings.$node
                                .attr('aria-checked', newStyle == 'selected');

                            //if user wants to animate status changes, let him do this
                            seatChartsSettings.animate ?
                                fn.settings.$node.switchClass(oldStyle, newStyle, 200) :
                                fn.settings.$node.removeClass(oldStyle).addClass(newStyle);

                            return fn.settings.style = newStyle;
                        })(arguments[0]) : fn.settings.style;
                };

                //either set or retrieve
                fn.status = function() {

                    return fn.settings.status = arguments.length == 1 ? 
                        fn.style(arguments[0]) : fn.settings.status;
                };

                //using immediate function to convienietly get shortcut variables
                (function(seatSettings, character, seat) {
                    //attach event handlers
                    $.each(['click', 'focus', 'blur'], function(index, callback) {

                        //we want to be able to call the functions for each seat object
                        fn[callback] = function() {
                            if (callback == 'focus') {
                                //if there's already a focused element, we have to remove focus from it first
                                if (seatCharts.attr('aria-activedescendant') !== undefined) {
                                    seats[seatCharts.attr('aria-activedescendant')].blur();
                                }
                                seatCharts.attr('aria-activedescendant', seat.settings.id);
                                seat.node().focus();
                            }

                            /*
                             * User can pass his own callback function, so we have to first check if it exists
                             * and if not, use our default callback.
                             *
                             * Each callback function is executed in the current seat context.
                             */
                            return fn.style(typeof seatSettings[character][callback] === 'function' ?
                                seatSettings[character][callback].apply(seat) : seatChartsSettings[callback].apply(seat));
                        };

                    });
                //the below will become seatSettings, character, seat thanks to the immediate function      
                })(seatChartsSettings.seats, fn.settings.character, fn);

                fn.node()
                    //the first three mouse events are simple
                    .on('click',      fn.click)
                    .on('mouseenter', fn.focus)
                    .on('mouseleave', fn.blur)

                    //keydown requires quite a lot of logic, because we have to know where to move the focus
                    .on('keydown',    (function(seat, $seat) {

                        return function (e) {

                            var $newSeat;

                            //everything depends on the pressed key
                            switch (e.which) {
                                //spacebar will just trigger the same event mouse click does
                                case 32:
                                    e.preventDefault();
                                    seat.click();
                                    break;
                                //UP & DOWN
                                case 40:
                                case 38:
                                    e.preventDefault();

                                    /*
                                     * This is a recursive, immediate function which searches for the first "focusable" row.
                                     * 
                                     * We're using immediate function because we want a convenient access to some DOM elements
                                     * We're using recursion because sometimes we may hit an empty space rather than a seat.
                                     *
                                     */
                                    $newSeat = (function findAvailable($rows, $seats, $currentRow) {
                                        var $newRow;

                                        //let's determine which row should we move to

                                        if (!$rows.index($currentRow) && e.which == 38) {
                                            //if this is the first row and user has pressed up arrow, move to the last row
                                            $newRow = $rows.last();
                                        } else if ($rows.index($currentRow) == $rows.length-1 && e.which == 40) {
                                            //if this is the last row and user has pressed down arrow, move to the first row
                                            $newRow = $rows.first();
                                        } else {
                                            //using eq to get an element at the desired index position
                                            $newRow = $rows.eq(
                                                //if up arrow, then decrement the index, if down increment it
                                                $rows.index($currentRow) + (e.which == 38 ? (-1) : (+1))
                                            );
                                        }                                               

                                        //now that we know the row, let's get the seat using the current column position
                                        $newSeat = $newRow.find('.seatCharts-seat,.seatCharts-space').eq($seats.index($seat));

                                        //if the seat we found is a space, keep looking further
                                        return $newSeat.hasClass('seatCharts-space') ?
                                            findAvailable($rows, $seats, $newRow) : $newSeat;

                                    })($seat
                                        //get a reference to the parent container and then select all rows but the header
                                            .parents('.seatCharts-container')
                                            .find('.seatCharts-row:not(.seatCharts-header)'),
                                        $seat
                                        //get a reference to the parent row and then find all seat cells (both seats & spaces)
                                            .parents('.seatCharts-row:first')
                                            .find('.seatCharts-seat,.seatCharts-space'),
                                        //get a reference to the current row
                                        $seat.parents('.seatCharts-row:not(.seatCharts-header)')
                                    );

                                    //we couldn't determine the new seat, so we better give up
                                    if (!$newSeat.length) {
                                        return;
                                    }

                                    //remove focus from the old seat and put it on the new one
                                    seat.blur();
                                    seats[$newSeat.attr('id')].focus();
                                    $newSeat.focus();

                                    //update our "aria" reference with the new seat id
                                    seatCharts.attr('aria-activedescendant', $newSeat.attr('id'));

                                    break;                                      
                                //LEFT & RIGHT
                                case 37:
                                case 39:
                                    e.preventDefault();
                                    /*
                                     * The logic here is slightly different from the one for up/down arrows.
                                     * User will be able to browse the whole map using just left/right arrow, because
                                     * it will move to the next row when we reach the right/left-most seat.
                                     */
                                    $newSeat = (function($seats) {

                                        if (!$seats.index($seat) && e.which == 37) {
                                            //user has pressed left arrow and we're currently on the left-most seat
                                            return $seats.last();
                                        } else if ($seats.index($seat) == $seats.length -1 && e.which == 39) {
                                            //user has pressed right arrow and we're currently on the right-most seat
                                            return $seats.first();
                                        } else {
                                            //simply move one seat left or right depending on the key
                                            return $seats.eq($seats.index($seat) + (e.which == 37 ? (-1) : (+1)));
                                        }

                                    })($seat
                                        .parents('.seatCharts-container:first')
                                        .find('.seatCharts-seat:not(.seatCharts-space)'));

                                    if (!$newSeat.length) {
                                        return;
                                    }

                                    //handle focus
                                    seat.blur();    
                                    seats[$newSeat.attr('id')].focus();
                                    $newSeat.focus();

                                    //update our "aria" reference with the new seat id
                                    seatCharts.attr('aria-activedescendant', $newSeat.attr('id'));
                                    break;  
                                default:
                                    break;

                            }
                        };

                    })(fn, fn.node()));
                    //.appendTo(seatCharts.find('.' + row));

            }
        })(fn, settings);

    fn.addClass('seatCharts-container');

    //true -> deep copy!
    $.extend(true, settings, setup);        

    //Generate default row ids unless user passed his own
    settings.naming.rows = settings.naming.rows || (function(length) {
        var rows = [];
        for (var i = 1; i <= length; i++) {
            rows.push(i);
        }
        return rows;
    })(settings.map.length);

    //Generate default column ids unless user passed his own
    settings.naming.columns = settings.naming.columns || (function(length) {
        var columns = [];
        for (var i = 1; i <= length; i++) {
            columns.push(i);
        }
        return columns;
    })(settings.map[0].split('').length);

    if (settings.naming.top) {
        var $headerRow = $('<div></div>')
            .addClass('seatCharts-row seatCharts-header');

        if (settings.naming.left) {
            $headerRow.append($('<div></div>').addClass('seatCharts-cell'));
        }


        $.each(settings.naming.columns, function(index, value) {
            $headerRow.append(
                $('<div></div>')
                    .addClass('seatCharts-cell')
                    .text(value)
            );
        });
    }

    fn.append($headerRow);

    //do this for each map row
    $.each(settings.map, function(row, characters) {

        var $row = $('<div></div>').addClass('seatCharts-row');

        if (settings.naming.left) {
            $row.append(
                $('<div></div>')
                    .addClass('seatCharts-cell seatCharts-space')
                    .text(settings.naming.rows[row])
            );
        }

        /*
         * Do this for each seat (letter)
         *
         * Now users will be able to pass custom ID and label which overwrite the one that seat would be assigned by getId and
         * getLabel
         *
         * New format is like this:
         * a[ID,label]a[ID]aaaaa
         *
         * So you can overwrite the ID or label (or both) even for just one seat.
         * Basically ID should be first, so if you want to overwrite just label write it as follows:
         * a[,LABEL]
         *
         * Allowed characters in IDs areL 0-9, a-z, A-Z, _
         * Allowed characters in labels are: 0-9, a-z, A-Z, _, ' ' (space)
         *
         */

        $.each(characters.match(/[a-z_]{1}(\[[0-9a-z_]{0,}(,[0-9a-z_ ]+)?\])?/gi), function (column, characterParams) { 
            var matches         = characterParams.match(/([a-z_]{1})(\[([0-9a-z_ ,]+)\])?/i),
                //no matter if user specifies [] params, the character should be in the second element
                character       = matches[1],
                //check if user has passed some additional params to override id or label
                params          = typeof matches[3] !== 'undefined' ? matches[3].split(',') : [],
                //id param should be first
                overrideId      = params.length ? params[0] : null,
                //label param should be second
                overrideLabel   = params.length === 2 ? params[1] : null;

            $row.append(character != '_' ?
                //if the character is not an underscore (empty space)
                (function(naming) {

                    //so users don't have to specify empty objects
                    settings.seats[character] = character in settings.seats ? settings.seats[character] : {};

                    var id = overrideId ? overrideId : naming.getId(character, naming.rows[row], naming.columns[column]);
                    seats[id] = new seat({
                        id        : id,
                        label     : overrideLabel ?
                            overrideLabel : naming.getLabel(character, naming.rows[row], naming.columns[column]),
                        row       : row,
                        column    : column,
                        character : character
                    });

                    seatIds.push(id);
                    return seats[id].node();

                })(settings.naming) :
                //this is just an empty space (_)
                $('<div></div>').addClass('seatCharts-cell seatCharts-space')   
            );
        });

        fn.append($row);
    });

    //if there're any legend items to be rendered
    settings.legend.items.length ? (function(legend) {
        //either use user-defined container or create our own and insert it right after the seat chart div
        var $container = (legend.node || $('<div></div>').insertAfter(fn))
            .addClass('seatCharts-legend');

        var $ul = $('<div class="row"></div>')
            .addClass('seatCharts-legendList')
            .appendTo($container);

        $.each(legend.items, function(index, item) {
            $ul.append(
                $('<div class="col-md-2 col-xs-2"></div>')
                    .addClass('seatCharts-legendItem')
                    .append(
                        $('<div></div>')
                            //merge user defined classes with our standard ones
                            .addClass(['seatCharts-seat', 'seatCharts-cell', item[1]].concat(
                                settings.classes, 
                                typeof settings.seats[item[0]] == "undefined" ? [] : settings.seats[item[0]].classes).join(' ')
                            )
                    )
                    .append(
                        $('<span></span>')
                            .addClass('seatCharts-legendDescription')
                            .text(item[2])
                    )
            );
        });

        return $container;
    })(settings.legend) : null;

    fn.attr({
        tabIndex : 0
    });


    //when container's focused, move focus to the first seat
    fn.focus(function() {
        if (fn.attr('aria-activedescendant')) {
            seats[fn.attr('aria-activedescendant')].blur();
        }

        fn.find('.seatCharts-seat:not(.seatCharts-space):first').focus();
        seats[seatIds[0]].focus();

    });

    //public methods of seatCharts
    fn.data('seatCharts', {
        seats   : seats,
        seatIds : seatIds,
        //set for one, set for many, get for one
        status: function() {
            var fn = this;

            return arguments.length == 1 ? fn.seats[arguments[0]].status() : (function(seatsIds, newStatus) {

                return typeof seatsIds == 'string' ? fn.seats[seatsIds].status(newStatus) : (function() {
                    $.each(seatsIds, function(index, seatId) {
                        fn.seats[seatId].status(newStatus);
                    });
                })();
            })(arguments[0], arguments[1]);
        },
        each  : function(callback) {
            var fn = this;

            for (var seatId in fn.seats) {
                if (false === callback.call(fn.seats[seatId], seatId)) {
                    return seatId;//return last checked
                }
            }

            return true;
        },
        node       : function() {
            var fn = this;
            //basically create a CSS query to get all seats by their DOM ids
            return $('#' + fn.seatIds.join(',#'));
        },

        find       : function(query) {//D, a.available, unavailable
            var fn = this;

            var seatSet = fn.set();

            //is RegExp
                    return query instanceof RegExp ?
                        (function () {
                            fn.each(function (id) {
                                if (id.match(query)) {
                                    seatSet.push(id, this);
                                }
                            });
                            return seatSet;
                        })() :
                        (query.length == 1 ?
                                (function (character) {
                                    //user searches just for a particual character
                                    fn.each(function () {
                                        if (this.char() == character) {
                                            seatSet.push(this.settings.id, this);
                                        }
                                    });

                                    return seatSet;
                                })(query) :
                                (function () {
                                    //user runs a more sophisticated query, so let's see if there's a dot
                                    return query.indexOf('.') > -1 ?
                                        (function () {
                                            //there's a dot which separates character and the status
                                            var parts = query.split('.');

                                            fn.each(function (seatId) {
                                                if (this.char() == parts[0] && this.status() == parts[1]) {
                                                    seatSet.push(this.settings.id, this);
                                                }
                                            });

                                            return seatSet;
                                        })() :
                                        (function () {
                                            fn.each(function () {
                                                if (this.status() == query) {
                                                    seatSet.push(this.settings.id, this);
                                                }
                                            });
                                            return seatSet;
                                        })();
                                })()
                        );

        },
        set        : function set() {//inherits some methods
            var fn = this;

            return {
                seats      : [],
                seatIds    : [],
                length     : 0,
                status     : function() {
                    var args = arguments,
                        that = this;
                    //if there's just one seat in the set and user didn't pass any params, return current status
                    return this.length == 1 && args.length == 0 ? this.seats[0].status() : (function() {
                        //otherwise call status function for each of the seats in the set
                        $.each(that.seats, function() {
                            this.status.apply(this, args);
                        });
                    })();
                },
                node       : function() {
                    return fn.node.call(this);
                },
                each       : function() {
                    return fn.each.call(this, arguments[0]);
                },
                get        : function() {
                    return fn.get.call(this, arguments[0]);
                },
                find       : function() {
                    return fn.find.call(this, arguments[0]);
                },
                set       : function() {
                    return set.call(fn);
                },
                push       : function(id, seat) {
                    this.seats.push(seat);
                    this.seatIds.push(id);
                    ++this.length;
                }
            };
        },
        //get one object or a set of objects
        get   : function(seatsIds) {
            var fn = this;

            return typeof seatsIds == 'string' ? 
                fn.seats[seatsIds] : (function() {

                    var seatSet = fn.set();

                    $.each(seatsIds, function(index, seatId) {
                        if (typeof fn.seats[seatId] === 'object') {
                            seatSet.push(seatId, fn.seats[seatId]);
                        }
                    });

                    return seatSet;
                })();
        }
    });

    return fn.data('seatCharts');
}

})(jQuery的);

1 个答案:

答案 0 :(得分:0)

因为sc.status(par1,par2)预期第一个par1格式为'Row_Col'而第二个par2格式为不可用。我必须将par1格式的座位号转换为:

$.each(response1.bookings, function (index, booking) {
var seat_n = convertSeat(booking.seat_id);
sc.get(seat_n).status('unavailable');
});

<强> convertSeat()

function convertSeat(seat_number) {
        if(seat_number <= 29){
            var seat_node = 'A_'+seat_number;
            return seat_node;
        }
        else if(seat_number <= 58){
            var seat = seat_number - 29;
            var seat_node = 'B_'+seat;
            return seat_node;
        }
        else if(seat_number <= 87){
            var seat = seat_number - 58;
            var seat_node = 'C_'+seat;
            return seat_node;
        }
        else if(seat_number <= 116){
            var seat = seat_number - 87;
            var seat_node = 'D_'+seat;
            return seat_node;
        }
        else if(seat_number <= 145){
            var seat = seat_number - 116;
            var seat_node = 'E_'+seat;
            return seat_node;
        }
        else if(seat_number <= 174){
            var seat = seat_number - 145;
            var seat_node = 'F_'+seat;
            return seat_node;
        }
        else if(seat_number <= 203){
            var seat = seat_number - 174;
            var seat_node = 'G_'+seat;
            return seat_node;
        }
        else if(seat_number <= 232){
            var seat = seat_number - 203;
            var seat_node = 'H_'+seat;
            return seat_node;
        }
        else if(seat_number <= 261){
            var seat = seat_number - 232;
            var seat_node = 'I_'+seat;
            return seat_node;
        }
        else if(seat_number <= 290){
            var seat = seat_number - 261;
            var seat_node = 'J_'+seat;
            return seat_node;
        }
        else if(seat_number <= 319){
            var seat = seat_number - 290;
            var seat_node = 'K_'+seat;
            return seat_node;
        }
        else if(seat_number <= 348){
            var seat = seat_number - 319;
            var seat_node = 'L_'+seat;
            return seat_node;
        }
        else if(seat_number <= 377){
            var seat = seat_number - 348;
            var seat_node = 'M_'+seat;
            return seat_node;
        }
        else if(seat_number <= 406){
            var seat = seat_number - 377;
            var seat_node = 'N_'+seat;
            return seat_node;
        }
        else if(seat_number <= 435){
            var seat = seat_number - 406;
            var seat_node = 'O_'+seat;
            return seat_node;
        }
        else if(seat_number <= 464){
            var seat = seat_number - 435;
            var seat_node = 'P_'+seat;
            return seat_node;
        }
        else if(seat_number <= 493){
            var seat = seat_number - 464;
            var seat_node = 'Q_'+seat;
            return seat_node;
        }
        else if(seat_number <= 522){
            var seat = seat_number - 493;
            var seat_node = 'R_'+seat;
            return seat_node;
        }
        else if(seat_number <= 551){
            var seat = seat_number - 522;
            var seat_node = 'S_'+seat;
            return seat_node;
        }
    }