Hello,
I was already able to edit existing records a non-spatial table in my SDE database using FeatureLayer and FeatureTable following this example (Using FeatureTable (no map) | ArcGIS API for JavaScript) and using the editable property. I would now like to be able to insert (clicking a button would add a blank record at the bottom) and delete selected records from this table. Is this possible? I thought about using applyEdits but I understand it will only accept graphics as parameters (FeatureLayer | API Reference | ArcGIS API for JavaScript)
Thanks!
Solved! Go to Solution.
There is no built in functionality for this (at least at 3.16). I had a similar need and ended up extending the featureTable dijit and adding the attributeInspector dijit to create a new row.
There is a bunch of extra functionality that you likely won't need, but here is my extended dijit code:
define([ 'dijit/Dialog', 'dijit/form/Button', "dijit/Toolbar", "dojo/dom-class", 'dojo/dom-construct', 'dojo/_base/array', 'dojo/_base/declare', "dojo/string", 'dojo/_base/lang', 'dojo/on', "dojo/query", 'dojo/text!./templates/featureTableEditor.htm', 'esri/dijit/AttributeInspector', 'esri/dijit/FeatureTable', 'esri/layers/FeatureLayer', 'esri/tasks/query', "esri/graphic" ], function( Dialog, Button, Toolbar, domClass, domConstruct, array, declare, string, lang, on, dojoQuery, template, AttributeInspector, FeatureTable, FeatureLayer, Query, Graphic ) { return declare(FeatureTable, { constructor: function(params, srcNodeRef) { var _this = this; this.editableCustom = (params.editable === true) ? true : false; params.editable = false; this.newRecordAttributes = params.newRecordAttributes || {}; this.customHeaderText = params.customHeaderText || null; }, buildRendering: function () { this.templateString = template; this.inherited(arguments); }, postCreate: function() { var _this = this; console.debug('fte',this) this.on('load',this._postGridCreated); //add the main class domClass.add(this.domNode, "fwijitsFeatureTable"); this._i18nStrings.loadingData = "Loading Table Data..."; this._i18nStrings.gridHeader = '${gridTitle} (${featureSelectedCount}/${featureCount} selected)'; this.inherited(arguments); }, ///////////////// // Functions that override/enhance functionality in the ESRI featureTable _refreshGrid: function(ids){ //forces a refresh of the dataStore item var _this = this; this._createStoreFromDataQuery(); var listener = this.grid.on('dgrid-refresh-complete',function(){ listener.remove(); if (ids){ _this.selectRows(ids); } }); }, //override the applyEditsListener _applyEditsListener: function() { var listener = on(this.featureLayer, "edits-complete", lang.hitch(this, function(listener) { this.emit("edits-complete", listener); })); return listener; }, // End Functions that override/enhance functionality in the ESRI featureTable /////////////////////////////////////////////////////////////////////////// startup: function() { this.inherited(arguments); }, _updateGridHeaderText: function() { if (this._gridTitleNode){ this._gridTitleNode.innerHTML = string.substitute(this._i18nStrings.gridHeader, { gridTitle: this.customHeaderText || this.featureLayer.name || this._i18nStrings.untitled, featureCount: this.featureCount, featureSelectedCount: this._featureSelectedCount }); } }, _postGridCreated: function(){ var _this = this; //open the row editor on double click this.grid.on('.dgrid-row:dblclick', function(evt) { _this.grid.clearSelection(); var row = _this.grid.row(evt); _this.grid.select(row); _this._editSelection(); //_this._generateRowEditor(row.id); //_this._toggleLoadingIndicator('block'); }); // this._setupEditorButtons(); this.on('row-select',function(row){ _this._updateEditorButtons('select'); }); this.on('row-deselect',function(row){ _this._updateEditorButtons('deselect'); }); //this._addEditorButtons(); }, _editSelection: function(){ //currently only handles single row this._generateRowEditor(this.selectedRowIds[0]); this._toggleLoadingIndicator('block'); }, //_deleteSelection: function(){ // //}, _updateEditorButtons: function(type){ console.debug('running',this.selectedRowIds.length,type) var disableButtons = false; if (type == 'deselect' && this.selectedRowIds.length <= 1){ disableButtons = true; } this._editSelectionButton.setDisabled(disableButtons); //this._deleteSelectionButton.setDisabled(disableButtons); }, _addNew: function() { var _this = this; this._toggleLoadingIndicator('block'); this.featureLayer.applyEdits( [{ 'attributes': _this.newRecordAttributes }], null, null, function(results) { _this._refreshGrid([results[0].objectId]); _this._generateRowEditor(results[0].objectId); }, function(err) { alert('the add did not work'); } ); }, // _addEditorButtons: function() { // var _this = this; // // var addnewButtonContainer = domConstruct.create("div", { // class: 'esri-feature-table-menu-item', // style: 'float:left' // }, this.gridMenuAnchor.domNode, "after"); // // var addnewButton = new Button({ // label: "Add New" // }).placeAt(addnewButtonContainer); // // addnewButton.on('click', function() { // _this._toggleLoadingIndicator('block'); // _this.featureLayer.applyEdits( // [{ // 'attributes': _this.newRecordAttributes // }], // null, // null, // function(results) { // _this._refreshGrid([results[0].objectId]); // _this._generateRowEditor(results[0].objectId); // }, // function(err) { // alert('the add did not work'); // } // ); // }); // }, _generateRowEditor: function(rowId) { var _this = this; var changeToCommit = false; var editFields = []; array.forEach(this.featureLayer.fields, function(field) { if (_this.hiddenFields.indexOf(field.name) == -1) { editFields.push({ fieldName: field.name, isEditable: true, label: field.alias }); } }); var attInspector = new AttributeInspector({ layerInfos: [{ 'featureLayer': this.featureLayer, 'isEditable': true, 'fieldInfos': editFields, showDeleteButton: false // a custom delete button will be added later }] }, domConstruct.create("div")); domClass.add(attInspector.domNode, "fwijitsFeatureTableAttInspector"); console.debug(attInspector) if (_this.saveButton) { _this.saveButton.destroy(); } if (_this.deleteButton) { _this.deleteButton.destroy(); } if (this.attrInspDialog) { _this.attrInspDialog.destroy(); } var rowQuery = new Query(); rowQuery.where = "ObjectID =" + rowId; _this.featureLayer.selectFeatures(rowQuery, FeatureLayer.SELECTION_NEW, function(features) { var updateFeature = features[0]; _this.attrInspDialog = new Dialog({ title: "Update row", content: attInspector.domNode, style: "width: 350px", class:_this.css.dialog, onHide: function() { _this.saveButton.destroy(); _this._toggleLoadingIndicator(); //_this.clearSelection(); } }); _this.attrInspDialog.show(); //add a delete button _this.deleteButton = new Button({ label: "Delete" }, domConstruct.create("div")); domConstruct.place(_this.deleteButton.domNode, attInspector.deleteBtn.domNode, "after"); _this.deleteButton.on("click", function() { //alert('delete now') var apply = _this.featureLayer.applyEdits( null, null, [updateFeature] ); apply.then(function(res) { _this._refreshGrid(); }, function(err) { alert('delete failed'); }); _this.attrInspDialog.hide(); }); //add a save button _this.saveButton = new Button({ label: "Save", disabled: false }, domConstruct.create("div")); domConstruct.place(_this.saveButton.domNode, attInspector.deleteBtn.domNode, "after"); _this.saveButton.on("click", function() { _this.attrInspDialog.hide(); if (changeToCommit === true){ updateFeature.getLayer().applyEdits( null, [updateFeature], null, function(res) { _this._refreshGrid([rowId]); }, function(err) { alert('the update did not work'); } ); } }); attInspector.on("attribute-change", function(attr) { //_this.saveButton.setDisabled(false); changeToCommit = true; updateFeature.attributes[attr.fieldName] = attr.fieldValue; }); }); }, //this is a work in progress resizeColumnsToContent: function(newSize) { for (var i in this.grid.columns) { var col = this.grid.columns; if (col.hidden == false){ var fieldName = col.field; var fieldAlias = col.label; var newWidth = this._getColumnWidth(fieldName,fieldAlias); this.grid.resizeColumnWidth(col.id, newWidth); } } }, _stripTags: function(HTML) { var tmp = document.createElement("DIV"); tmp.innerHTML = HTML; return tmp.textContent || tmp.innerText; }, _replaceURLWithHTMLLinks: function(text) { var t = text + ""; var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; return t.replace(exp, "<a href='$1' target='blank'>View Page</a>"); }, _getColumnWidth: function(fieldName, fieldAlias, data) { var _this = this; var longestDataField = "-"; //fetch the field domain var domain = null; array.forEach(this.featureLayer.fields,function(fieldInfo){ if (fieldInfo.name == fieldName && fieldInfo.domain){ domain = fieldInfo.domain; } }); array.forEach(this.grid.store.data, function(item) { console.debug(' ',item) var cellData; if (item.attributes) { cellData = item.attributes[fieldName]; } else { cellData = item[fieldName]; } //handle domains if (domain && domain.codedValues){ var cellText = ''; array.forEach(domain.codedValues,function(codedValue){ if (codedValue.code == cellData){ cellText = codedValue.name; } }); if (cellText !== ''){ cellData = cellText; } } console.debug(' ',cellData) //account for empty cells cellData = (!cellData || cellData === null || cellData === ' ' || cellData === '') ? "-" : cellData; //Strip any html tags if (typeof cellData === 'string' && cellData.indexOf('<a') > -1) { cellData = _this._stripTags(cellData); } else if (typeof cellData === 'string' && cellData.indexOf('http') > -1 && cellData.indexOf('<a') == -1) { cellData = _this._stripTags(_this._replaceURLWithHTMLLinks(cellData)); } //check to see if the current fld is longer than previous flds if (cellData.length > longestDataField.length) { longestDataField = cellData; } }); //calculate header and cell string length var resizeFactor = 1.5; var maxColumnWidth = 30; var cellLen = longestDataField.length / resizeFactor; var hdrLen = fieldAlias.length <= 10 ? fieldAlias.length : fieldAlias.length / 1.3; var columnWidth = hdrLen > cellLen ? hdrLen : cellLen; columnWidth = columnWidth < 30 ? columnWidth : maxColumnWidth; return columnWidth*10; } }); });
The template:
<div class="${baseClass}"> <div id="${gridBorderContainerId}" class="esri-feature-table-border-container" data-dojo-attach-point="_gridBorderContainer" data-dojo-type="dijit.layout.BorderContainer" gutters="false"> <div id="${gridHeaderId}" class="esri-feature-table-content-pane esri-feature-table-menu" data-dojo-attach-point="_gridHeaderNode" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'top'"> <div class="esri-feature-table-menu-item esri-feature-table-loading-indicator" data-dojo-attach-point="_gridLoadingIndicatorNode" style="display:none;"></div> <div class="esri-feature-table-menu-item esri-feature-table-title" data-dojo-attach-point="_gridTitleNode"></div> <div class="esri-feature-table-menu-item esri-feature-table-closer-container"> <a class="esri-feature-table-closer toggleOpened" data-dojo-attach-point="tableCloseButton" href="JavaScript:void(0);" title="Hide Table"></a> </div> <div data-dojo-attach-point="_menuNode" class="esri-feature-table-menu-item esri-feature-table-menu-options"> <div id="${gridMenuNodeId}"></div> </div> </div> <div id="${gridContentPaneId}" class="esri-feature-table-content-pane" data-dojo-attach-point="_gridContentPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'center'"> <div id="${gridId}" class="esri-feature-table-grid" data-dojo-attach-point="_gridNode"></div> </div> <div class="esri-feature-table-editor-toolbar" data-dojo-attach-point="_gridEditToolbarPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'bottom'"> <div data-dojo-attach-point="_gridEditorToolbar" data-dojo-type="dijit/Toolbar"> <div data-dojo-type="dijit/form/Button" data-dojo-attach-event="onClick:_addNew" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableAdd', showLabel:false">Add</div> <div data-dojo-type="dijit/form/Button" data-dojo-attach-point="_editSelectionButton" data-dojo-attach-event="onClick:_editSelection" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableEdit', showLabel:false, disabled:true">Edit Selected</div> <!--div data-dojo-type="dijit/form/Button" data-dojo-attach-point="_deleteSelectionButton" data-dojo-attach-event="onClick:_deleteSelection" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableDelete', showLabel:false, disabled:true">Delete Selected</div--> </div> </div> </div> </div>
The css:
.dgrid { font-size: 9px; } .fwijitsFeatureTableMapSelectedRows .dgrid-selected { background-color: #00ffff; } .fwijitsFeatureTableMapSelectedRows .dgrid-row:hover { border: 2px solid #ff00ff; background-color: transparent; } .fwijitsFeatureTableMapSelectedRows .dgrid-selected:hover { border: 2px solid #ff00ff; background-color: #00ffff; } .fwijitsFeatureTableAttInspector .atiLayerName { display:none; } .esri-feature-table-editor-toolbar{ } .fwijitsFeatureTable .esri-feature-table-closer-container{ display:none; } .fwijitsFeatureTableAttInspector .atiAttributes .dijitButtonNode{ border-radius:0px !important; } .fwijitsFeatureTableAttInspector .atiField{ padding:0px !important; margin:2px; } .fwijitsFeatureTableEditorIcon { background-image: url('images/featureTableEditor/editorIconsEnabled.png'); /* editor icons sprite image for the enabled state */ background-repeat: no-repeat; width: 18px; height: 18px; text-align: center; } .dijitDisabled .fwijitsFeatureTableEditorIcon { background-image: url('images/featureTableEditor/editorIconsDisabled.png'); /* editor icons sprite image for the disabled state */ } .fwijitsFeatureTableAdd { background-position: 0; } .fwijitsFeatureTableEdit { background-position: -18px; } .fwijitsFeatureTableDelete { background-position: -36px; }
At the very least, the javascript code should give you a start.
I have this same question. I did not see any way to do this using the FeatureTable. Does anyone have any hints or suggestions as to accomplish adding a new row to the FeatureTable (and to delete an existing row)?
Thanks,
Abby
Have you tried creating a new Graphic object and not update the geometry?
There is no built in functionality for this (at least at 3.16). I had a similar need and ended up extending the featureTable dijit and adding the attributeInspector dijit to create a new row.
There is a bunch of extra functionality that you likely won't need, but here is my extended dijit code:
define([ 'dijit/Dialog', 'dijit/form/Button', "dijit/Toolbar", "dojo/dom-class", 'dojo/dom-construct', 'dojo/_base/array', 'dojo/_base/declare', "dojo/string", 'dojo/_base/lang', 'dojo/on', "dojo/query", 'dojo/text!./templates/featureTableEditor.htm', 'esri/dijit/AttributeInspector', 'esri/dijit/FeatureTable', 'esri/layers/FeatureLayer', 'esri/tasks/query', "esri/graphic" ], function( Dialog, Button, Toolbar, domClass, domConstruct, array, declare, string, lang, on, dojoQuery, template, AttributeInspector, FeatureTable, FeatureLayer, Query, Graphic ) { return declare(FeatureTable, { constructor: function(params, srcNodeRef) { var _this = this; this.editableCustom = (params.editable === true) ? true : false; params.editable = false; this.newRecordAttributes = params.newRecordAttributes || {}; this.customHeaderText = params.customHeaderText || null; }, buildRendering: function () { this.templateString = template; this.inherited(arguments); }, postCreate: function() { var _this = this; console.debug('fte',this) this.on('load',this._postGridCreated); //add the main class domClass.add(this.domNode, "fwijitsFeatureTable"); this._i18nStrings.loadingData = "Loading Table Data..."; this._i18nStrings.gridHeader = '${gridTitle} (${featureSelectedCount}/${featureCount} selected)'; this.inherited(arguments); }, ///////////////// // Functions that override/enhance functionality in the ESRI featureTable _refreshGrid: function(ids){ //forces a refresh of the dataStore item var _this = this; this._createStoreFromDataQuery(); var listener = this.grid.on('dgrid-refresh-complete',function(){ listener.remove(); if (ids){ _this.selectRows(ids); } }); }, //override the applyEditsListener _applyEditsListener: function() { var listener = on(this.featureLayer, "edits-complete", lang.hitch(this, function(listener) { this.emit("edits-complete", listener); })); return listener; }, // End Functions that override/enhance functionality in the ESRI featureTable /////////////////////////////////////////////////////////////////////////// startup: function() { this.inherited(arguments); }, _updateGridHeaderText: function() { if (this._gridTitleNode){ this._gridTitleNode.innerHTML = string.substitute(this._i18nStrings.gridHeader, { gridTitle: this.customHeaderText || this.featureLayer.name || this._i18nStrings.untitled, featureCount: this.featureCount, featureSelectedCount: this._featureSelectedCount }); } }, _postGridCreated: function(){ var _this = this; //open the row editor on double click this.grid.on('.dgrid-row:dblclick', function(evt) { _this.grid.clearSelection(); var row = _this.grid.row(evt); _this.grid.select(row); _this._editSelection(); //_this._generateRowEditor(row.id); //_this._toggleLoadingIndicator('block'); }); // this._setupEditorButtons(); this.on('row-select',function(row){ _this._updateEditorButtons('select'); }); this.on('row-deselect',function(row){ _this._updateEditorButtons('deselect'); }); //this._addEditorButtons(); }, _editSelection: function(){ //currently only handles single row this._generateRowEditor(this.selectedRowIds[0]); this._toggleLoadingIndicator('block'); }, //_deleteSelection: function(){ // //}, _updateEditorButtons: function(type){ console.debug('running',this.selectedRowIds.length,type) var disableButtons = false; if (type == 'deselect' && this.selectedRowIds.length <= 1){ disableButtons = true; } this._editSelectionButton.setDisabled(disableButtons); //this._deleteSelectionButton.setDisabled(disableButtons); }, _addNew: function() { var _this = this; this._toggleLoadingIndicator('block'); this.featureLayer.applyEdits( [{ 'attributes': _this.newRecordAttributes }], null, null, function(results) { _this._refreshGrid([results[0].objectId]); _this._generateRowEditor(results[0].objectId); }, function(err) { alert('the add did not work'); } ); }, // _addEditorButtons: function() { // var _this = this; // // var addnewButtonContainer = domConstruct.create("div", { // class: 'esri-feature-table-menu-item', // style: 'float:left' // }, this.gridMenuAnchor.domNode, "after"); // // var addnewButton = new Button({ // label: "Add New" // }).placeAt(addnewButtonContainer); // // addnewButton.on('click', function() { // _this._toggleLoadingIndicator('block'); // _this.featureLayer.applyEdits( // [{ // 'attributes': _this.newRecordAttributes // }], // null, // null, // function(results) { // _this._refreshGrid([results[0].objectId]); // _this._generateRowEditor(results[0].objectId); // }, // function(err) { // alert('the add did not work'); // } // ); // }); // }, _generateRowEditor: function(rowId) { var _this = this; var changeToCommit = false; var editFields = []; array.forEach(this.featureLayer.fields, function(field) { if (_this.hiddenFields.indexOf(field.name) == -1) { editFields.push({ fieldName: field.name, isEditable: true, label: field.alias }); } }); var attInspector = new AttributeInspector({ layerInfos: [{ 'featureLayer': this.featureLayer, 'isEditable': true, 'fieldInfos': editFields, showDeleteButton: false // a custom delete button will be added later }] }, domConstruct.create("div")); domClass.add(attInspector.domNode, "fwijitsFeatureTableAttInspector"); console.debug(attInspector) if (_this.saveButton) { _this.saveButton.destroy(); } if (_this.deleteButton) { _this.deleteButton.destroy(); } if (this.attrInspDialog) { _this.attrInspDialog.destroy(); } var rowQuery = new Query(); rowQuery.where = "ObjectID =" + rowId; _this.featureLayer.selectFeatures(rowQuery, FeatureLayer.SELECTION_NEW, function(features) { var updateFeature = features[0]; _this.attrInspDialog = new Dialog({ title: "Update row", content: attInspector.domNode, style: "width: 350px", class:_this.css.dialog, onHide: function() { _this.saveButton.destroy(); _this._toggleLoadingIndicator(); //_this.clearSelection(); } }); _this.attrInspDialog.show(); //add a delete button _this.deleteButton = new Button({ label: "Delete" }, domConstruct.create("div")); domConstruct.place(_this.deleteButton.domNode, attInspector.deleteBtn.domNode, "after"); _this.deleteButton.on("click", function() { //alert('delete now') var apply = _this.featureLayer.applyEdits( null, null, [updateFeature] ); apply.then(function(res) { _this._refreshGrid(); }, function(err) { alert('delete failed'); }); _this.attrInspDialog.hide(); }); //add a save button _this.saveButton = new Button({ label: "Save", disabled: false }, domConstruct.create("div")); domConstruct.place(_this.saveButton.domNode, attInspector.deleteBtn.domNode, "after"); _this.saveButton.on("click", function() { _this.attrInspDialog.hide(); if (changeToCommit === true){ updateFeature.getLayer().applyEdits( null, [updateFeature], null, function(res) { _this._refreshGrid([rowId]); }, function(err) { alert('the update did not work'); } ); } }); attInspector.on("attribute-change", function(attr) { //_this.saveButton.setDisabled(false); changeToCommit = true; updateFeature.attributes[attr.fieldName] = attr.fieldValue; }); }); }, //this is a work in progress resizeColumnsToContent: function(newSize) { for (var i in this.grid.columns) { var col = this.grid.columns; if (col.hidden == false){ var fieldName = col.field; var fieldAlias = col.label; var newWidth = this._getColumnWidth(fieldName,fieldAlias); this.grid.resizeColumnWidth(col.id, newWidth); } } }, _stripTags: function(HTML) { var tmp = document.createElement("DIV"); tmp.innerHTML = HTML; return tmp.textContent || tmp.innerText; }, _replaceURLWithHTMLLinks: function(text) { var t = text + ""; var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; return t.replace(exp, "<a href='$1' target='blank'>View Page</a>"); }, _getColumnWidth: function(fieldName, fieldAlias, data) { var _this = this; var longestDataField = "-"; //fetch the field domain var domain = null; array.forEach(this.featureLayer.fields,function(fieldInfo){ if (fieldInfo.name == fieldName && fieldInfo.domain){ domain = fieldInfo.domain; } }); array.forEach(this.grid.store.data, function(item) { console.debug(' ',item) var cellData; if (item.attributes) { cellData = item.attributes[fieldName]; } else { cellData = item[fieldName]; } //handle domains if (domain && domain.codedValues){ var cellText = ''; array.forEach(domain.codedValues,function(codedValue){ if (codedValue.code == cellData){ cellText = codedValue.name; } }); if (cellText !== ''){ cellData = cellText; } } console.debug(' ',cellData) //account for empty cells cellData = (!cellData || cellData === null || cellData === ' ' || cellData === '') ? "-" : cellData; //Strip any html tags if (typeof cellData === 'string' && cellData.indexOf('<a') > -1) { cellData = _this._stripTags(cellData); } else if (typeof cellData === 'string' && cellData.indexOf('http') > -1 && cellData.indexOf('<a') == -1) { cellData = _this._stripTags(_this._replaceURLWithHTMLLinks(cellData)); } //check to see if the current fld is longer than previous flds if (cellData.length > longestDataField.length) { longestDataField = cellData; } }); //calculate header and cell string length var resizeFactor = 1.5; var maxColumnWidth = 30; var cellLen = longestDataField.length / resizeFactor; var hdrLen = fieldAlias.length <= 10 ? fieldAlias.length : fieldAlias.length / 1.3; var columnWidth = hdrLen > cellLen ? hdrLen : cellLen; columnWidth = columnWidth < 30 ? columnWidth : maxColumnWidth; return columnWidth*10; } }); });
The template:
<div class="${baseClass}"> <div id="${gridBorderContainerId}" class="esri-feature-table-border-container" data-dojo-attach-point="_gridBorderContainer" data-dojo-type="dijit.layout.BorderContainer" gutters="false"> <div id="${gridHeaderId}" class="esri-feature-table-content-pane esri-feature-table-menu" data-dojo-attach-point="_gridHeaderNode" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'top'"> <div class="esri-feature-table-menu-item esri-feature-table-loading-indicator" data-dojo-attach-point="_gridLoadingIndicatorNode" style="display:none;"></div> <div class="esri-feature-table-menu-item esri-feature-table-title" data-dojo-attach-point="_gridTitleNode"></div> <div class="esri-feature-table-menu-item esri-feature-table-closer-container"> <a class="esri-feature-table-closer toggleOpened" data-dojo-attach-point="tableCloseButton" href="JavaScript:void(0);" title="Hide Table"></a> </div> <div data-dojo-attach-point="_menuNode" class="esri-feature-table-menu-item esri-feature-table-menu-options"> <div id="${gridMenuNodeId}"></div> </div> </div> <div id="${gridContentPaneId}" class="esri-feature-table-content-pane" data-dojo-attach-point="_gridContentPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'center'"> <div id="${gridId}" class="esri-feature-table-grid" data-dojo-attach-point="_gridNode"></div> </div> <div class="esri-feature-table-editor-toolbar" data-dojo-attach-point="_gridEditToolbarPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'bottom'"> <div data-dojo-attach-point="_gridEditorToolbar" data-dojo-type="dijit/Toolbar"> <div data-dojo-type="dijit/form/Button" data-dojo-attach-event="onClick:_addNew" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableAdd', showLabel:false">Add</div> <div data-dojo-type="dijit/form/Button" data-dojo-attach-point="_editSelectionButton" data-dojo-attach-event="onClick:_editSelection" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableEdit', showLabel:false, disabled:true">Edit Selected</div> <!--div data-dojo-type="dijit/form/Button" data-dojo-attach-point="_deleteSelectionButton" data-dojo-attach-event="onClick:_deleteSelection" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableDelete', showLabel:false, disabled:true">Delete Selected</div--> </div> </div> </div> </div>
The css:
.dgrid { font-size: 9px; } .fwijitsFeatureTableMapSelectedRows .dgrid-selected { background-color: #00ffff; } .fwijitsFeatureTableMapSelectedRows .dgrid-row:hover { border: 2px solid #ff00ff; background-color: transparent; } .fwijitsFeatureTableMapSelectedRows .dgrid-selected:hover { border: 2px solid #ff00ff; background-color: #00ffff; } .fwijitsFeatureTableAttInspector .atiLayerName { display:none; } .esri-feature-table-editor-toolbar{ } .fwijitsFeatureTable .esri-feature-table-closer-container{ display:none; } .fwijitsFeatureTableAttInspector .atiAttributes .dijitButtonNode{ border-radius:0px !important; } .fwijitsFeatureTableAttInspector .atiField{ padding:0px !important; margin:2px; } .fwijitsFeatureTableEditorIcon { background-image: url('images/featureTableEditor/editorIconsEnabled.png'); /* editor icons sprite image for the enabled state */ background-repeat: no-repeat; width: 18px; height: 18px; text-align: center; } .dijitDisabled .fwijitsFeatureTableEditorIcon { background-image: url('images/featureTableEditor/editorIconsDisabled.png'); /* editor icons sprite image for the disabled state */ } .fwijitsFeatureTableAdd { background-position: 0; } .fwijitsFeatureTableEdit { background-position: -18px; } .fwijitsFeatureTableDelete { background-position: -36px; }
At the very least, the javascript code should give you a start.
Thank you very much. I am trying to first use your code by integrating into the example at Using FeatureTable (no map) | ArcGIS API for JavaScript 3.17 , but so far I have been unsuccessful. I am probably doing some very basic mistakes but here is what I am doing. Here is my version of code (in a file text.html) and the folder structure.
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>FeatureTable without map</title> <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.17/dijit/themes/claro/claro.css"> <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.17/esri/css/esri.css"> <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.17/esri/css/esri.css"> <script src="//js.arcgis.com/3.17/"></script> <script type="text/javascript"> dojoConfig = { parseOnLoad: true, packages: [{ "name": "newModule", "location": location.pathname.replace(/\/[^/]+$/, "") + "/module" }] }; </script> <style> html, body, #myTableNode { width:100%; height:100%; margin:0; padding:0; } #top, #bot { margin: 0; padding: 0; } </style> <script> var map; //console.log(location.pathname.replace(/\/[^/]+$/, "") + "/module"); require([ "esri/layers/FeatureLayer", "esri/dijit/FeatureTable", "newModule/featureTableEditor", "dojo/dom", "dojo/parser", "dojo/ready", ], function ( FeatureLayer, FeatureTable,featureTableEditor, dom, parser, ready ) { parser.parse(); ready(function(){ // Create the feature layer var myFeatureLayer = new FeatureLayer("https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/california_census_blocks/FeatureSe...", { mode: FeatureLayer.MODE_ONDEMAND, outFields: ["NAME","GEOID","MTFCC","ALAND","AWATER"], visible: true, id: "fLayer" }); myTable = new featureTableEditor({ featureLayer : myFeatureLayer, showGridMenu: false, hiddenFields: ["FID","C_Seq","Street"] // field that end-user can show, but is hidden on startup }, "myTableNode"); myTable.startup(); }); }); </script> </head> <body class="claro esri"> <div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline', gutters: false" style="width:100%; height:100%;"> <div id="top" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'"> <p><em>The FeatureTable dijit supports tables with lots of features, with the table growing as you scroll.</em></p> </div> <div id="bot" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"> <div id="myTableNode"></div> </div> </div> </body> </html>
I don't think your too far off. Here are a couple things I notice right off the bat...
Thanks. I got it working now. It looks and works awesome. By the way the main reason it didn't work was because I wasn't aware of "dojo/text!" requirement. I was putting "templates/featureTableEditor.html" for importing and the compiler was naturally looking for a JS file.
Thanks again!!
Excellent. Glad to hear it works for you. Were you able to test it on 3.17?
I've just tried, and it doesn't work. I am getting this error:
Error: uniqName_0 template:gridBorderContainerId
Stack trace:
.cache["dijit/_TemplatedMixin"]/</e<._stringRepl/<@https://js.arcgis.com/3.17/:372:222
.cache["dojo/_base/lang"]/</e.hitch/<@https://js.arcgis.com/3.17/:63:207
.cache["dojo/string"]/</q.substitute/<@https://js.arcgis.com/3.17/:376:308
.cache["dojo/string"]/</q.substitute@https://js.arcgis.com/3.17/:376:154
.cache["dijit/_TemplatedMixin"]/</e<._stringRepl@https://js.arcgis.com/3.17/:372:105
.cache["dijit/_TemplatedMixin"]/</e<.buildRendering@https://js.arcgis.com/3.17/:373:177
m@https://js.arcgis.com/3.17/:155:342
.buildRendering@http://127.0.0.1:8020/extendFeatureTable/module/featureTableEditor.js:60:9
.cache["dijit/_WidgetBase"]/</f<.create@https://js.arcgis.com/3.17/:350:13
.cache["dijit/_WidgetBase"]/</f<.postscript@https://js.arcgis.com/3.17/:348:470
d/<@https://js.arcgis.com/3.17/:157:442
@http://127.0.0.1:8020/extendFeatureTable/test.html:68:19
.cache["dojo/ready"]/</b.addOnLoad/f<@https://js.arcgis.com/3.17/:150:250
.cache["dojo/ready"]/</e@https://js.arcgis.com/3.17/:149:503
q.signal/<@https://js.arcgis.com/3.17/:14:445
a@https://js.arcgis.com/3.17/:10:295
q.signal@https://js.arcgis.com/3.17/:14:417
ja@https://js.arcgis.com/3.17/:28:166
ga@https://js.arcgis.com/3.17/:28:198
qa/s@https://js.arcgis.com/3.17/:30:434
q.injectUrl/g<@https://js.arcgis.com/3.17/:35:149
3.17:36:486
I have a hard time reading these errors. I suppose the error is triggered by the "this.inherited(arguments);" line in the buildRendering function inside featureTableEditor Can you tell what this is about?
It looks like they modified the template quite a bit at 3.17. Try using the following html. I haven't tried this myself yet.
<div> <div class="esri-feature-table-border-container" data-dojo-attach-point= "_gridBorderContainer" data-dojo-type="dijit.layout.BorderContainer" gutters="false"> <div class="esri-feature-table-content-pane esri-feature-table-menu" data-dojo-attach-point= "_gridHeaderNode" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'top'"> <div class="esri-feature-table-menu-item esri-feature-table-loading-indicator" data-dojo-attach-point= "_gridLoadingIndicatorNode" style="display:none;"></div> <div class="esri-feature-table-menu-item esri-feature-table-title" data-dojo-attach-point= "_gridTitleNode"></div> <div class="esri-feature-table-menu-item esri-feature-table-closer-container"></div> <div data-dojo-attach-point= "_menuNode" class="esri-feature-table-menu-item esri-feature-table-menu-options"> <div data-dojo-attach-point= "_gridMenuNode"></div> </div> </div> <div class="esri-feature-table-content-pane" data-dojo-attach-point= "_gridContentPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'center'"> <div class="esri-feature-table-grid" data-dojo-attach-point="_gridNode"></div> </div> <!-- custom editor tools section --> <div class="esri-feature-table-editor-toolbar" data-dojo-attach-point="_gridEditToolbarPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'bottom'"> <div data-dojo-attach-point="_gridEditorToolbar" data-dojo-type="dijit/Toolbar"> <div data-dojo-type="dijit/form/Button" data-dojo-attach-event="onClick:_addNew" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableAdd', showLabel:false">Add</div> <div data-dojo-type="dijit/form/Button" data-dojo-attach-point="_editSelectionButton" data-dojo-attach-event="onClick:_editSelection" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableEdit', showLabel:false, disabled:true">Edit Selected</div> <!--div data-dojo-type="dijit/form/Button" data-dojo-attach-point="_deleteSelectionButton" data-dojo-attach-event="onClick:_deleteSelection" data-dojo-props="iconClass:'fwijitsFeatureTableEditorIcon fwijitsFeatureTableDelete', showLabel:false, disabled:true">Delete Selected</div--> </div> </div> <!-- end custom editor tools section --> </div> </div>