Search code examples
jqueryhtmlangularjsservicenow

Structure of the JSON and HTML for a complex dynamic table


My Requirement: - (I have created a fiddle with my current progress)

I have an angular[1.4.0] app where I need to populate a table & its content dynamically including the header names and their corresponding values using a json object being sent from the backend(ServiceNow).

As of now, the table looks something like as shown below enter image description here

As you can see above, using ng-repeat the headers(Users, Required Headset etc) are being iterated from the object horizontally/column-wise(<th>) AND the User column(left most) are also being iterated dynamically vertically/row-wise(<tr>). The 'User' header will always be the only known first column but its values will be again dynamic.

Next, the elements that come under each header are also unknown/dynamic, meaning whether the elements under "Required Headset" column should be a selectbox/textbox/checkbox is determined by the data coming from the backend.

Also I obviously need to control these elements individually which means I need unique ng-model for each dynamic field which could be achieved with the prototype method but in this complex case I'm not sure how.

So basically, the number of users should determine the number of rows and each row will have varied inputs/elements for each columns. Later the consumer enters the values in the fields and saves the updated data.

My Question:

What is the best way to structure the JSON and correspondingly iterate the items in the HTML to get the above requirements.

What I have done so far:

Since the Users are iterating row-wise different from others being iterated column-wise(header names and their corresponding elements which come under it), I created 2 objects ie, $scope.users which is an Array and $scope.rowData which is an Array of objects containing column-wise details which looks like below.

$scope.rowData = [
{
   column_name: "Required Headset",
   options: ["one", "two", "three"],
   required: "true",
   type: "select",
   u_req_headset: ""
},
{
   column_name: "Primary Contact Number",
   options: [],
   required: "true",
   type: "text",
   u_primary_contact_number: ""
}
...
];

PS: In this object I tried to create unique keys(u_req_headset and u_primary_contact_number) so I can use them in ng-model to later get the updated field values but currently not able to get it to work.

Using the above objects, in HTML I am iterating these as shown below

<table class="table">
    <thead>
        <tr>
           <th>User</th>
            <th ng-repeat="m in rowData">
                {{m.column_name}}
            </th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="user in users track by $index">
            <td>{{user}}</td>
            <td ng-repeat="row in rowData track by $index">
                <input ng-if="row.type == 'text'" type="text" />

                <input type="checkbox" ng-if="row.type == 'checkbox'"/>

                <select ng-if="row.type == 'select'">
                    <option ng-repeat="option in row.options" value="{{option}}">{{option}}</option>
                </select>
            </td>
        </tr>
    </tbody>
</table>

Issue I am facing, where I would appreciate any help:

With the current solution, the issues I am facing are:(1st being the most important)

  • Way to bind values of each fields uniquely to get each fields value on save. Obviously if I use ng-model="something", the change would reflect for all the rows & this is obviously wrong in many levels. I need to use the prototype way, eg: row.u_req_headset from the above object but the issue again is key name( "u_req_headset" in this case) is not static. It can be something very different for another table data(dynamic). I just need a variable to bind each element individually within ng-repeat so I can get the value of that element later on save

  • Soon I am also planning to add validations to these dynamic fields.

  • I am sure there is a better way to structure the json and populate the data for my requirement.

The explanation might be a little complex or confusing but unfortunately so is my requirement so I have created a Fiddle to replicate my current situation. Any help is much appreciated.


Solution

  • The reason it wasn't working was because the model you were using was 'row.answer', which is the same for all iterations against 'users'.

    Fixed the fiddle.

    <tr ng-repeat="user in users">
      <td>{{user.name}}</td>
      <td ng-repeat="row in rowData">
        <input ng-model="user.answer" ng-if="row.type == 'text'" type="text" />
    
        <input ng-model="user.check" type="checkbox" ng-if="row.type == 'checkbox'" />
    
        <select ng-model="user.selected" ng-if="row.type == 'select'">
          <option ng-repeat="option in row.options" value="{{option}}">{{option}}</option>
        </select>
      </td>
    </tr>