最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - BookYourSeat: Automatic Seat Selection on Click using AngularJS [GIF] - Stack Overflow

programmeradmin3浏览0评论

BookyourSeat:

It is an angularJs app that helps you book your seats for a movie show similar to bookmyshow .

]

What the User Can Do (User Cases)?

  1. Select and Deselect the Seats with respect to the selectedVal, i.e if the selectedVal = 4 then the user can select only 4 seats in total.

  2. if the SelectedVal is less than 1 then the user should not be able to select the seat anymore unless the user deselect any of the previously selected seats and select again.

  3. Booked Seats Case: If the check value of a seat is true, then the user should not be able to select or deselect that seat(a.blocked CSS rule is Added for that purpose) since it is already selected by another user(Lets assume).

Automatic Seat Selection Cases

As shown in the GIF

  1. If the user selects 3 seats and click on the first seat in the first row it should automatically select 2 and 3 on the same row.

  1. If the user Selects 3 seats and clicks on the second last seat in the row then last two seats should be filled and the remaining seat should be filled where ever the user clicks.

  1. If the user selects 3 seats and clicks on only the last seat then only that seat should be filled.

In case of 4 seats.

Problem:

I am able to achieve the automatic selection process using angular.forEach() but cannot all the logics correctly.

$scope.execute = function(i, j, itemVal, itemLetter) {
        angular.forEach($scope.obj, function(v, k) {
          if (v[i].val == itemVal && v[i].letter == itemLetter) {
            if (v[i].seat == true || ($scope.isDisabled && v[i].check == false)) {
              return;
            }
            v[i].check = !v[i].check;
            if (v[i].check)
              $scope.selectedVal -= 1;
            else
              $scope.selectedVal += 1;

           //seatSelection
            var m = i;
            for (var l = 0; l < $scope.selectedVal; l++)
              v[m++].check = true;
                //seatSelectionEnd

            console.log(itemVal + " " + itemLetter);
            if ($scope.selectedVal < 1) {
              $scope.isDisabled = true;
            } else {
              $scope.isDisabled = false;
            }
          }
        });
      };
    }])

Working Fiddle: /

BookyourSeat:

It is an angularJs app that helps you book your seats for a movie show similar to bookmyshow .

]

What the User Can Do (User Cases)?

  1. Select and Deselect the Seats with respect to the selectedVal, i.e if the selectedVal = 4 then the user can select only 4 seats in total.

  2. if the SelectedVal is less than 1 then the user should not be able to select the seat anymore unless the user deselect any of the previously selected seats and select again.

  3. Booked Seats Case: If the check value of a seat is true, then the user should not be able to select or deselect that seat(a.blocked CSS rule is Added for that purpose) since it is already selected by another user(Lets assume).

Automatic Seat Selection Cases

As shown in the GIF

  1. If the user selects 3 seats and click on the first seat in the first row it should automatically select 2 and 3 on the same row.

  1. If the user Selects 3 seats and clicks on the second last seat in the row then last two seats should be filled and the remaining seat should be filled where ever the user clicks.

  1. If the user selects 3 seats and clicks on only the last seat then only that seat should be filled.

In case of 4 seats.

Problem:

I am able to achieve the automatic selection process using angular.forEach() but cannot all the logics correctly.

$scope.execute = function(i, j, itemVal, itemLetter) {
        angular.forEach($scope.obj, function(v, k) {
          if (v[i].val == itemVal && v[i].letter == itemLetter) {
            if (v[i].seat == true || ($scope.isDisabled && v[i].check == false)) {
              return;
            }
            v[i].check = !v[i].check;
            if (v[i].check)
              $scope.selectedVal -= 1;
            else
              $scope.selectedVal += 1;

           //seatSelection
            var m = i;
            for (var l = 0; l < $scope.selectedVal; l++)
              v[m++].check = true;
                //seatSelectionEnd

            console.log(itemVal + " " + itemLetter);
            if ($scope.selectedVal < 1) {
              $scope.isDisabled = true;
            } else {
              $scope.isDisabled = false;
            }
          }
        });
      };
    }])

Working Fiddle: https://jsfiddle/rittamdebnath/5vqxgtq3/11/

Share Improve this question asked Jun 13, 2016 at 18:24 rittamrittam 3181 gold badge3 silver badges14 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 1

Your looping logic is a bit difficult to follow, but more critically, unnecessary. Instead of a click function that loops through the whole collection, have it just interact directly with the object bound to the element being clicked.

Change your anchor element binding to this: ng-click="clickSeat(item)", and use a function on the controller like this:

$scope.clickSeat = function(seat) {
    if (!seat.seat && !$scope.isDisabled) {
      if (seat.check) {
        seat.check = false;
        $scope.selectedSeatCount--;
      } else if ($scope.selectedSeatCount < $scope.selectedVal) {
        seat.check = true;
        $scope.selectedSeatCount++;
      }
    }
}

Here's an updated fiddle: https://jsfiddle/5vqxgtq3/12/

I don't know if this captures all the functionality you're looking for, but hopefully effectively demonstrates how the logic is easier to reason when it's no longer relying on a loop, and you can expand upon it from there.

I've changed your code with the following points to implement the logic:

  • changed model to 2d-Array style. seats = [ [Obj0, Obj1, Obj2], [Obj3, Obj4, Obj5] ]
  • calculated distance to border = how many seats to select for current row. Then we can calculate the rest of the available seats for current count.
  • added rang property to create the sections for different row groups.

I think I've implemented all your use cases.

Please have a look at the demo below or at this fiddle.

My code is pretty plicated as well but I think the loops are required because of the updating of the other selections.

angular.module('bookYourSeatApp', [])
	.factory('seats', SeatsFactory)
    .controller('mainCtrl', MainCtrl);

function SeatsFactory($rootScope, $timeout) {
	var seatProps = {
    	id: 0,
    	caption: 0,
        checked: false,
        booked: false
    };
	var seats = {
    	'firstRang': {
            //           col0 1 2 3 4  5 
        	// row 0 seat 0   1 2 3 4  5
            // row 1 seat 6   7 8 9 10 11
            seats: createSeats(2, 6) // rows, cols
        },
        'secondRang': {
        	seats: createSeats(3, 6)
        }
    };
    
    function createSeats(rows, cols) {
    	var arr = [[]];
        var seatIndex = 0;
        for (var row = 0; row < rows; row++) {
        	arr[row] = [];
            for(var col=0; col < cols; col++) {
            	var seat = angular.extend({}, seatProps, {
                	id: seatIndex,
                    caption: seatIndex,
                    booked: seatIndex < 5 // 0 to 5 booked
                });
            	arr[row][col] = seat;
                seatIndex++;
            }
        }
        return arr;
    }
    
	function checkSelected(newCount) {
    	// selected fewer or more than persons in select.
        // --> uncheck all
        var checkedCount=0, keys = Object.keys(seats);
        for (var rang=0; rang < keys.length; rang++) {
        	var key = keys[rang];
        	var curSeats = seats[key].seats;
            for (var row=0; row < curSeats.length; row++) {
                for (var col=0; col < curSeats[row].length; col++) {
                    if ( curSeats[row][col].checked ) {
                        checkedCount++;
                    }
                }
            }
            //console.log('new count', newCount, checkedCount);
            // we can have more or less selections after selection change
            // --> more inc availCount
            if (checkedCount === 0) {
            	// nothing selected
                factory.availCount = angular.copy(newCount);
            }
            else if (newCount.val > checkedCount) {
            	//console.log('add delta', newCount, checkedCount)
            	factory.availCount.val = (newCount.val - checkedCount);
            } else {
            	removeAllCheck();
            }
        }
    }
    
	function removeCheck(rang) {
    	// later pass user to this function (for now remove all checked)
        /*var curSeats = seats[rang].seats
        for (var row=0; row < curSeats.length; row++) {
            for (var col=0; col < curSeats[row].length; col++) {
            	curSeats[row][col].checked = false;
            }
        }*/
        keys = Object.keys(seats);
        
        for (var rang=0; rang < keys.length; rang++) {
        	var key = keys[rang];
        	var curSeats = seats[key].seats;
            for (var row=0; row < curSeats.length; row++) {
                for (var col=0; col < curSeats[row].length; col++) {
                    curSeats[row][col].checked = false;
                }
            }
        }
    }
    
    function removeAllCheck() {
     	keys = Object.keys(seats);
    	for (var rang=0; rang < keys.length; rang++) {
        	var key = keys[rang];
        	var curSeats = seats[key].seats;
            for (var row=0; row < curSeats.length; row++) {
                for (var col=0; col < curSeats[row].length; col++) {
                    curSeats[row][col].checked = false;
                }
            }
        }
    }
    
    function selectSeats(selection, count) {
    	// todo:
        // check distance to border, keep the rest as clickable
        // selection = {rang, row, seat}
		console.log(selection);
        var row = selection.row,
        	seat = selection.seat;
        
        if ( !seat.booked ) {
            //console.log('availCount', factory.availCount);
            if ( factory.availCount.val == 0 ) {
                //console.log('new selection');
                factory.availCount = angular.copy(count);
                removeCheck(); //selection.rang);
            }

            var borderDistance = row.length - row.indexOf(seat),
            	rest = borderDistance > count.val ? 0:  count.val - borderDistance;
                
			if ( factory.availCount.val === count.val) {
                // first click
                var lastIndex = rest > 0 ? row.length: row.indexOf(seat) + count.val;
                for ( var seatIndex = row.indexOf(seat); seatIndex < lastIndex; seatIndex++) {
                    row[seatIndex].checked = true;
                }
                factory.availCount.val = rest; // update available seats
            } 
            else {
                // second click dec. availCounter
                // single change of seats
                /*if ( factory.availCount.val < 0 ) {
                    row[row.indexOf(seat)].checked = false; // remove check
                    factory.availCount.val++;
                }
                else {*/
                if ( !row[row.indexOf(seat)].checked ) {
                	// only if not already checked
                    row[row.indexOf(seat)].checked = true;
                    if ( factory.availCount.val > 0 ) {
                        factory.availCount.val--;
                    }
                 }
                //}
            }
        }
    }
    
	var factory = {
    	map: seats,
        select: selectSeats,
        availCount: {},
        setAvailCount: function(count) {
        	console.log('avail', count);
            checkSelected(count);
        }
    };
    
    return factory
}

function MainCtrl(seats) {
	var vm = this;
    angular.extend(vm, {
    	seats: seats,
        selectionCount: [//[0,1,2,3,4],[
        {id: 0, val: 0}, // object for two-way binding
        {id: 1, val: 1},
        {id: 2, val: 2},
        {id: 3, val: 3},
        {id: 4, val: 4},
        ],
        selectedCount: 0
    });
    
    vm.selectedCount = vm.selectionCount[2];
    seats.setAvailCount(vm.selectedCount);
}
table {
    border: 1px solid black;
    padding: 0.5em;
}

td {
    padding: 1em;
    border: 2px solid gray;
}

td:hover {
    cursor: default;
    background-color: gray;
}

.active {
    border: 2px solid lightgreen;
    border-radius: 5px;
}

.booked {
    background-color: lightgray;
}
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="bookYourSeatApp" ng-controller="mainCtrl as ctrl">
    <label>Persons <select ng-model="ctrl.selectedCount" ng-change="ctrl.seats.setAvailCount(ctrl.selectedCount)" ng-options="count as count.val for count in ctrl.selectionCount"></select></label>
    Seats left: {{ctrl.seats.availCount.val}}<br/>
    <table ng-repeat="(key, rang) in ctrl.seats.map">
        <tr ng-repeat="row in rang.seats">
            <td ng-repeat="seat in row" ng-class="{'active': seat.checked, 'booked': seat.booked}" ng-click="ctrl.seats.select({rang:key, row:row, seat: seat}, ctrl.selectedCount)">
                {{seat.caption}}
            </td>
        </tr>
    </table>
    <pre>{{ctrl.seats.map | json : 2}}</pre>
</div>

发布评论

评论列表(0)

  1. 暂无评论