How to show attributes table in API4

4658
12
06-06-2018 02:31 AM
AhmadLibda
New Contributor III

4.x‌

js api 4.7

attribue table‌

How to show attributes table for a selected layer in API 4.7. I need anything similar to featuretable in API 3.

0 Kudos
12 Replies
ReneRubalcava
Frequent Contributor

This sample is using dgrid to show the results of a query

Highlight features by geometry | ArcGIS API for JavaScript 4.7 

You can look at that sample to put together something you can use.

DawnStalberg
New Contributor

We have an application where we would like to display the attribute table for the feature layer small no. of rows), and then allow the user to edit directly in the attribute table, and then reflect the changes on the map e.g. popups / defined symbology. We also want the user to be able to select the item on the table and then show the selection on the map (reverse of the above mentioned example).  Is this workflow possible with JS 4.12?

0 Kudos
DavidWilson3
Occasional Contributor

Hi Dawn,

I have had the same problem as you with an app I have been developing. API 3.x had the FeatureTable widget that nicely and easily allowed this functionality, however this is not available in 4.x yet. FeatureTable will be available later this year in an update but until then you will have to use other functionality or libraries to do what you want to do. using dgrid is one way to do this and combining it with esri/request to make REST and POST calls to services. I personally have been using boostrap and jquery.datatables to create a table with CRUD capabilities like you described in your workflow. 

So yes this workflow is possible in 4.12 but will require some extra work until FeatureTable widget comes out later this year for 4.x esri JS API. 

0 Kudos
DawnStalberg
New Contributor

Thanks, David - I've gone with API 3.29 for now - FeatureTable edit works great.

But now my dilemma is.... I want the user to be able to edit the Attribute table and render the changes on the map but not actually update/apply the edits to the underlying feature service - so I either need to create some sort of disconnected clone, or I need to cancel the edits after they have been rendered on the map, but BEFORE they are applied to the underlying data! Is this even possible? Your dynamic table for 4.12 in your reply to Ahmed will give me the disconnect I need, but I am not sure I will be able to get the "edit data / refresh map / cancel edits before they are applied/sync'd back to the server" functionality.

I've tried to create a new layer from a FeatureCollection tha tcan be bound to the table, but I get a "cyclic object value" error on the new layer (Can I populate a FeatureTable with a FeatureLayer built from a query and a featureCollection? ) Would it be possible to create a separate Graphics layer from the feature service and load those contents into the FeatureTable to get the edit / refresh map / cancel edits functionality I am trying to produce?

0 Kudos
DavidWilson3
Occasional Contributor

Hi Ahmed,

What I have done to show attributes in a table has been to create a function in Javascript to dynamically create a table by creating div elements based on a REST response from my feature services using esri/request, which creates elements with content that is taken from the fields of the service. I then use jquery.datatables and bootstrap tables CDNs on this table to apply CSS and pagination. 

AhmadLibda
New Contributor III

could you show me the code

0 Kudos
DavidWilson3
Occasional Contributor

Here is a snippet (works but is a still a work in progress), I am using boostrap tables CDN which is the reason for the specific element classes and content.

<script type="text/javascript">

    require([
        "esri/request"
    ], function (esriRequest) {

        populateAttributesTable();

        //populate the attribute of a given layer
        function populateAttributesTable(e) {

            //alert("calling attribute table for Layer " + e.target.layerid);
	        let queryurl = "service url";
	        let queryOptions = {
     			responseType: "json",
     			query:  
     			{
					f: "json",
					where:"1=1",
					returnCountOnly: false,
					outFields: "*",
					resultRecordCount: "1000"
     			}
     		}

            esriRequest(queryurl, queryOptions).then(response => {
                console.log("The response is: ", response);
                let tableWrapper = document.getElementById("tableWrapper");
                let table = document.createElement("table");
                table.id = "dataTable";
                table.className = "table table-striped table-hover";
                //tableWrapper.appendChild(table); //appends the table to tableWrapper
                let header = document.createElement("thead");
                table.appendChild(header);
                let tableRowHeader = document.createElement("tr");
                header.appendChild(tableRowHeader);            

                for (let i = 0; i < 5; i++) {
                    let headTable = document.createElement("th");
                    headTable.innerHTML = response.data.fields[i].alias;
                    tableRowHeader.appendChild(headTable);
                }

                let headTableOptions = document.createElement("th");
                headTableOptions.innerHTML = "Options";
                tableRowHeader.appendChild(headTableOptions);

                let tableBody = document.createElement("tbody");
                table.appendChild(tableBody);

                for (let j = 0; j < response.data.features.length; j++)
	     	    {
	     		    let feature = response.data.features[j];
	     		    let tableRowBody = document.createElement("tr");
                    tableBody.appendChild(tableRowBody);                  
	     		    for (let i = 0; i < 5; i++)
		     	    {
		     		    let field = response.data.fields[i];
			            let divTable = 
                                         document.createElement("td");
		                    divTable.innerHTML = 
                                         feature.attributes[field.name];
				    tableRowBody.appendChild(divTable);        
                    }

                    let footerTD = document.createElement("td");
                    tableRowBody.appendChild(footerTD);
                    let editModal = document.createElement("a");
                    editModal.setAttribute("href", "#editModal");
                    editModal.className = "edit";
                    editModal.setAttribute("data-toggle", "modal");
                    footerTD.appendChild(editModal);
                    let editModalIcon = document.createElement("i");
                    editModalIcon.className = "material-icons";
                    editModalIcon.setAttribute("data-toggle", "tooltip");
                    editModalIcon.setAttribute("title", "Edit");
                    editModalIcon.innerHTML = "&#xE254;";
                    editModal.appendChild(editModalIcon);
                    let deleteModal = document.createElement("a");
                    deleteModal.setAttribute("href", "#deleteModal");
                    deleteModal.className = "delete";
                    deleteModal.setAttribute("data-toggle", "modal");
                    footerTD.appendChild(deleteModal);
                    let deleteModalIcon = document.createElement("i");
                    deleteModalIcon.className = "material-icons";
                    deleteModalIcon.setAttribute("data-toggle", "tooltip");
                    deleteModalIcon.setAttribute("title", "Delete");
                    deleteModalIcon.innerHTML = "&#xE872;";
                    deleteModal.appendChild(deleteModalIcon);
	     	    }

                tableWrapper.appendChild(table);

                require(["https://cdn.datatables.net/1.10.19/js/jquery.dataTables.js"], function () {

                    $(document).ready(function () {
                    $('#dataTable').DataTable();
                    $('.dataTables_length').addClass('bs-select');
                    // Activate tooltip
                    $('[data-toggle="tooltip"]').tooltip();

                    // Select/Deselect checkboxes
                    var checkbox = $('table tbody input[type="checkbox"]');
                        $("#selectAll").click(function () {
                            if (this.checked) {
                                checkbox.each(function () {
                                    this.checked = true;
                                });
                            } else {
                                checkbox.each(function () {
                                    this.checked = false;
                                });
                            }
                        });
                        checkbox.click(function () {
                            if (!this.checked) {
                                $("#selectAll").prop("checked", false);
                            }
                        });

                    });

                });

            });
        };
    }); 

</script>
0 Kudos
AndyFairbairn
Occasional Contributor

Thanks for sharing David - this has hopefully set me off down a useful path. However, when I've been experimenting, I'm not getting any .features in my response, so the For loop on line 51 in your snippet is going to hit problems for me.  I get the fields no problem (for previous For loop on 38), but no features. Simplified test example below, be grateful if anyone has some advice. 

Cheers, 

Andy.

var url = "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads/FeatureServer/0";
var query = {
			responseType: "json",
			query:  
			{
				 f: "json",
				 where:"1=1",
				 returnCountOnly: false,
				 outFields: "*",
				 resultRecordCount: "1000"
			}
	   }

esriRequest(url, query).then(function(response) {
	console.log(response);
});
0 Kudos
DavidWilson3
Occasional Contributor

Hi Andy,

Try this - 

//populate the attribute table with the attributes of a given layer
function populateAttributesTable(e)
{
//alert("calling attribute table for Layer " + e.target.layerid);
let queryurl = "https://giswebtst01.it.ohio-state.edu/arcgis/rest/services/OARDC/OARDC_SD/FeatureServer/2/query";
let attributetable = document.getElementById("attributetable");
attributetable.innerHTML ="";
let queryOptions = {
responseType: "json",
query:
{
f: "json",
where:"1=1",
returnCountOnly: false,
outFields: "*",
resultRecordCount: "50"
}
}
Request(queryurl,queryOptions).then (response =>
{
//alert(response.data.fields.length);
let table = document.createElement("table");
table.border = 2;
let header = document.createElement("tr");
table.appendChild(header);
//populate the fields/ columns
for (let i = 0; i < response.data.fields.length; i++)
{
let column = document.createElement("th");
column.textContent = response.data.fields.alias;
header.appendChild(column);
}
//loop through all features
for (let j = 0; j < response.data.features.length; j++)
{
let feature = response.data.features;
let row = document.createElement("tr");
table.appendChild(row);
for (let i = 0; i < response.data.fields.length; i++)
{
let field = response.data.fields;
let column = document.createElement("td");
column.textContent = feature.attributes[field.name];
row.appendChild(column);
}
}
attributetable.appendChild(table);
}, response => el.style.visibility="hidden" );
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

0 Kudos