Skip to content

Commit

Permalink
Merge pull request #618 from roemhildtg/proposal-custom-identify-form…
Browse files Browse the repository at this point in the history
…atter

Add the ability to add custom field formatters
  • Loading branch information
tmcgee authored Oct 10, 2016
2 parents 2838839 + 611c07b commit 0b3838b
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 48 deletions.
21 changes: 18 additions & 3 deletions viewer/js/config/identify.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
define([
'dojo/i18n!./nls/main'
], function (i18n) {
'dojo/i18n!./nls/main',
'dojo/_base/lang'
], function (i18n, lang) {

var linkTemplate = '<a href="{url}" target="_blank">{text}</a>';
function directionsFormatter (noValue, attributes) {
return lang.replace(linkTemplate, {
url: 'https://www.google.com/maps/dir/' + attributes.Address + ' Louisville, KY',
text: 'Get Directions'
});
}
return {
map: true,
mapClickMode: true,
Expand Down Expand Up @@ -30,6 +38,13 @@ define([
2: {
title: i18n.identify.louisvillePubSafety.policeStation,
fieldInfos: [{
// example of adding a 'calculated' or formatted field
// click on a louisville kentucky police station to see
// the result
fieldName: 'Directions',
visible: true,
formatter: directionsFormatter
}, {
fieldName: 'Name',
visible: true
}, {
Expand Down Expand Up @@ -62,4 +77,4 @@ define([
}
}
};
});
});
113 changes: 68 additions & 45 deletions viewer/js/gis/dijit/Identify.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ define([
'esri/TimeExtent',
'dojo/text!./Identify/templates/Identify.html',
'dojo/i18n!./Identify/nls/resource',
'./Identify/Formatters',

'dijit/form/Form',
'dijit/form/FilteringSelect',
'xstyle/css!./Identify/css/Identify.css'
], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, MenuItem, lang, array, all, topic, query, domStyle, domClass, Moveable, Memory, IdentifyTask, IdentifyParameters, PopupTemplate, FeatureLayer, TimeExtent, IdentifyTemplate, i18n) {
], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, MenuItem, lang, array, all, topic, query, domStyle, domClass, Moveable, Memory, IdentifyTask, IdentifyParameters, PopupTemplate, FeatureLayer, TimeExtent, IdentifyTemplate, i18n, Formatters) {

return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
widgetsInTemplate: true,
Expand All @@ -47,6 +48,19 @@ define([
'shape_len', 'shape.stlength()',
'shape.area', 'shape_area', 'shape.starea()'
],
/**
* field type mappings to their default formatter functions
* overriding this object will globally replace the default
* formatter function for the field type
* @type {Object<Function>}
*/
defaultFormatters: {
'esriFieldTypeSmallInteger': Formatters.formatInt,
'esriFieldTypeInteger': Formatters.formatInt,
'esriFieldTypeSingle': Formatters.formatFloat,
'esriFieldTypeDouble': Formatters.formatFloat,
'esriFieldTypeDate': Formatters.formatDate
},

postCreate: function () {
this.inherited(arguments);
Expand Down Expand Up @@ -313,11 +327,20 @@ define([
return;
}
}
fSet.push(result.feature);
var feature = this.getFormattedFeature(result.feature);
fSet.push(feature);
}, this);
}, this);
this.map.infoWindow.setFeatures(fSet);
},
getFormattedFeature: function (feature) {
array.forEach(feature.infoTemplate.info.fieldInfos, function (info) {
if (typeof info.formatter === 'function') {
feature.attributes[info.fieldName] = info.formatter(feature.attributes[info.fieldName], feature.attributes);
}
});
return feature;
},
identifyError: function (err) {
this.map.infoWindow.hide();
topic.publish('viewer/handleError', {
Expand All @@ -330,52 +353,41 @@ define([
},

getInfoTemplate: function (layer, layerId, result) {
var popup = null,
content = null;
var popup, config;
if (result) {
layerId = result.layerId;
} else if (layerId === null) {
layerId = layer.layerId;
}

// get infoTemplate from the layer's infoTemplates array
if (layer.infoTemplates) {
if (layer.infoTemplates.hasOwnProperty(layerId)) {
return layer.infoTemplates[layerId].infoTemplate;
} else {
return null;
}
}

// see if we have a Popup config defined for this layer
if (this.identifies.hasOwnProperty(layer.id)) {
if (this.identifies[layer.id].hasOwnProperty(layerId)) {
popup = this.identifies[layer.id][layerId];
if (popup) {
if (typeof (popup.declaredClass) !== 'string') { // has it been created already?
if (popup.content) {
content = popup.content;
}
popup = new PopupTemplate(popup);
if (content) {
popup.setContent(content);
}
this.identifies[layer.id][layerId] = popup;
}
var ids = this.identifies;
if (ids.hasOwnProperty(layer.id)) {
if (ids[layer.id].hasOwnProperty(layerId)) {
popup = ids[layer.id][layerId];
if (popup instanceof PopupTemplate) {
return popup;
}
}
} else {
ids[layer.id] = {};
}

// if no Popup config found, create one with all attributes or layer fields
if (!popup) {
popup = this.createDefaultInfoTemplate(layer, layerId, result);
// by mixin in the users config with the default props we can
// generate a config object that provides the basics automatically
// while letting the user override only the parts they want...like mediaInfos
config = lang.mixin(this.createDefaultInfoTemplate(layer, layerId, result), ids[layer.id][layerId] || {});

popup = ids[layer.id][layerId] = new PopupTemplate(config);
if (config.content) {
popup.setContent(config.content);
}

return popup;
return ids[layer.id][layerId];
},

createDefaultInfoTemplate: function (layer, layerId, result) {
var popup = null, fieldInfos = [];
var popup = null,
fieldInfos = [];

var layerName = this.getLayerName(layer);
if (result) {
Expand All @@ -390,14 +402,14 @@ define([
if (attributes.hasOwnProperty(prop)) {
this.addDefaultFieldInfo(fieldInfos, {
fieldName: prop,
label: prop.replace(/_/g, ' '),
label: this.makeSentenceCase(prop),
visible: true
});
}
}
}

// from the outFields of the layer
// from the outFields of the layer
} else if (layer._outFields && (layer._outFields.length) && (layer._outFields[0] !== '*')) {

var fields = layer.fields;
Expand All @@ -414,33 +426,44 @@ define([
}
}));

// from the fields layer
// from the fields layer
} else if (layer.fields) {

array.forEach(layer.fields, lang.hitch(this, function (field) {
this.addDefaultFieldInfo(fieldInfos, {
fieldName: field.name,
label: field.alias,
label: field.alias === field.name ? this.makeSentenceCase(field.name) : field.alias,
visible: true
});
}));
}

if (fieldInfos.length > 0) {
var featLayer = this.getFeatureLayerForDynamicSublayer(layer, layerId);
popup = new PopupTemplate({
popup = {
title: layerName,
fieldInfos: fieldInfos,
showAttachments: (layer.hasAttachments || featLayer.hasAttachments)
});
if (!this.identifies[layer.id]) {
this.identifies[layer.id] = {};
}
this.identifies[layer.id][layerId] = popup;
showAttachments: (layer.hasAttachments)
};
}

return popup;
},
/**
* converts a string to a nice sentence case format
* @url http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
* @param {string} str The string to convert
* @return {string} The converted string
*/
makeSentenceCase: function (str) {
if (!str.length) {
return '';
}
str = str.toLowerCase().replace(/_/g, ' ').split(' ');
for (var i = 0; i < str.length; i++) {
str[i] = str[i].charAt(0).toUpperCase() + (str[i].substr(1).length ? str[i].substr(1) : '');
}
return (str.length ? str.join(' ') : str);
},

addDefaultFieldInfo: function (fieldInfos, field) {
var nameLC = field.fieldName.toLowerCase();
Expand Down
21 changes: 21 additions & 0 deletions viewer/js/gis/dijit/Identify/Formatters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
define([
'dojo/number',
'dojo/date/locale'
], function (number, locale) {
return {
formatInt: function (value) {
return number.format(value);
},
formatFloat: function (value) {
return number.format(value, {
places: 3
});
},
formatDate: function (value) {
var date = new Date(value);
return locale.format(date, {
formatLength: 'short'
});
}
};
});

0 comments on commit 0b3838b

Please sign in to comment.