Angular 范围和 ng-click / ng-show 设置多个 div

Angular scope and ng-click / ng-show to set multiple divs

我正在为我目前的代码寻求一些帮助。

主要的 objective 是能够单击任何加号图标并使其覆盖所有其他 div 块。

当点击加号图标时,它还会在右侧显示一个 div 块。

正如您在单击块 2 时看到的那样,它会执行所有预期的操作。

我正在寻找一种在单击任何加号图标时使用 Angular 执行此操作的有效方法。

这只是我在这里展示的一个小样本,实际上需要覆盖 10 到 20 个块。

如果有人能在这里看到一种使用更少代码并更好地利用作用域的方法,将不胜感激。

我已经看过许多选项,例如 post here

试过这个但它不想工作...

data-ng-class="{coverThisBlock: value2 == 'off',coverThisBlock: value == 'on'}"

如果我不得不对 10 个块使用这种类型的选项,那将是一个真正的混乱。

主要问题

是否有更好的 Angular 方法来实现此功能...单击任何加号图标时,它会更改范围以供 ngclass 和 ng-show 使用?

如何正确连接此示例的示波器?

非常感谢。

我已经设置了一个工作 FIDDLE HERE

这是 Avijit Gupta 的最终工作示例

<div class="container" ng-app="plusMinusApp"  ng-controller="plusMinusController">

<div class="row" ng-init="value1 = 'off'">
 <!--<div class="col-xs-4" data-ng-class="{coverThisBlock: value2 == 'off',coverThisBlock: value == 'on'}"> --> 
    <div class="col-sm-4 col-xs-6" data-ng-class="{coverThisBlock: value2 == 'off'}">    
        <div class="divClass" 
        data-ng-click="(selectBlock(1)) ; (status1 = !status1) ; (value1 = { 'on': 'off', 'off':'on'}[value1])" 
        data-ng-class="{'active-selection': status1 == activeClass}">
        1
        </div>
        <i ng-click="(selectBlock(1)) ; (status1 = !status1) ; (value1 = { 'on': 'off', 'off':'on'}[value1])" 
        class="btn btn-primary text-center fa" 
        ng-class="{'fa-minus': status1, 'fa-plus': !status1}"></i>
    </div>
    <div  ng-show="value1 == 'on'" class="col-xs-4 textdiv">Hello</div>
</div>

<div class="row" >
    <div class="col-sm-4 col-xs-6" ng-init="value2 = 'on'">    
        <div class="divClass" 
        data-ng-click="(value2 = { 'on': 'off', 'off':'on'}[value2])" 
        data-ng-class="{'active-selection': value2 == 'off'}">
        2
        </div>
        <i ng-click="(value2 = { 'on': 'off', 'off':'on'}[value2])" 
        class="btn btn-primary text-center fa" 
        ng-class="{'fa-minus': (value2 == 'off'), 'fa-plus': value2}"></i>
    </div>
    <div  ng-show="value2 == 'off'" class="col-xs-3 textdiv">Hello</div>
</div>

<div class="row">  
    <div class="col-sm-4 col-xs-6" data-ng-class="{'coverThisBlock': value2 == 'off'}">    
        <div class="divClass" 
        data-ng-click="(selectBlock(3)) ; (status3 = !status3)" 
        data-ng-class="{'active-selection': !status3 == activeClass}">
        3
        </div>
        <i ng-click="(selectBlock(3)) ; (status3 = !status3)" 
        class="btn btn-primary text-center fa" 
        ng-class="{'fa-minus': status3, 'fa-plus': !status3}"></i>
    </div>
</div>

<div class="row"> 
    <div class="col-sm-4 col-xs-6" data-ng-class="{'coverThisBlock': value2 == 'off'}">    
        <div class="divClass" 
        data-ng-click="(selectBlock(1)) ; (status4 = !status4)" 
        data-ng-class="{'active-selection': status4 == activeClass}">
        4
        </div>
        <i ng-click="(selectBlock(1)) ; (status4 = !status4)" 
        class="btn btn-primary text-center fa" 
        ng-class="{'fa-minus': status4, 'fa-plus': !status4}"></i>
    </div>
    <div  ng-show="status4" class="col-xs-4 textdiv">Hello</div>   
</div>

<div class="row" ng-init="value = 'off'">
    <div class="col-sm-4 col-xs-6" data-ng-class="{'coverThisBlock': value2 == 'off'}">    
        <div class="divClass" 
        data-ng-click="(selectBlock(1)) ; (status = !status) ; (value = { 'on': 'off', 'off':'on'}[value])" 
        data-ng-class="{'active-selection': status == activeClass}">
        5
        </div>
        <i ng-click="(selectBlock(1)) ; (status = !status) ; (value = { 'on': 'off', 'off':'on'}[value])" 
        class="btn btn-primary text-center fa" 
        ng-class="{'fa-minus': status, 'fa-plus': !status}"></i>
    </div>
    <div  ng-show="value == 'on'" class="col-xs-4 textdiv">Hello</div>
</div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="js/plusMinusApp.j"></script>
<script>

var myModule = angular.module('plusMinusApp', []);
myModule.controller('plusMinusController', function ($scope) {

    $scope.status  = false;    
    $scope.status1 = false;
    $scope.status2 = false;
    $scope.status3 = false;
    $scope.status4 = false;    

$scope.blocks = [{
    id: '1',
    block: "1",
  }, {
    id: '2',
    block: "2",
  }, {
    id: '3',
    block: "3",
  }, {
    id: '4',
    block: "4",
  }, {
    id: '5',
    block: "5"
  }];
 // $scope.activeClass = 0;  
  $scope.selectBlock = function(id) {
    $scope.activeClass = id;
    console.log(id);
  };  
});    
</script>  

回答要用 NG-REPEAT 做的问题

ng-repeat 可以对每个不同的 div

使用多个 css 类

显然可以。

像这样使用范围 id...

<div class="block-{{block.id}}">

和 css 这样的...

.block-1 {...

WORKING FIDDLE OF THIS HERE

编辑(根据提问者的评论)

UPDATED FIDDLE

  1. 一次只能点击一个?或者,如果另一个是 open/clicked,第一个打开的将被重置并关闭

这将您的代码简化了将近 2 倍。

初始状态:

  • None 个块已 selected。
  • None 个块被覆盖。

代码:

$scope.setToInitialState = function() {
  $scope.blocks.forEach(function(block) {
    $scope.isSelected[block.id] = false;
    $scope.isCovered[block.id] =  false;
  });
};

触摸状态:

  • 切换被点击方块的 selected 状态。 (在 select 和 deselect 之间切换)。
  • 如果select已编辑,则覆盖并删除select所有其他块。
  • 如果删除select,则将应用程序恢复到初始状态。

代码:

$scope.selectBlock = function(id) {
  $scope.isSelected[id] = !$scope.isSelected[id];
  $scope.isCovered[id] = false;
  if ($scope.isSelected[id]) {
    $scope.blocks.forEach(function(block) {
      if (block.id !== id) {
        $scope.isCovered[block.id] = true;
        $scope.isSelected[block.id] = false;
      }    
    });
  }
  else {
    $scope.setToInitialState();
  }
};
  1. demo中使用的都是相同的设置块大小,但实际使用的所有div块都是不同的高度和宽度。每个块都是不同的图像

您应该考虑使用 ng-src

我假设您可能正在从数据库中检索所有这些内容。然后,如果可能的话,您可以将每张图片放在固定大小的 div 中,这样它们的大小都相同。

  1. 此外,显示器 div分为 2 个垂直半屏部分

稍微调整 css 即可设置。


原始答案

WORKING FIDDLE

假设您的应用有两种状态:

  1. 初始状态(未触及)
  2. 触摸状态

最初,您处于初始状态:

  • 没有显示正确的 div。
  • 所有图标都是'plus'(没有'minus')
  • None 个块被覆盖。

代码:

$scope.setToInitialState = function() {
  $scope.plusCount = 0;
  $scope.blocks.forEach(function(block) {
    $scope.isPlus[block.id] = true;
    $scope.isShowDiv[block.id] = false;
    $scope.isCoverBlock[block.id] = false;
    $scope.plusCount += 1;
  });
};

当你处于Touched状态时:

  • 所有这些块都被覆盖,它们有一个 'plus' 图标。
  • 仅显示那些块的右侧 div,未被覆盖。

代码:

// Run when user clicks on the 'plus' or 'minus' icon.
$scope.selectBlock = function(id) {
  $scope.isPlus[id] = !$scope.isPlus[id]; // toggle between 'plus' and 'minus' icons
  if ($scope.isPlus[id]) {
    $scope.plusCount += 1;
  }
  else {
    $scope.plusCount -= 1;
  }
  $scope.blocks.forEach(function(block) {

    if ($scope.isPlus[block.id]) {
      $scope.isCoverBlock[block.id] = true;
    }
    else {    
      $scope.isCoverBlock[block.id] = false;
    }
    $scope.isShowDiv[block.id] = !$scope.isCoverBlock[block.id];

  });
};

所以,基本上当用户与视图交互并实际点击图标时,然后 he/she 转到 touched state(上面的代码是 运行)。

只有当所有的图标都是'plus'时,才必须将用户发送到initial state:

if ($scope.plusCount === $scope.blocks.length) {
  $scope.setToInitialState();
}

html的变化:

  1. 在最外层div加上ng-init="setToInitialState()",这样一开始我们就处于初始状态

代码:

<div class="container" ng-app="plusMinusApp"  ng-controller="plusMinusController" ng-init="setToInitialState()">
  1. 每个块使用ng-repeat代替copy-pasting代码:

代码:

<div class="row" ng-repeat="block in blocks">
    <div class="col-sm-4 col-xs-6" data-ng-class="{ 'coverThisBlock': isCoverBlock[block.id]}">    
        <div class="divClass" 
        data-ng-class="{'active-selection': !isPlus[block.id]}">
        {{block.id}}
        </div>
        <i data-ng-click="selectBlock(block.id)" 
        class="btn btn-primary text-center fa" 
        data-ng-class="{'fa-minus': !isPlus[block.id], 'fa-plus': isPlus[block.id]}"></i>
    </div>
    <div data-ng-show="isShowDiv[block.id]" class="col-xs-3 textdiv">Hello</div>
</div>

希望对您有所帮助!

更新

拍,一次只有一个。好吧...我写的几乎所有内容都适用。

New Fiddle

所以唯一的区别是 JS。我们有一个代表 所选块 .

的数字,而不是选定的 块数组
this.blocks = Array.apply(null, Array(10)).map(function (val, index) {return index;});

this.activeIndex = null;

this.isActive = function(index) {
    return that.activeIndex === index;
};

this.hasSelected = function() {
    return that.activeIndex !== null;
};

this.selectBlock = function(index) {

    if (that.activeIndex === index) {
        that.activeIndex = null;
    } else {
        that.activeIndex = index;
    }

};

看,好的 JS 代码很容易维护,即使需求发生变化(或者当我发现它们发生变化时)也是如此。

(We actually can get by without these helper functions, but we use them for the sake of prettier code and maybe encapsulation.)


原答案

Fiddle here

我希望我已经解释了为什么我们应该在 fiddle 中做这些事情,并给出了可信的 references/further 阅读 material。

要事第一

  • 不要使用 $scope。我喜欢 controller as 语法。基本上,在 JS 中,你使用 this.prop 和 HTML,你使用 myCtrlAs.propDocs
  • 这是一个 CSS 问题。趁着:not()

两条原则:KISS and DRY

所以我们遇到了相同 copy-pasted 代码块的问题。正如@avijit 所说,您应该使用 ng-repeat 指令。

<div class="row" ng-repeat="block in plusMinus.blocks track by $index">
    //This entire block will be repeated
</div>

对于每一行,我们需要跟踪它是否被选中。遵循 KISS 原则,我们唯一需要跟踪的状态就是这个

否则,事情会变得太复杂。

  //each element represents the state of a row
  this.blocks = [0,0,0,0,0]; 

所以这个块数组用于ng-repeat


你问,我们将如何跟踪什么变暗什么是活跃的?

答案是....等等


你没有


相反,我们使用位于控制器上的函数来获取有关单个 blocks 变量的信息。你可以反对我的措辞,但请注意我是怎么说“keep track”的?同样,不要存储重复的状态数据。根据我以前的经验,这变成了一场噩梦。

(我们实际上可以不用这些辅助函数,但我们使用它们是为了更漂亮的代码和封装。)

所以我要指出的第一个功能:

this.hasSelected = function() {
  return that.blocks.indexOf(true) !== -1;
};

这是做什么用的?你猜到了!确定我们是否应该 "cover up" 未选中的行。

使用CSS——有趣有用!

所以我们有条件地将 .has-selected class 应用于包装器。

因此 "cover" 仅在其具有 .has-selected 的祖先时适用,我们有

has-selected :not(.active) > .col-sm-4 {
  width: 33%;
  height: inherit;
  background-color: rgba(00,00,00,0.8);
  z-index: 9;
}
.has-selected :not(.active) .col-sm-4 {
  @media (max-width:420px){
    width: 80%;
  }
}  

回到ng-repeat

哦,到这里你应该知道了$index是用来访问ng-repeat中当前HTML的索引的。 (文档和 SO Thread

<div class="label-index" data-ng-class="{'active-selection': !plusMinus.isActive($index)}">
          {{$index}}
</div>

结束语

  • 阅读文档
  • 不要试图用一种工具做所有事情
  • 如果你觉得我解释得不是特别好,尽管问。

另外,我想我搞砸了一些造型。希望大家自行解决。

您可以在下面的代码片段中找到最佳解决方案

angular.module('plusMinusApp', [])
 .controller('plusMinusController', function ($scope) {
  $scope.blocks = [1, 2, 3, 4, 5, 6];
  var expandedBlock;
  
  $scope.isAnyBlockExpanded = function() {
   return expandedBlock !== undefined;
  };
  
  $scope.isBlockExpanded = function(blockId) {
   return expandedBlock === blockId;
  };
  
  $scope.toggleBlockExpandingStatus = function(blockId) {
   expandedBlock = $scope.isBlockExpanded(blockId) ? undefined : blockId;
  }; 
 });
body {
    padding-top: 15px;
}

.divClass{
    width: 35%;
    height:50px;
    text-align:center;
    line-height:50px;
    float: left;
    left:15px;
    margin-top: 25px;
    margin-bottom: 25px;
    margin-right: 15px;
    color: orange;
    font-size: 18px;
    border:2px solid #000; 
    background-color: rgba(00,00,00,0.6);
    cursor: pointer;
}

.textdiv {
    border:2px solid green; 
    background-color: rgba(100,100,100,0.1);
    height:50px;
    text-align:center;
    line-height:50px;
    margin-top: 25px;
 display: none;
}

.expanded-block  .textdiv {
 display: block;
}

i {
    color:#000;
    font-size: 40px;
    line-height:50px;
}

.btn {
    height: 50px;
    margin-top: 25px;
    margin-left: 15px;
}
 
.expanded-block  .divClass {
    background-color:rgba(100,100,100,0.1);
    width: 35%;
    font-size: 40px;
    text-align: center;
    border:2px solid green; 
}

.collapsed-block .block-item {
    width: 33%;
    height: inherit;
    background-color: rgba(00,00,00,0.8);
    z-index: 9;
}

@media (max-width:420px){
 .collapsed-block {
  width: 80%;
 }
}  
<html>
<head>
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"/>
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"/>
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>

<body ng-app="plusMinusApp">
 <div class="container"  ng-controller="plusMinusController">

  <div ng-repeat="block in blocks" class="row" ng-class="{'collapsed-block': isAnyBlockExpanded() && !isBlockExpanded(block), 'expanded-block': isBlockExpanded(block)}">
   <div class="col-sm-4 col-xs-6 block-item">    
    <div class="divClass" ng-click="toggleBlockExpandingStatus(block)">{{block}}</div>
    <i ng-click="toggleBlockExpandingStatus(block)" class="btn btn-primary text-center fa" ng-class="isBlockExpanded(block) ? 'fa-minus': 'fa-plus'"></i>
   </div>
   <div class="col-xs-4 textdiv">Hello</div>
  </div>
  
 </div>
</body>
</html>