【问题标题】:Howto use ng-switch inside ng-repeat for editing JSON API data如何在 ng-repeat 中使用 ng-switch 来编辑 JSON API 数据
【发布时间】:2016-05-17 15:30:54
【问题描述】:

我知道这是一个反复出现的问题,但很遗憾我找不到适合我的情况的答案。

基本上,我从 JSON API 端点获取数据,该端点使用ng-repeat 显示在表格中。我现在想ng-switch 视图输入字段以修改数据(并稍后将其发送回服务器)。

Atm,我的解决方案取决于数据中有一个我不喜欢的属性。我确信有比在检索数据后注入此属性更聪明的方法 - 有什么建议吗?

HTML:

<tbody>
  <tr ng-repeat="item in data" ng-switch on="item.edit" >
    <td ng-switch-default ng-bind="item.color"></td>
    <td ng-switch-when='true'>
      <input type="text" ng-model="item.color" />
    </td>
    <td ng-switch-default><button ng-click="switch(item)">edit</button></td>
    <td ng-switch-when='true'><button ng-click="send(item)">send</button></td>
  </tr>
</tbody>

JS:

var app = angular.module('myApp', []);

app.controller('MyCtrl', function($scope) {

  $scope.switch = function (item) {
    if (item.edit) {
      item.edit = false;
    } else {
      item.edit = true;
    }
  };

  $scope.send = function (item) {
    if (item.edit) {
      // data is sent...
      item.edit = false;
    } else {
      item.edit = true;
    }
  };

  $scope.data = [
      {color: 'blue', edit: false},
      {color: 'green', edit: false},
      {color: 'orange', edit: false}];
});

提前致谢!

这是一个笨蛋: http://plnkr.co/edit/h8ar4S43JUvjHurzLgT0?p=preview

【问题讨论】:

  • 在此处包含相关代码,链接可能会失效,我们不应该去外部站点查看代码。

标签: javascript angularjs json angularjs-ng-repeat angularjs-ng-switch


【解决方案1】:

如果您不想将标志放在数据对象上,则需要使用单独的对象来存储它们。使用WeakMaps,您可以轻松地将数据对象或元素本身与标志对象相关联。如果您针对的是较旧的浏览器,则需要找到一种类似的方法来将数据对象/或元素与标志对象相关联

JS

let map = new WeakMap();
$scope.editing = function(item){
    return map.get(item).edit;
}
$scope.switch = function (item) {
    let flags = map.get(item);
    if (flags.edit) {
        flags.edit = false;
    } else {
        flags.edit = true;
    }
};
//Note you could combine switch and send into a single toggle function
$scope.send = function (item) {
    let flags = map.get(item);
    if (flags.edit) {
        flags.edit = false;
    } else {
        flags.edit = true;
    }
};
$scope.data = [
  {color: 'blue'},
  {color: 'green'},
  {color: 'orange'}
];
//Create an empty flags object for each data item
for(let item of $scope.data){
   map.set(item,{});
}

HTML

<tr ng-repeat="item in data" ng-switch on="editing(item)" >
    <td ng-switch-default ng-bind="item.color"></td>
    <td ng-switch-when='true'>
        <input type="text" ng-model="item.color" />
    </td>
    <td ng-switch-default><button ng-click="switch(item)">edit</button></td>
    <td ng-switch-when='true'><button ng-click="send(item)">send</button></td>
</tr>

演示

// Code goes here
var app = angular.module('myApp', []);

app.controller('MyCtrl', function($scope) {
  var map = new WeakMap();
  
  //Using fat arrow less code to write
  $scope.editing = item=>map.get(item).edit;
  
  
  //Since "switch" and "send" had similar 
  //toggling code just combined them
  //Also no need to use if statement, just use the NOT operator
  //to toggle the edit flag
  $scope.toggle = item=>{
    let flags = map.get(item);
    flags.edit = !flags.edit;
  };

  $scope.switch = item=>{
    $scope.toggle(item);
    //Do some switching? 
    //if not doing anything else just 
    //call toggle in the ng-click
  };
  $scope.send = item=>{
    $scope.toggle(item);
    //Do some sending
  };

  $scope.data = [
      {color: 'blue'},
      {color: 'green'},
      {color: 'orange'}];
      
  for(let item of $scope.data){
    map.set(item,{});
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
  <table>
    <thead>
      <tr>
        <th width="180">Column</th>
        <th>Edit</th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="item in data" ng-switch on="editing(item)" >
        <td ng-switch-default ng-bind="item.color"></td>
        <td ng-switch-when='true'>
          <input type="text" ng-model="item.color" />
        </td>
        <td ng-switch-default><button ng-click="switch(item)">edit</button></td>
        <td ng-switch-when='true'><button ng-click="send(item)">send</button></td>
      </tr>
    </tbody>
  </table><br>
  "$scope.data" should never change after hitting edit/send since the flag is no longer on the data item object:
  <code><pre>{{data}}</pre></code>
</div>

【讨论】:

  • 嘿帕特里克,感谢这个解决方案。这无疑最好地回答了最初的问题,因此这是被接受的,尽管我正在考虑将标志存储在数据 b/c 上,但这并不是那么重要。稍后我将对 WeakMap 进行更深入的研究 b/c 我没有得到你的最后一点,标志不再出现在数据项上。我的想法:在 $http.put 之后,我必须重新同步并重建地图......
  • @conrel,如果你的数据没有改变,例如你没有在$http.put回调中做另一个$scope.data = [...],那么地图保留关联,你不需要重建地图。 “不要在数据项上没有标记的情况下得到最后一点” 这意味着 edit 不再在 item 对象上,而是在 flags 上对象,因此您不必在将数据发送回服务器之前“清理”数据
【解决方案2】:

我正在使用 ng-show,但希望这能展示出更好的方法:

http://plnkr.co/edit/63Io7k1mJcfppxBQUVef?p=preview

我使用ng-show 代替,我只是在需要时将“编辑”隐式附加到对象,因为您不需要立即将其设置为true。缺少该属性将意味着它返回 false。

标记:

<tbody> <tr ng-repeat="item in data"> <td ng-show="!item.edit" ng-bind="item.color"></td> <td ng-show='item.edit'> <input type="text" ng-model="item.color" /> </td> <td><button ng-click="edit(item)">{{item.edit ? "Send" : "Edit"}}</button></td> </tr> </tbody>

【讨论】:

  • 这仍然会将edit 标志放在数据对象上,OP 希望不必依赖将标志放在数据对象上。
  • 所以只是在发送之前剥离属性?如果 OP 迫切地不想把它放在上面,那么创建一个单独的数组来映射到这个数组并使用布尔值来指示您是否正在编辑,例如[1,0,0]。为简单起见,仅使用与数据相同的索引进行映射。
  • 嘿丹尼尔,谢谢你的建议。我是角度新手,如果我错了,请纠正我,但我有点担心这种方法的性能。使用 ng-show/-hide 会导致很多绑定在每个摘要中更新,对吗?因此我想使用 ng-if/-switch 编辑:我有很多数据 :) 分页在列表中...
  • 你已经完成了一半,ng-show 和 ng-hide 切换已经在 DOM 中的元素的可见性,而 ng-switch 和 ng-If 从DOM。因此,如果您正在优化页面,则可能首选 switch。实际上并没有很好的记录。无论如何,摘要循环仍会检查它们的状态。
  • 完全正确,但是 afaik 对隐藏元素进行了成本性能评估
【解决方案3】:

对于这种情况,我总是将视图状态封装在指令中。这里的意思是为每一行创建一个指令,并在该指令中移动item.edit 标志。

一个非常幼稚的实现如下:

HTML:

<tbody>
    <tr ng-repeat="item in data" inplace-edit="item" send-callback="send(item)"></tr>
</tbody>

JS:

app.directive('inplaceEdit', function() {
  return {
    restrict: 'A',
    template:
      '<td ng-if="!inEditMode" ng-bind="item.color"></td>' +
      '<td ng-if="inEditMode">' +
        '<input type="text" ng-model="item.color" />' +
      '</td>' +
      '<td ng-if="!inEditMode"><button ng-click="toEditMode()">edit</button></td>' +
      '<td ng-if="inEditMode"><button ng-click="send()">send</button></td>',
    scope: {
      item: '=inplaceEdit',
      sendCallback: '&'
    },
    link: function(scope) {
      scope.inEditMode = false;

      scope.toEditMode = function() {
        scope.inEditMode = true;
      };

      scope.send = function() {
        scope.sendCallback({item: scope.item});
        scope.inEditMode = false;
      };
    }
  };
});

查看分叉的 plunk:http://plnkr.co/edit/BS6a866aiy3BA9MX0Flx?p=preview

我要添加的内容以使其现代化:

  1. controllerAs, bindToController
  2. 一些用于回滚/撤消更改的代码(即编辑模式下的“取消”按钮)
  3. 使用 Angular 1.5.x 和单向绑定:item: '&gt;inplaceEdit' 或将 inplace-edit 指令与 ng-model 集成

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-23
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    • 2017-03-27
    • 1970-01-01
    相关资源
    最近更新 更多