tmcgee/cmv-widgets

View on GitHub
widgets/Search/README.md

Summary

Maintainability
Test Coverage
# Search Widget for CMV
Used in conjunction with the [Attributes Table](https://github.com/tmcgee/cmv-widgets#attributes-tables) widget to provide a user interface for querying feature layers, dynamic layers, tables and related records using QueryTask and FindTask.

**NOTE** The Advanced Search capabilities in the Search widget use a JQuery plug-in. For the widget to load properly, you will need to make modifications to your app.js file to include JQuery as a package. Please see the comment in the example [app.js](https://github.com/tmcgee/cmv-widgets/blob/master/config/app.js).

---
## Example Configuration:
``` javascript
search: {
    include: true,
    id: 'search',
    type: 'titlePane',
    path: 'widgets/Search',
    canFloat: true,
    title: 'Search',
    open: true,
    position: 0,
    options: 'config/searchWidget'
},
```

## Screenshot:
![Screenshot](https://tmcgee.github.io/cmv-widgets/images/search1.jpg)

---
## Example Search Widget Configuration:
``` javascript
define([
    'dojo/on',
    'dojo/date/locale'
], function (on, locale) {

    function formatDateTime (value) {
        var date = new Date(value);
        return locale.format(date, {
            formatLength: 'short'
        });
    }

    return {
        map: true,
        mapClickMode: true,

        /*
           Show button to open the Query Builder widget
           This new widget not yet been released
        */
        enableQueryBuilder: false,

        /*
            continue adding multiple shapes before searching
        */
        enableDrawMultipleShapes: true,

        /*
            add the results of a search to the existing results from a previous search
        */
        enableAddToExistingResults: true,

        /*
            use spatial filters in searches by attribute
        */
        enableSpatialFilters: true,

        /*
            control which spatial filters are available
        */
        spatialFilters: {
            entireMap: true,
            currentExtent: true,
            identifiedFeature: true,
            searchFeatures: true,
            searchSelected: true,
            searchSource: true,
            searchBuffer: true
        },

        /*
            Control which drawing tools are available to the user
        */
        drawingOptions: {
            rectangle: true,
            circle: true,
            point: true,
            polyline: true,
            freehandPolyline: true,
            polygon: true,
            freehandPolygon: true,
            stopDrawing: true,
            identifiedFeature: true,
            selectedFeatures: true,

            // change the symbology for drawn shapes and buffer around them
            symbols: {}
        },

        /*
            Override the options used for searching from the URL query string.
        */
        queryStringOptions: {
            // what parameter is used to pass the layer index
            layerParameter: 'layer',

            // what parameter is used to pass the attribute search index
            searchParameter: 'search',

            // what parameter is used to pass the values to be searched
            valueParameter: 'values',

            // if passing multiple values, how are they delimited
            valueDelimiter: '|',

            // Should the widget open when the search is executed?
            openWidget: true
        },

        /*
            Symbology for drawn shapes
        */
        symbols: {
            point: {
                type: 'esriSMS',
                style: 'esriSMSCircle',
                size: 6,
                color: [0, 0, 0, 64],
                angle: 0,
                xoffset: 0,
                yoffset: 0,
                outline: {
                    type: 'esriSLS',
                    style: 'esriSLSSolid',
                    color: [255, 0, 0],
                    width: 2
                }
            },
            polyline: {
                type: 'esriSLS',
                style: 'esriSLSSolid',
                color: [255, 0, 0],
                width: 2
            },
            polygon: {
                type: 'esriSFS',
                style: 'esriSFSSolid',
                color: [0, 0, 0, 64],
                outline: {
                    type: 'esriSLS',
                    style: 'esriSLSSolid',
                    color: [255, 0, 0],
                    width: 1
                }
            },

            // symbology for buffer around shapes
            buffer: {
                type: 'esriSFS',
                style: 'esriSFSSolid',
                color: [255, 0, 0, 32],
                outline: {
                    type: 'esriSLS',
                    style: 'esriSLSDash',
                    color: [255, 0, 0, 255],
                    width: 1
                }
            }
        },

        /*
            Override the units available for the buffer tool.
        */
        bufferUnits: [
            {
                value: GeometryService.UNIT_FOOT,
                label: 'Feet',
                selected: true
            },
            {
                value: GeometryService.UNIT_STATUTE_MILE,
                label: 'Miles'
            },
            {
                value: GeometryService.UNIT_METER,
                label: 'Meters'
            },
            {
                value: GeometryService.UNIT_KILOMETER,
                label: 'Kilometers'
            },
            {
                value: GeometryService.UNIT_NAUTICAL_MILE,
                label: 'Nautical Miles'
            },
            {
                value: GeometryService.UNIT_US_NAUTICAL_MILE,
                label: 'US Nautical Miles'
            }
        ],

        layers: [
            {
                name: 'Damage Assessment',
                expression: '', // additional where expression applied to all queries
                idProperty: 'objectid',
                queryParameters: {
                    type: 'spatial', // spatial, relationship, table or database
                    layerID: 'DamageAssessment', // from operational layers
                    sublayerID: 0,
                    outFields: ['*']
                },
                advancedSearchOptions: {
                    defaultToCaseInsensitive: true,
                    fetchAllFields: true,
                    fields: [
                        {
                            field: 'name',
                            type: 'string'
                        },
                        {
                            field: 'county',
                            type: 'string',
                            unique: true
                        },
                        {
                            field: 'state',
                            type: 'string',
                            options: [
                                {
                                    id: 'CA',
                                    name: 'California'
                                },
                                {
                                    id: 'IL',
                                    name: 'Illinois'
                                }
                            ],
                            multiple: false
                        },
                        {
                            field: 'rating',
                            type: 'integer',
                            range: {
                                min: 0,
                                max: 10
                            }
                        },
                        {
                            field: 'temperature',
                            type: 'double'
                        },
                        {
                            field: 'startdate',
                            type: 'date'
                        }
                    ]
                },
                attributeSearches: [
                    {
                        name: 'Search For Assessments',
                        searchFields: [
                            {
                                name: 'Inspector Name',
                                label: 'Inspector Name',
                                expression: '(inspector LIKE \'[value]%\')',
                                placeholder: 'Enter the name Fred',
                                required: true,
                                minChars: 3
                            },
                            {
                                name: 'Type of Damage',
                                label: 'Type of Damage',
                                expression: '(typdamage LIKE \'[value]%\')',
                                values: ['*', 'Destroyed', 'Major', 'Minor']
                            }
                        ],

                        title: 'Assessments',
                        topicID: 'assessmentsQuery',
                        gridOptions: {
                            columns: [
                                {
                                    field: 'incidentnm',
                                    label: 'Name'
                                },
                                {
                                    field: 'inspdate',
                                    label: 'Inspected',
                                    width: 150,
                                    get: function (object) { // allow export as a proper date
                                        return new Date(object.inspdate);
                                    },
                                    formatter: formatDateTime
                                },
                                {
                                    field: 'inspector',
                                    label: 'Inspector'
                                },
                                {
                                    field: 'fulladdr',
                                    label: 'Address'
                                },
                                {
                                    field: 'pstlcity',
                                    label: 'City'
                                },
                                {
                                    field: 'typdamage',
                                    label: 'Damage'
                                },
                                {
                                    field: 'lastupdate',
                                    label: 'Updated',
                                    get: function (object) { // allow export as a proper date
                                        return new Date(object.lastupdate);
                                    },
                                    formatter: formatDateTime
                                }
                            ],
                            sort: [
                                {
                                    attribute: 'incidentnm',
                                    descending: 'ASC'
                                }
                            ]
                        }
                    }
                ]
            },
            {
                name: 'Hospitals',
                expression: '', // additional where expression applied to all queries
                idProperty: 'OBJECTID',
                queryParameters: {
                    type: 'table', // spatial, relationship, table or database
                    layerID: 'louisvillePubSafety', // from operational layers
                    sublayerID: 5,
                    outFields: ['*']
                },
                attributeSearches: [
                    {
                        name: 'Search For Hospital',
                        searchFields: [
                            {
                                name: 'Hospital Name',
                                label: 'Name',
                                expression: '(NAME LIKE \'[value]%\')',
                                placeholder: 'Enter the name of the hospital',
                                required: true,
                                minChars: 3
                            },
                            {
                                name: 'Total Admissions',
                                label: 'Total Admissions >=',
                                expression: '(TOTALADM >= [value])',
                                placeholder: 'Total Admissions >='
                            },
                            {
                                name: 'Total Admissions',
                                label: 'Total Admissions <=',
                                expression: '(TOTALADM <= [value])',
                                placeholder: 'Total Admissions <='
                            }
                        ],

                        title: 'Hospitals',
                        topicID: 'hospitalQuery',
                        gridOptions: {
                            columns: [
                                {
                                    id: 'Action',
                                    field: 'OBJECTID',
                                    label: 'Action',
                                    width: 32,
                                    sortable: false,
                                    exportable: false,
                                    renderCell: function (object, value, node) {
                                        on(node, 'click', function () {
                                            alert('Do something exciting here like search for related records or edit the selected record.');
                                        });
                                        node.innerHTML = '<i class=\'fas fa-pencil\' style=\'margin-left:8px;\'></i>';
                                    }
                                },
                                {
                                    field: 'NAME',
                                    label: 'Name',
                                    width: 150
                                },
                                {
                                    field: 'ADDRESS',
                                    label: 'Address',
                                    width: 150
                                },
                                {
                                    field: 'CITY',
                                    label: 'City',
                                    width: 80
                                },
                                {
                                    field: 'STABREV',
                                    label: 'State',
                                    width: 50
                                },
                                {
                                    field: 'ZIPCODE',
                                    label: 'Zip Code',
                                    width: 80
                                },
                                {
                                    field: 'TOTALADM',
                                    label: 'Total Admission',
                                    width: 100
                                },
                                {
                                    field: 'LASTUPDATE',
                                    label: 'Last Update',
                                    width: 100,
                                    get: function (object) { // allow export as a proper date
                                        return new Date(object.LASTUPDATE);
                                    },
                                    formatter: formatDateTime
                                }
                            ],
                            sort: [
                                {
                                    attribute: 'NAME',
                                    descending: 'ASC'
                                }
                            ]
                        }
                    },
                ]
            },
            {
                name: 'Police Stations',
                expression: '', // additional where expression applied to all queries
                queryParameters: {
                    type: 'table', // spatial, relationship, table or database
                    layerID: 'louisvillePubSafety', // from operational layers
                    sublayerID: 2,
                    outFields: ['*']
                },
                idProperty: 'OBJECTID',
                attributeSearches: [
                    {
                        name: 'Search For Police Station By Name',
                        searchFields: [
                            {
                                name: 'PDNAME',
                                label: 'Station Name',
                                expression: '(PDNAME = \'[value]\')',
                                unique: true
                            }
                        ],

                        title: 'Police Stations',
                        topicID: 'policeStationQuery',
                        gridOptions: {
                            columns: [
                                {
                                    field: 'PDNAME',
                                    label: 'Name',
                                    width: 150
                                },
                                {
                                    field: 'ADDRESS',
                                    label: 'Address',
                                    width: 150
                                },
                                {
                                    field: 'PDTYPE',
                                    label: 'Type',
                                    width: 100
                                },
                                {
                                    field: 'FUNCTION',
                                    label: 'Function',
                                    width: 100
                                },
                                {
                                    field: 'LASTUPDATE',
                                    label: 'Last Update',
                                    width: 100,
                                    get: function (object) { // allow export as a proper date
                                        return new Date(object.LASTUPDATE);
                                    },
                                    formatter: formatDateTime
                                }
                            ],
                            sort: [
                                {
                                    attribute: 'PDNAME',
                                    descending: 'ASC'
                                }
                            ]
                        }
                    }
                ]
            },
            {
                name: 'Public Safety by Name',
                findOptions: {
                    url: 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer',
                    layerIds: [1, 2, 3, 4, 5, 6, 7],
                    searchFields: ['FDNAME, PDNAME', 'NAME', 'RESNAME']
                },
                attributeSearches: [
                    {
                        name: 'Search for Public Safety Locations By Name',
                        searchFields: [
                            {
                                name: 'Name',
                                label: 'Name',
                                expression: '[value]%\')',
                                placeholder: 'fdname, pdname, name or resname',
                                required: true,
                                minChars: 3
                            }
                        ],

                        title: 'Public Safety Locations',
                        topicID: 'findPublicSafterQuery',
                        gridOptions: {
                            columns: [
                                {
                                    field: 'value',
                                    label: 'Name'
                                },
                                {
                                    field: 'displayFieldName',
                                    label: 'Field',
                                    width: 150
                                },
                                {
                                    field: 'layerName',
                                    label: 'Layer',
                                    width: 150
                                },
                                {
                                    field: 'Last Update Date',
                                    label: 'Last Updated',
                                    width: 150,
                                    get: function (object) { // allow export as a proper date
                                        return new Date(object['Last Update Date']);
                                    },
                                    formatter: formatDate

                                }
                            ],
                            sort: [
                                {
                                    attribute: 'Name',
                                    descending: false
                                }
                            ]
                        }
                    }
                ]
            }
        ]
    };
});
```

## Screenshot:
![Screenshot](https://tmcgee.github.io/cmv-widgets/images/search2.jpg)

---
##Search Topics

### Subscribed Topics
The Search widget subscribes to the following topics. The topicID should be unique for each instance of the widget.
``` javascript
// execute a basic search  (incomplete and untested)
topicID + '/search'

// execute a query
topicID + '/executeQuery'

//  update the available spatial filters when the table (tab) is updated
this.attributesContainerID + '/tableUpdated'

// set the sql where clause for the current attributes search
this.topicID + '/setSQLWhereClause'

this.topicID + '/clearSQLWhereClause'

// listens for the mapClickMode changing
'mapClickMode/currentSet'
```

### Published Topics
The Search widdet publishes the following topics. The topicID should be unique for each instance of the widget.
```javascript
// publishes to Growl widget to provide users with information such as when a query is executing or details about the query results (number of results)
'growler/growl'

// publish a change in mapClickMode
'mapClickMode/setCurrent'

// return the  mapClickMode to the default
'mapClickMode/setDefault'

// publish to an accompanying attributes table and running the submitted query or find task.
this.attributesContainerID + '/addTable'

// opens the QueryBuilder widget
this.queryBuilderTopicID + '/openDialog'
```