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>