BookYourSeat:使用 AngularJS 点击时自动选择座位 [GIF]
Posted
技术标签:
【中文标题】BookYourSeat:使用 AngularJS 点击时自动选择座位 [GIF]【英文标题】:BookYourSeat: Automatic Seat Selection on Click using AngularJS [GIF] 【发布时间】:2016-10-14 06:46:13 【问题描述】:预订您的座位:
这是一个 angularJs 应用程序,可帮助您为类似于 bookmyshow 的电影节目预订座位。
]
用户可以做什么(用户案例)?
相对于 selectedVal 选择和取消选择席位,即如果 selectedVal = 4 则用户总共只能选择 4 个席位。
如果 SelectedVal 小于 1,那么用户应该不能 不再选择座位,除非用户取消选择任何 之前选择的座位,然后再次选择。
预订座位案例:如果座位的检查值为真,则 用户不应该能够选择或取消选择该座位(a.blocked 为此目的添加了 CSS 规则),因为它已经被 另一个用户(假设)。
自动选座案例
如 GIF 所示
-
如果用户选择 3 个座位并点击第一行的第一个座位,它应该会自动选择同一行的 2 和 3。
-
如果用户选择 3 个座位并单击该行中倒数第二个座位,则应填充最后两个座位,并且应在用户单击的任何位置填充剩余的座位。
-
如果用户选择 3 个席位并仅单击最后一个席位,则应仅填充该席位。
如果是 4 个座位。
问题:
我可以使用angular.forEach()
实现自动选择过程,但不能正确地完成所有逻辑。
$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;
);
;
])
工作小提琴:https://jsfiddle.net/rittamdebnath/5vqxgtq3/11/
【问题讨论】:
【参考方案1】:您的循环逻辑有点难以理解,但更关键的是,没有必要。而不是循环遍历整个集合的点击函数,让它直接与绑定到被点击元素的对象交互。
将您的锚元素绑定更改为:ng-click="clickSeat(item)"
,并在控制器上使用如下函数:
$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++;
这是一个更新的小提琴:https://jsfiddle.net/5vqxgtq3/12/
我不知道这是否捕获了您正在寻找的所有功能,但希望能有效地展示逻辑在不再依赖循环时如何更容易推理,并且您可以从那里扩展它。
【讨论】:
【参考方案2】:我已将您的代码更改为以下几点来实现逻辑:
将模型更改为二维阵列样式。seats = [ [Obj0, Obj1, Obj2], [Obj3, Obj4, Obj5] ]
计算到边界的距离 = 为当前行选择的座位数。然后我们可以计算当前剩余的可用座位数。
添加了rang
属性来为不同的行组创建部分。
我想我已经实现了你所有的用例。
请看下面的演示或fiddle。
我的代码也很复杂,但我认为循环是必需的,因为更新了其他选择。
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.com/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>
【讨论】:
好的,请看at the fork https://github.com/AWolf81/BookYourSeats/tree/devel。我已经添加了演示中的代码,并进行了一些修改,以实现您的座位布局。 感谢您的精彩贡献,但我在问题中列出的问题很少。 github.com/rittamdebnath/BookYourSeats/issues 能否请您解决问题并尽快推送。谢谢你:)以上是关于BookYourSeat:使用 AngularJS 点击时自动选择座位 [GIF]的主要内容,如果未能解决你的问题,请参考以下文章