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]的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS进阶(三十三)书海拾贝之简介AngularJS中使用factory和service的方法

angularjs插件怎么使用

AngularJS学习之旅—AngularJS 服务

使用 webpack 导入 angularjs 模块

AngularJS

angularjs学习之八(angularjs中isolate scope的使用)