# EXAMPLE (template) - displaying a two dimensional table

**URL:** https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662
**Category:** Dashboard
**Created:** [7 June 2018 11:04 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662 "2018-06-07T11:04:17Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)
#### Post date: [7 June 2018 11:04 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/1 "2018-06-07T11:04:17Z")

</div>

Problem: You need to display a table with first name, last name and age.

Sample data:  
Paul Doe, 24  
Greg Jones, 31  
Able Smith, 29

We will use a function node to create the table like this:

 ![55%20AM](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/15717ac0c0e36e4ce36e6610fecb8182453626f8.png)  
And display the table using the template node. Here is what we use in the template node:  
 ![09%20AM](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/10d835b205afa58dc98c4b4a25355428db132d7d.png)  
In this case we use the ng-repeat twice, once to process each row of the table in the `<tr>` and once to display each item in each row using a `<td>` element.

Here is what the display will look like:  
 ![17%20AM](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/115dc6ef2352d7579bd3426c4a244f76014c735e.png)

the following is the flow that is used in this example:  
`[{"id":"1b61c07f.7d06f8","type":"inject","z":"968ca76f.3dc46","name":"Go","topic":"","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":90,"y":260,"wires":[["a30ba039.4650a8"]]},{"id":"a30ba039.4650a8","type":"function","z":"968ca76f.3dc46","name":"build array (2)","func":"var arr =[[\"Paul\",\"Doe\",24],[\"Greg\",\"Jones\",31],[\"Able\",\"Smith\",29]];\nmsg.payload = arr;\nreturn msg;","outputs":1,"noerr":0,"x":260,"y":260,"wires":[["c9727c65.303f"]]},{"id":"7fa8d335.150f84","type":"debug","z":"968ca76f.3dc46","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":790,"y":260,"wires":[]},{"id":"c9727c65.303f","type":"ui_template","z":"968ca76f.3dc46","group":"3c5da821.6d5638","name":"Two dimension array table","order":1,"width":"6","height":"6","format":"<table id=\"table\" border=\"1\">\n <tr>\n <th>First Name</th> \n <th>Last Name</th>\n <th>Age</th>\n </tr>\n <tbody>\n <tr ng-repeat=\"row in msg.payload\">\n <td ng-repeat=\"item in row\" >{{item}}</td>\n </tr>\n </tbody>\n</table>\n\n","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":480,"y":260,"wires":[["7fa8d335.150f84"]]},{"id":"3c5da821.6d5638","type":"ui_group","z":"","name":"Two dimension Array","tab":"f9ac9e91.20e588","order":2,"disp":true,"width":"6","collapse":false},{"id":"f9ac9e91.20e588","type":"ui_tab","z":"","name":"Table Examples","icon":"dashboard","order":1}]`

---

<div class="post-metadata">

### Author: ![arturmaj](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/arturmaj/32/3309_2.png) [@arturmaj](https://discourse.nodered.org/u/arturmaj)
#### Post date: [24 October 2018 16:21 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/2 "2018-10-24T16:21:07Z")

</div>

Thank you.

---

<div class="post-metadata">

### Author: ![hugobox](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hugobox/32/2948_2.png) [@hugobox](https://discourse.nodered.org/u/hugobox)
#### Post date: [24 October 2018 17:00 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/3 "2018-10-24T17:00:50Z")

</div>

Here is a flow to get a dynamic table with sortable columns, a searchbar and outputs the clicked row data:

Enjoy!

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/a/ae20e4722788f4a918ed9be78375fcd06eb0e9cb.jpeg)

```auto
[{"id":"ee4d312b.cc342","type":"ui_template","z":"95993933.d7c978","group":"18e6e44c.b0561c","name":"Search Sortable Table","order":1,"width":"6","height":"5","format":"<style>\n\ntable {\n color: #333;\n font-family: Helvetica, Arial, sans-serif;\n width: 100%;\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd, th {\n border: 1px solid transparent;\n /* No more visible border */\n height: 30px;\n transition: all 0.3s;\n /* Simple transition for hover effect */\n}\nth {\n background: #DFDFDF;\n /* Darken header a bit */\n font-weight: bold;\n}\ntd {\n background: #FAFAFA;\n}\n\n/* Cells in even rows (2,4,6...) are one color */\n\ntr:nth-child(even) td {\n background: #F1F1F1;\n}\n\n/* Cells in odd rows (1,3,5...) are another (excludes header cells) */\n\ntr:nth-child(odd) td {\n background: #FEFEFE;\n}\ntr td:hover {\n background: #666;\n color: #FFF;\n}\n\n/* Hover cell effect! */\n \n.animate-enter, \n.animate-leave\n{ \n -webkit-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;\n -moz-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;\n -ms-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;\n -o-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;\n transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;\n position: relative;\n display: block;\n} \n\n.animate-enter.animate-enter-active, \n.animate-leave {\n opacity: 1;\n top: 0;\n height: 30px;\n}\n\n.animate-leave.animate-leave-active,\n.animate-enter {\n opacity: 0;\n top: -50px;\n height: 0px;\n}\n \n.container\n{\n max-height: 450px;\n overflow-y: scroll;\n overflow-x: hidden;\n}\n</style>\n\n<div>\n <form>\n <span class=\"input-group\">\n <i class=\"fa fa-search\"></i>\n <input type=\"text\" class=\"form-control\" placeholder=\"Search\" ng-model=\"search\">\n </span> \n </form>\n <div class=\"container\" ng-app=\"sortApp\">\n\n <table>\n <thead>\n <tr style=\"width:100%\">\n <td>\n <a href=\"#\">\n Index\n </a>\n </td>\n <td>\n <a href=\"#\" ng-click=\"sortType = 'firstname'; sortReverse = !sortReverse\">\n First Name \n <span ng-show=\"sortType == 'firstname' && !sortReverse\" class=\"fa fa-caret-down\"></span>\n <span ng-show=\"sortType == 'firstname' && sortReverse\" class=\"fa fa-caret-up\"></span>\n </a>\n </td>\n <td>\n <a href=\"#\" ng-click=\"sortType = 'lastname'; sortReverse = !sortReverse\">\n Last Name \n <span ng-show=\"sortType == 'lastname' && !sortReverse\" class=\"fa fa-caret-down\"></span>\n <span ng-show=\"sortType == 'lastname' && sortReverse\" class=\"fa fa-caret-up\"></span>\n </a>\n </td>\n <td>\n <a href=\"#\" ng-click=\"sortType = '(age -0)'; sortReverse = !sortReverse\">\n Age\n <span ng-show=\"sortType == '(age -0)' && !sortReverse\" class=\"fa fa-caret-down\"></span>\n <span ng-show=\"sortType == '(age -0)' && sortReverse\" class=\"fa fa-caret-up\"></span>\n </a>\n </td>\n\n </tr>\n </thead>\n <tbody>\n <tr ng-repeat=\"user in msg.options | orderBy:sortType:sortReverse | filter:search track by $index\" ng-click=\"msg.payload = user;send(msg);\" style=\"width:100%\" flex>\n <td><b ng-bind=\"$index+1\"></b></td>\n <td ng-bind=\"user.firstname\"></td>\n <td ng-bind=\"user.lastname\"></td>\n <td ng-bind=\"user.age\"></td>\n </tr>\n </tbody>\n </table>\n\n</div>\n</div>\n</body></html>","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":880,"y":2180,"wires":[["e91124.de6c3ee"]]},{"id":"a60a7430.d10bd8","type":"inject","z":"95993933.d7c978","name":"Go","topic":"","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":490,"y":2180,"wires":[["bece8dfc.55e45"]]},{"id":"e91124.de6c3ee","type":"debug","z":"95993933.d7c978","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1110,"y":2180,"wires":[]},{"id":"bece8dfc.55e45","type":"change","z":"95993933.d7c978","name":"","rules":[{"t":"set","p":"options","pt":"msg","to":"[{\"firstname\":\"Paul\",\"lastname\":\"Doe\",\"age\":24},{\"firstname\":\"Greg\",\"lastname\":\"Jones\",\"age\":31},{\"firstname\":\"Able\",\"lastname\":\"Smith\",\"age\":29}]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":660,"y":2180,"wires":[["ee4d312b.cc342"]]},{"id":"18e6e44c.b0561c","type":"ui_group","z":0,"name":"Tables","tab":"e3a9c600.825af8","order":8,"disp":true,"width":"6"},{"id":"e3a9c600.825af8","type":"ui_tab","z":0,"name":"Angular UI templates","icon":"dashboard"}]

```

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [23 November 2018 08:37 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/4 "2018-11-23T08:37:25Z")

</div>

Thank you for the great examples.  
How could any of the examples be adapted to add the possibility to edit values in the table and send them back to the database?

---

<div class="post-metadata">

### Author: ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)
#### Post date: [23 November 2018 10:46 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/5 "2018-11-23T10:46:54Z")

</div>

what have you tried?

---

<div class="post-metadata">

### Author: ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)
#### Post date: [23 November 2018 12:56 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/6 "2018-11-23T12:56:38Z")

</div>

There was a thread a short while back from someone trying to do similar - [Gridview with CRUD Options (MySQL)](https://discourse.nodered.org/t/gridview-with-crud-options-mysql/2244/29)

---

<div class="post-metadata">

### Author: ![hugobox](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hugobox/32/2948_2.png) [@hugobox](https://discourse.nodered.org/u/hugobox)
#### Post date: [23 November 2018 14:18 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/7 "2018-11-23T14:18:48Z")

</div>

From my example above, you could modify the template to have fields in the table's ng-repeat section and add a save button to output the whole table via ng-click.

```auto

<div>
     <form>
      <span class="input-group">
          <i class="fa fa-search"></i>
        <input type="text" class="form-control" placeholder="Search" ng-model="search">
        <button ng-click="msg.payload = msg.options;send(msg)">Save</button>
      </span>      
  </form>
  <div class="container" ng-app="sortApp">

      <table>
        <thead>
        <tr style="width:100%">
            <td>
          <a href="#">
            Index
          </a>
        </td>
        <td>
          <a href="#" ng-click="sortType = 'firstname'; sortReverse = !sortReverse">
            First Name 
            <span ng-show="sortType == 'firstname' && !sortReverse" class="fa fa-caret-down"></span>
            <span ng-show="sortType == 'firstname' && sortReverse" class="fa fa-caret-up"></span>
          </a>
        </td>
        <td>
          <a href="#" ng-click="sortType = 'lastname'; sortReverse = !sortReverse">
          Last Name 
            <span ng-show="sortType == 'lastname' && !sortReverse" class="fa fa-caret-down"></span>
            <span ng-show="sortType == 'lastname' && sortReverse" class="fa fa-caret-up"></span>
          </a>
        </td>
        <td>
          <a href="#" ng-click="sortType = '(age -0)'; sortReverse = !sortReverse">
            Age
            <span ng-show="sortType == '(age -0)' && !sortReverse" class="fa fa-caret-down"></span>
            <span ng-show="sortType == '(age -0)' && sortReverse" class="fa fa-caret-up"></span>
          </a>
        </td>

          </tr>
          </thead>
          <tbody>
        <tr ng-repeat="user in msg.options | orderBy:sortType:sortReverse | filter:search track by $index" style="width:100%" flex>
                <td><b ng-bind="$index+1"></b></td>
               <td><input type="text" ng-model="user.firstname"></td>
               <td><input type="text" ng-model="user.lastname"></td>
               <td><input type="number" ng-model="user.age"></td>
         </tr>
        </tbody>
      </table>

</div>
</div>
</body></html>
```

---

<div class="post-metadata">

### Author: ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)
#### Post date: [23 November 2018 15:46 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/8 "2018-11-23T15:46:43Z")

</div>

Nice example! I noticed onething, the input 'type' for the age should be `number`  
`<td><input type="number" ng-model="user.age"></td>`  
or, if it has been changed, you get a string back on save.

---

<div class="post-metadata">

### Author: ![hugobox](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/hugobox/32/2948_2.png) [@hugobox](https://discourse.nodered.org/u/hugobox)
#### Post date: [23 November 2018 15:48 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/9 "2018-11-23T15:48:04Z")

</div>

Thanks! corrected above.

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [26 November 2018 09:53 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/10 "2018-11-26T09:53:23Z")

</div>

Thanks again. Could you please explain how exactly can the click of the "Save" button be handled in a function node, that prepares the SQL"update" query that should be executed by a (for instance) SQLite node ?  
For me it is not clear how can from the "Template" html code be generated a new message containing the edited cell value(s).  
What would change if each row would have its own "save" button?

---

<div class="post-metadata">

### Author: ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)
#### Post date: [26 November 2018 11:09 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/11 "2018-11-26T11:09:17Z")

</div>

Have you tried adding debug nodes to your flow and experimenting? That will show you what is coming out of a node and you can then decide how to handle that data - i.e. pass it to a function node to build the sql.

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [26 November 2018 16:04 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/12 "2018-11-26T16:04:21Z")

</div>

Good idea, got it working ! Thx again.

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [27 November 2018 10:02 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/13 "2018-11-27T10:02:45Z")

</div>

Is there any possibility to update several records of the SQLite table in one-shot ? For instance if several values have been edited in the table before clicking the "save" button.

---

<div class="post-metadata">

### Author: ![ukmoose](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ukmoose/32/13_2.png) [@ukmoose](https://discourse.nodered.org/u/ukmoose)
#### Post date: [27 November 2018 10:19 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/14 "2018-11-27T10:19:47Z")

</div>

Try Googling "sqlite multiple row updates"

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [27 November 2018 10:36 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/15 "2018-11-27T10:36:10Z")

</div>

I searched, but I am not sure if there is any solution for SQLite.  
Otherwise, would be possible to have a loop in the function handling of the "save" button event, that calls several times the send() function with different topics, to trigger the function node connected to the output of the template node?

---

<div class="post-metadata">

### Author: ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)
#### Post date: [27 November 2018 10:40 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/16 "2018-11-27T10:40:13Z")

</div>

Did you try any of the things the search suggested?

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [27 November 2018 11:00 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/17 "2018-11-27T11:00:49Z")

</div>

My mistake, I think that you are both right : "INSERT OR REPLACE" seems to be able to update several values from several rows.

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [27 November 2018 13:59 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/18 "2018-11-27T13:59:20Z")

</div>

One more problem (sorry about that). To make some columns editable at double-click, I set the contenteditable flag to "true" for these columns in the template node. This works fine with Firefox and Chrome, but not with Edge (here it is not possible to edit a column by double-clicking it). Is there any explanation for this "read-only" behaviour on Edge?

---

<div class="post-metadata">

### Author: ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)
#### Post date: [27 November 2018 14:24 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/19 "2018-11-27T14:24:44Z")

</div>

Did you try a google search?

---

<div class="post-metadata">

### Author: ![abra](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/abra/32/3443_2.png) [@abra](https://discourse.nodered.org/u/abra)
#### Post date: [27 November 2018 15:08 UTC](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662/20 "2018-11-27T15:08:04Z")

</div>

Not really sure what should I search for. Does Microsoft Edge have problems with Angular ?

[Next page](https://discourse.nodered.org/t/example-template-displaying-a-two-dimensional-table/662.md?page=2)
