4

I have an HTML table that is bound to data via AngularJS. To make it simple, let's just say it has two columns, CustomerId and CustomerName.

When a user clicks on the row (or a plus sign, button, link, doesn't matter), I would like to expand a section below the row, make an ajax call, and display the resulting data. I would also like to collapse the previously expanded row, if any.

This seems like a DOM manipulation task, and I know how to do it in JQuery (or at least can figure it out), but I'd like to do it properly (i.e. "the Angular Way").

2 Answers 2

6

This is actually a bit difficult to do with Angular today, but you have a couple of options.

First, I think the most declarative solution would be to have a <tr> with the normal state, and a <tr> with the edit state:

<tr ng-show="edit"><td><input ng-model="model.name" ...
<tr ng-hide="edit"><td>{{model.name}} ...

the alternative (which actually is simpler) is to do this on the column <td>

<tr>
  <td ng-show="edit"><input ng-model="model.name" ... 
  <td ng-hide="edit">{{model.name}} ... 
</tr>

The reason this is simpler is that in the current version (1.0.x) of Angular you can only do ng-repeat on a single root element (although it looks like this will get changed in v 1.2.x: multi-element directives). Fortunately you're allowed to use multiple <tbody> tags in html, so this is actually valid:

<tbody ng-repeat="model in models"> 
  <tr ng-show="edit"><td><input ng-model="model.name" ...
  <tr ng-hide="edit"><td>{{model.name}} ...
<tbody>

Note that using ng-hide only hides the element from the dom. If you're concerned about performance (huge tables or mobile devices) ng-switch (or ng-if in 1.2.x) might be a better option as it removes the hidden part from the dom:

  <tbody ng-repeat="model in models" ng-switch="row.edit" ng-init="row={}">
    <tr ng-switch-when="true">
      <td><input type="text" ng-model="model.customerId" disabled /></td>
      <td><input type="text" ng-model="model.customerName" /></td>
      <td ng-click="row.edit=false">done</td>
    </tr>
    <tr ng-switch-default>
      <td>{{model.customerId}}</td>
      <td>{{model.customerName}}</td>
      <td ng-click="row.edit=true">edit</td>
    </tr>
  </tbody>

Update: I've added a third solution which uses ng-include:

This method is maybe not the most declarative, but it works pretty good. I've created two different row templates (these can be separate files or inlined as ng-templates as in my example), and then I use ng-include to switch between the two templates. Note that this works without the additional <tbody>:

<script type="text/ng-template" charset="utf-8" id="display.html">
  <td>{{model.customerId}}</td>
  <td>{{model.customerName}}</td>
  <td ng-click="row.edit=true">edit</td>
</script>

<script type="text/ng-template" charset="utf-8" id="edit.html">
  <td><input type="text" ng-model="model.customerId" disabled /></td>
  <td><input type="text" ng-model="model.customerName" /></td>
  <td ng-click="row.edit=false">done</td>
</script>

<table border="0">
  <tr>
    <th>CustomerId</th>
    <th>CustomerName</th>
    <th>Edit</th>
  </tr>

  <tr ng-repeat="model in models" 
      ng-include="{true:'edit.html',false:'display.html'}[row.edit]" 
      ng-init="row={edit:false}"></tr>
</table>

I've created a simple example using ng-switch and ng-show/hide: http://plnkr.co/edit/6kBPIT0Z07ti4BtnGrXj

Sign up to request clarification or add additional context in comments.

1 Comment

Fantastic! I went with the ng-switch option.
0

This can be done through directives. DOM manipulation is generally done through directives. http://plnkr.co/edit/0Z36Q3EEvP9GElzuAe5M

var app = angular.module('App', []);
        angular.module('App').directive(
                'tab', ['$http',
                    function ($http) {
                        return {
                            template: '<table border="1" ng-click="click();show=!show" ><tr >' +
                                    '<th >ID</th>' + '<th>customer</th>' +
                                    ' </tr>' +
                                    '<tr ng-show="show" ng-repeat="data in datas"><td>{{data[0]}}</td><td>'+
                                    '{{data[1]}}</td></tr>' +
                                    '</table><br/>',
                            restrict: 'A',
                            link: function postLink(scope,element) {
                                scope.show =false;
                                scope.click = function () {
                                    //console.log(scope.datas);
                                    if (scope.datas ==null) {
                                        $http.get('/data').success(function (data) {
                                            scope.datas =data;
                                        }).error(function () {
                                          scope.datas = [[1,"i am customer 1"],[3,"i am customer 2"]];
                                        })
                                    }
                                }
                            }
                        };
                    }
                ]);

HTML:

<body ng-app="App">
<div tab></div>
</body>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.