Creating a checkbox tree to define constants for a where clause

4360
9
Jump to solution
03-13-2015 02:29 PM
TracySchloss
Frequent Contributor

I need to figure out how to set up check boxes to choose values to query from a data layer.  Some of the values will be a single category, such as 'Audiologist' or "Orthopedist'.  But there will also be a category that is more of a group "Mental Health", that might have subcategories of 'Alcohol',' Narcotics'

If I could organize this using a checkbox tree, then the items that had subcategories could be grouped under a single item in the tree, which the ones that didn't would just be a one line with a checkbox.  I think this would give a cleaner look to the interface. 

This is obviously exactly what's going on with the TOC, but I'm not dealing with layers. The Values will remain constant and I don't think I'll have even a dozen to deal with.  Once the user makes their selection, then I can use the values to create a where clause and then either a queryTask or a selectFeatures on featureLayer.  That results of the query will go into a grid.  What I'm envisioning isn't a TOC, or I'd just use that. 

I'm having a hard time finding a good example of the checkbox tree.  I found this site, but it's enough out of date that the code isn't working for me. http://thejekels.com/cbtree/demos/ArcGIS.php   I vaguely remember a POI example on the ESRI site from a couple years back, but I can't find a working example of that either.

If anyone has a better suggestion, I'd like to hear it. 

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Esteemed Contributor

Tracy,

   Try this:

  function createWhereClause (sortedString){

    var whereSnippet = "Hosp_Type LIKE '%";

    var whereClause = "";

    for (var i = 0, len = sortedString.length; i < len; ++i) {

      if (i === 0){

        whereClause =+ whereSnippet + sortedString + "%'"

      } else {

        whereClause =+ " OR " + whereSnippet + sortedString + "%'";

      }

    }

    return whereClause;

  }

View solution in original post

0 Kudos
9 Replies
ChrisSergent
Regular Contributor III

Here is an example for adding checkboxes to toggle layer visibility: Toggle layer visibility | ArcGIS API for JavaScript You could use this concept to set the parameters for your query.

0 Kudos
TracySchloss
Frequent Contributor

Thanks, I've seen it.  I'm trying to also offer some sort of grouping or hierarchy.  It's going to look a lot like a TOC, but with completely different functionality.  If I can't figure it out, then I'll go to a single set of features without any type of grouping, and maybe handle the grouping with padding the styles.

0 Kudos
ChrisSergent
Regular Contributor III

I'm not sure, but if you already have the values that you want, perhaps this will help: Dojo Dijit Tree with Checkboxes

TracySchloss
Frequent Contributor

I've been looking at this since I came in this AM.  It seems like it has a lot of functionality, but I'm digging all over to figure out how it all fits together.   I wondered if there were alternatives.

I can get it to work very generically, but I hoped someone would say they'd used it and could provide me a decent example.  It includes an example with the ESRI JS API,  but it's out of date and isn't working for me.  At the moment, I'm trying to figure out how to style it with no icons.  I only want the check boxes, and it defaults to a folder/file set of symbols.

0 Kudos
TracySchloss
Frequent Contributor

I was able to get this figured out, as far as the checkbox tree is concerned.  I used Chris's suggestion of the Dojo Dijit Tree with Checkboxes.  Once I downloaded and referenced it in my code, I was able to use the check box events to populate my query.  The problem I have now is my logic of using a where clause IN doesn't work like I'd thought.  What I really need is a function that creates a big concatenated OR statement.  The way I have it now, it only finds the records that exactly matching the values, when what I really wanted was any record that contained that value.  At least I'm getting the values from the checkboxes, which was my original posting.

<!DOCTYPE html>

<html>

  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />

    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>

    <title>CheckBox Tree Example</title>

      <link rel="stylesheet" href="https://js.arcgis.com/3.11/dijit/themes/claro/claro.css"/>

        <link rel="stylesheet" href="cbtree/themes/claro/claro.css"/>

   

  <script type="text/javascript">

    var dojoConfig = {

      parseOnLoad: false,

      async:true,

        packages: [{

          "name": "cbtree",

          "location": location.pathname.replace(/\/[^/]+$/, "")+'/cbtree'

        }]

      };

    </script>

  <script type="text/javascript" src="https://js.arcgis.com/3.11/"></script>

  <script type="text/javascript">

    var popup, map, geocoder, layer, template, symbol;

    var searchList = [];

    var pathName = "https://ogitest.oa.mo.gov";

    require([

      "dojo/parser","dojo/dom-style", "dojo/dom-construct","esri/dijit/Popup","dojo/store/Memory",

      "dojo/store/Observable","cbtree/Tree", "cbtree/store/ObjectStore", "cbtree/model/ForestStoreModel",

      "cbtree/extensions/TreeStyling",

      "esri/map", "esri/layers/GraphicsLayer",

      "esri/symbols/PictureMarkerSymbol","esri/symbols/SimpleMarkerSymbol","esri/symbols/SimpleLineSymbol",

      "esri/InfoTemplate","esri/tasks/query","esri/tasks/QueryTask",

      "dojo/_base/Color", "dojo/dom","dojo/on","dijit/registry", "dojo/_base/array",

      "dijit/layout/BorderContainer","dijit/layout/TabContainer","dijit/layout/ContentPane","dijit/form/Button",

        "dijit/TitlePane",  "dojo/domReady!" ], function (

          parser,domStyle,domConstruct, Popup, Memory, Observable,Tree, ObjectStore, StoreModel,

          TreeStyling, Map,GraphicsLayer,PictureMarkerSymbol, SimpleMarkerSymbol,

          SimpleLineSymbol,InfoTemplate,Query,QueryTask, Color, dom,on, registry, arrayUtils) {

            parser.parse();

          

            var qTask = new QueryTask(pathName+"/arcgis/rest/services/DHSS/medicalFacility/MapServer/0");

            var searchQuery = new Query();

      //    searchQuery.outSpatialReference = spatialReference;

            searchQuery.returnGeometry = false;

            searchQuery.outFields = ["Facility", "Address", "City","Hosp_Type", "OBJECTID"];//fields you want in your grid

          var data = [

              { id: "CA", name:"Critical Access", type:"parent"},

              { id: "GA", name:"General Acute Care", type:"parent"},

              { id: "LT", name:"Long Term Care", type:"parent" },            

              { id: "PSY", name:"Psychiatric", type:"parent" },

              { id: "REH", name:"Rehabilitation", type:"parent" },

              { id: "VA", name:"Veterans", type:"parent"},

              { id: "OT", name:"Other", type:"parent"}

            ];

        var store = new Memory( { data: data });

            var model = new StoreModel( { store: store,

                rootLabel: "Specialty Type",

                showRoot:false,

                query: {type: 'parent'},

              });

          tree = new Tree( {

            model: model,

            id: "tree02",

            branchReadOnly: false,

            branchcheckBox:true,

            branchIcons: false,

            nodeIcons: false,

            leafIcons:false,

            rootNode:false

            }, "CheckboxTree" );

            tree.startup();

      // Establish listener and start the tree.

        function checkBoxClicked( item, nodeWidget, evt ) {

            var newState = nodeWidget.get("checked" );

            var label    = this.model.getLabel(item);

            if( newState ) {

              searchList.push(label);

          //    tree.set("iconStyle", {border:"solid"}, item );

          //    tree.set("labelStyle",{color:"red"}, item );

            } else {

var index = array.indexOf(label);

if (index > -1) {

    searchList.splice(index, 1);

}

            }

          }

      function executeQuery(){

          searchList.sort();

          var sortedList = sortAndRemoveDuplicates(searchList);

          var sortedString = sortedList.join("','");

          var whereClause = "HOSP_TYPE IN ('" + sortedString + "')";

          console.log("whereClause = " + whereClause);

          searchQuery.where = whereClause;

          qTask.execute(searchQuery,queryHandler);

      }

    function queryHandler(results){

      console.log("in queryHandler");

    }

    function sortAndRemoveDuplicates(arr) {

    arr.sort( function(a, b) { return a - b; } );

    var copy = arr.slice(0);

    arr.length = 0;

    for (var i = 0, len = copy.length; i < len; ++i) {

        if (i == 0 || copy != copy[i - 1]) {

            arr.push(copy);

        }

    }

    return arr;

}

    //event listeners

      tree.on( "checkBoxClick", checkBoxClicked );

      registry.byId('btnSearch').on('click', function(evt){

      //  searchList.length = 0;

        executeQuery();

      });

    });

  </script>

</head>

  <body class="claro">

    <h1 class="DemoTitle">The CheckBox Tree with Multi State CheckBoxes</h1>

    <p>

      A basic CheckBox Tree using a dojo/store Memory store (non-observable).

    </p>

    <div id="CheckboxTree">

    </div>

            <button id="btnSearch" data-dojo-type="dijit/form/Button">Search</button>

    <div id="gridDiv"></div>

  </body>

</html>

RobertScheitlin__GISP
MVP Esteemed Contributor

Tracy,

   Untested code written in Notepad.

      function executeQuery(){

          searchList.sort();

          var sortedList = sortAndRemoveDuplicates(searchList);

          var whereClause = '';

          array.map(sortedList, lang.hitch(this, function(value, index){

            if(index === 0){

              whereClause += "HOSP_TYPE = '" + value + "'";

            }else{

              whereClause += "OR HOSP_TYPE = '" + value + "'";

            }

          }));t

          console.log("whereClause = " + whereClause);

          searchQuery.where = whereClause;

          qTask.execute(searchQuery,queryHandler);

      }

You will need to require dojo/_base/array and dojo/_base/lang of course

0 Kudos
TracySchloss
Frequent Contributor

I realized after I looked at the data more closely that a simple Hosp_Type = 'some value' isn't going to work.  In my actual data, not just this basic sample, the data column allows there to be multiple values, not just one in that column.  In those instances where there is only one specified, 'equal to' works fine,  But I'm just as likely to have a type of 'orthopedic, neurologic' or 'mental health w/ IQ test, mental health w Weschler'.  The user wants to check as many boxes as they want.  At least I'm only searching within this one 'type' column and not all. 

I'm thinking I'll need a function to generate a long where clause instead, although I don't have the syntax right yet.  I"m also not sure this is going to work for my definition expression of my feature layer.

    function executeQuery(){

        searchList.sort();

      var searchClause = createWhereClause(searchList);

        searchQuery.where = searchClause;

        qTask.execute(searchQuery, updateGridHandler);

        pointLayer.setDefinitionExpression(searchClause);

    }

  function createWhereClause (sortedString){

    var whereSnippet = "Hosp_Type LIKE '%";

    var whereClause = "";

    for (var i = 0, len = sortedString.length; i < len; ++i) {

      if (i < sortedString.length -1){  //this part isn't right yet!!

        whereClause =+ whereSnippet + sortedString + "%' OR "

      } else {

        whereClause =+ whereSnippet + sortedString + "%'";

      }

    }

    return whereClause;

  }

This is public facing.  I've been told this isn't sensitive, since it's provider information, not patient data.

Medical Review Team Provider Search

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Tracy,

   Try this:

  function createWhereClause (sortedString){

    var whereSnippet = "Hosp_Type LIKE '%";

    var whereClause = "";

    for (var i = 0, len = sortedString.length; i < len; ++i) {

      if (i === 0){

        whereClause =+ whereSnippet + sortedString + "%'"

      } else {

        whereClause =+ " OR " + whereSnippet + sortedString + "%'";

      }

    }

    return whereClause;

  }

View solution in original post

0 Kudos
TracySchloss
Frequent Contributor

That's it, after I switch =+ to +=.

Now I need to figure out how to programmatically uncheck all the boxes with my 'Clear' button.

0 Kudos