如何允许用户使用 Javascript 的两个过滤器 for ArcGIS

How to allow user to use two filter with Javascript for ArcGIS

有两个过滤器,允许用户选择主要命令或年级。但是,有人可以为我指出正确的方向,告诉我如何真正让他们互相倾听。例如,如果用户拍摄了 30ABCT 并希望按 E4 等级对其进行过滤。我需要怎样做?

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>
      MOS Status - Test
    </title>

    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.18/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/4.18/"></script>

    <style>
      html,
      body,
      
    #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }

    #grade-filter{
      height: 315px;
      width: 150%;
      visibility: hidden;
      }

    .grade-item {
      width: 100%;
      padding: 12px;
      text-align: center;
      vertical-align: baseline;
      cursor: pointer;
      height: 40px;
      }

    .grade-item:focus {
      background-color: dimgrey;
    }

    .grade-item:hover {
      background-color: dimgrey;
    }
      
    #major-command-filter{
      height: 315px;
      width: 150%;
      visibility: hidden;
      }
    .majorCommand-item {
      width: 100%;
      padding: 12px;
      text-align: center;
      vertical-align: baseline;
      cursor: pointer;
      height: 40px;
     
    }

    .majorCommand-item:focus {
      background-color: dimgrey;
    }

    .majorCommand-item:hover {
      background-color: dimgrey;
    }

      .esri-editor .esri-item-list__scroller {
        max-height: 350px;
      }

      #info {
        padding: 14px;
        border-radius: 5px;
        width: 25%;
      }
    </style>

    <script>
      require([
        "esri/Map",
        "esri/layers/FeatureLayer",
        "esri/form/FormTemplate",
        "esri/widgets/Editor",
        "esri/views/MapView",
        "esri/widgets/Expand",
        "esri/popup/content/TextContent",
      ], function (
        Map,
        FeatureLayer,
        FormTemplate,
        Editor,
        MapView,
        Expand,
        TextContent,
      ) {
        const editThisAction = {
          title: "Edit feature",
          id: "edit-this",
          className: "esri-icon-edit",
        };

        let editor, features, majorCommandView, gradeView;
        // Create a popTemplate
        const template = {
          title: "MOS Vacancy: {mos}",
          content:
            "<ul><li>Grade: <b>{grade}</b></li>" +
            "<li>Unit: <b>{unit}</b></li>" +
            "<li>Major Command: <b>{macom}</b></li>" +
            "<li>City: <b>{city}</b></li><ul>",
          actions: [editThisAction],
        };

        // Create a map from the referenced webmap item id
        const featureLayer = new FeatureLayer({
          url:
            "https://ncguardview.nc.gov/server/rest/services/Hosted/test/FeatureServer/0",
          outFields: ["*"],
          displayField: "mos",
          popupTemplate: template,
          formTemplate: {
            title: "NCNG MOS Vacancy",
            description: "Provide information for MOS Vacancy",
            elements: [
              {
                // Autocasts to new GroupElement
                type: "group",
                label: "Military Occupation Specaility",
                //description: "Field inspector information",
                elements: [
                  {
                    // Autocasts to new FieldElement
                    type: "field",
                    fieldName: "mos",
                    label: "MOS",
                  },
                  {
                    type: "field",
                    fieldName: "series",
                    label: "MOS Branch",
                  },
                  {
                    type: "field",
                    fieldName: "jobtitle",
                    label: "MOS Job Title",
                  },
                  {
                    type: "field",
                    fieldName: "grade",
                    label: "MOS Grade",
                  },
                ],
              }, // end of first group element
              {
                type: "group",
                label: "Unit",
                elements: [
                  {
                    type: "field",
                    fieldName: "unit",
                    label: "Unit",
                  },
                  {
                    type: "field",
                    fieldName: "battalion",
                    label: "Battalion",
                  },
                  {
                    type: "field",
                    fieldName: "macom",
                    label: "Major Command",
                  },
                ],
              }, // End of Second Group
              {
                type: "group",
                label: "Location",
                elements: [
                  {
                    type: "field",
                    fieldName: "address",
                    label: "Unit Address",
                  },
                  {
                    type: "field",
                    fieldName: "city",
                    label: "Unit City",
                  },
                  {
                    type: "field",
                    fieldName: "county",
                    label: "Unit County",
                  },
                ],
              }, // End of Second Group,
              {
                type: "group",
                label: "Status",
                elements:[{
                  type: "field",
                  fieldName: "vacancy",
                  label: "Vacancy Status",
                }]
              }
            ],
          },
        });
         // Create the Map
        const map = new Map({
          basemap: "streets-night-vector",
          layers: [featureLayer]
        });
        //map.add(featureLayer);

        const view = new MapView({
          container: "viewDiv",
          map: map,
          zoom: 6,
          center: [-79, 35],
        });
        ///////////////////////////////////////////////////////////////////
        /*                    Grade Filter                  */
        
        // Doesn't really filter out Grade. The filter still inlcudes 
        // whatever grades are at that location
        const gradeNode = document.querySelectorAll(`.grade-item`);
        const gradeElement = document.getElementById("grade-filter");
        gradeElement.addEventListener('click', filterByGrade); // handle user choice
        // Handle selection for user filter
        function filterByGrade(event) {
          const selectedGrade = event.target.getAttribute("data-grade");
          gradeView.filter = {
            where: "grade = '"+ selectedGrade +"'",
          };
        };
        view.whenLayerView(featureLayer).then(function (layerView) {
          gradeView = layerView;
          // set up UI items
          gradeElement.style.visibility = 'visible';
          const gradeExpand = new Expand({
            view: view,
            content: gradeElement,
            expandIconClass: "esri-icon-filter",
            group: "top-left",
          });
          
          // clear filters
          gradeExpand.watch("expanded", function(){
            if(!gradeExpand.expanded) {
              gradeView.filter = null;
            };
          });
          view.ui.add(gradeExpand, 'top-left');
        });
        
        ///////////////////////////////////////////////////////////////////
        const majComNode = document.querySelectorAll(`.majorCommand-item`);
        const majComElement = document.getElementById("major-command-filter");

        // click event handler for seasons choices
        majComElement.addEventListener("click", filterByCommand);

        // User clicked on Major Commands 30th, 449th, 13th, and etc..
        // set an attribute filter on major command layer view
        function filterByCommand(event) {
          const selectedCommand = event.target.getAttribute("data-command");
          majorCommandView.filter = {
            where: "macom = '" + selectedCommand + "'",
          };
        }

        view.whenLayerView(featureLayer).then(function (layerView) {
          majorCommandView = layerView;

          // set up UI items
          majComElement.style.visibility = "visible";
          const majCommandExpand = new Expand({
            view: view,
            content: majComElement,
            expandIconClass: "esri-icon-filter",
            group: "top-left",
          });
          // clear the filters
          majCommandExpand.watch( "expanded", function() {
            if(!majCommandExpand.expanded) {
              majorCommandView.filter = null;
            }
          });
          view.ui.add(majCommandExpand, 'top-left')
          //////////////////////////////////////////
        /* Stop with Filter and Begin with Editor */
   /////////////////////////////////////////////////////
        view.when(function () {
          view.popup.autoOpenEnabled = true; //disable popups

          // Create the Editor
          let editor = new Editor({
            view: view,
            container: document.createElement("div"),
            layerInfos: [
              {
                layer: featureLayer,
                deleteEnabled: true,
                addEnabled: true,
              },
            ],
          });
          // Add widget to top-right of the view
          //view.ui.add(editor, "bottom-right");

          // Execute each time the "Edit Feature" action is called
          function editThis() {
            // If the EditorViewModel's activeWorkflow is null, make the popup not visible
            if (!editor.viewModel.activeWorkFlow) {
              view.popup.visible =false;

              editor.startUpdateWorkflowAtFeatureEdit(
                view.popup.selectedFeature
              );

              view.ui.add(editor, "bottom-right");
              view.popup.spinnerEnabled = true;
            }

            // We need to set a timeout to ensure the editor widget is fully rendered. We
            // then grab it from the DOM stack
            setTimeout(function () {
              // Use the editor's back button as a way to cancel out of editing
              let arrComp = editor.domNode.getElementsByClassName(
                "esri-editor__back-button esri-interactive"
              );
              if (arrComp.length === 1) {
                // Add a tooltip for the back button
                arrComp[0].setAttribute(
                  "title",
                  "Cancel edits, return to popup"
                );
                // Add a listerner to listen for when the editor's back button is clicked
                arrComp[0].addEventListener("click", function (evt) {
                  console.log(evt);
                  // Prevent the default behavior for the back button and instead remove the editor and reopen the popup
                  evt.preventDefault();
                  //view.ui.remove(editor);
                  view.popup.open({
                    features: features,
                  });
                });
              }
            }, 150);
          }
          // Event handler that fires each time an action is clicked
          view.popup.on("trigger-action", function (event) {
            if (event.action.id === "edit-this") {
              editThis();
            }
          });

          // Watch when the popup is visible
          view.popup.watch("visible", function (event) {
            // Check the Editor's viewModel state, if it is currently open and editing existing features, disable popups
            if (editor.viewModel.state === "editing-existing-feature") {
              view.popup.close();
            } else {
              // Grab the features of the popup
              features = view.popup.features;
            }
          });
          featureLayer.on("apply-edits", function () {
            // Once edits are applied to the layer, remove the Editor from the UI
            //view.ui.remove(editor);

            // Iterate through the features
            features.forEach(function (feature) {
              // Reset the template for the feature if it was edited
              feature.popupTemplate = template;
            });

            // Open the popup again and reset its content after updates were made on the feature
            if (features) {
              view.popup.open({
                features: features,
              });
            }

            // Cancel the workflow so that once edits are applied, a new popup can be displayed
            editor.viewModel.cancelWorkflow();
          });
        });
        });
        view.ui.add("info", {
          position: "bottom-left",
          index: 1,
        });
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div id="major-command-filter" class="esri-widget">
      <div class="majorCommand-item visible-command" data-command="30 ABCT">30 ABCT</div>
      <div class="majorCommand-item visible-command" data-command="130 MEB">130 MEB</div>
      <div class="majorCommand-item visible-command" data-command="113 SB">113 SB</div>
      <div class="majorCommand-item visible-command" data-command="60 TC">60 TC</div>
      <div class="majorCommand-item visible-command" data-command="449 TAB">449 TAB</div>
      <div class="majorCommand-item visible-command" data-command="139 REG">139 REG</div>
      <div class="majorCommand-item visible-command" data-command="JFHQ">JFHQ</div>
      <div class="majorCommand-item visible-command" data-command="TEST">TEST</div>
    </dvi>
    <div id="grade-filter" class="esri-widget">
        <div class="grade-item visible-grade" data-grade="E1">E1</div>
        <div class="grade-item visible-grade" data-grade="E2">E2</div>
        <div class="grade-item visible-grade" data-grade="E3">E3</div>
        <div class="grade-item visible-grade" data-grade="E4">E4</div>
        <div class="grade-item visible-grade" data-grade="E5">E5</div>
        <div class="grade-item visible-grade" data-grade="E6">E6</div>
        <div class="grade-item visible-grade" data-grade="E7">E7</div>
        <div class="grade-item visible-grade" data-grade="E8">E8</div>
    </dvi>
    <div id="info" class="esri-widget">
      <h3>Select a feature to display its popup</h3>
      <h4>
        Edit the feature by clicking on the "Edit feature" action within the
        popup.
      </h4>
    </div>
  </body>
</html>

你的想法是对的,只是两点:

  • 你只需要一个“AND”条件来混合主要命令和成绩
  • 如果您想对展开进行分组,则需要使用另一种机制来重置过滤器,例如重置按钮或类似按钮。这是因为一组中只会打开一个展开。

看看我为您编写的代码,基于您的代码,但只简化了过滤器逻辑。

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>
    MOS Status - Test
  </title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css" />
  <script src="https://js.arcgis.com/4.18/"></script>

  <style>
    html,
    body,

    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }

    #grade-filter {
      height: 315px;
      width: 150%;
    }

    .grade-item {
      width: 100%;
      padding: 12px;
      text-align: center;
      vertical-align: baseline;
      cursor: pointer;
      height: 40px;
    }

    .grade-item:focus {
      background-color: dimgrey;
    }

    .grade-item:hover {
      background-color: dimgrey;
    }

    #major-command-filter {
      height: 315px;
      width: 150%;
    }

    .majorCommand-item {
      width: 100%;
      padding: 12px;
      text-align: center;
      vertical-align: baseline;
      cursor: pointer;
      height: 40px;

    }

    .majorCommand-item:focus {
      background-color: dimgrey;
    }

    .majorCommand-item:hover {
      background-color: dimgrey;
    }
  </style>

  <script>
    require([
      "esri/Map",
      "esri/layers/FeatureLayer",
      "esri/views/MapView",
      "esri/widgets/Expand"
    ], function (
      Map,
      FeatureLayer,
      MapView,
      Expand
    ) {

      // map & layer set up

      const featureLayer = new FeatureLayer({
        url: "https://ncguardview.nc.gov/server/rest/services/Hosted/test/FeatureServer/0",
        outFields: ["*"]
      });
      const map = new Map({
        basemap: "streets-night-vector",
        layers: [featureLayer]
      });
      const view = new MapView({
        container: "viewDiv",
        map: map,
        zoom: 6,
        center: [-79, 35],
      });
      let flView = null;
      view.whenLayerView(featureLayer).then(layerView => flView = layerView);
      
      // filter logic

      let selectedGrade = null;
      let selectedCommand = null;
      const updateFilter = function() {
        let conditions = [];
        if (selectedGrade) {
          conditions.push(`(grade='${selectedGrade}')`);
        }
        if (selectedCommand) {
          conditions.push(`(macom='${selectedCommand}')`);
        }
        flView.filter = conditions.length > 0 ? {where: conditions.join("AND")} : null;
        console.log(flView.filter && flView.filter.where);
      }

      // click event handlers

      const filterByGrade = (event) => {
        selectedGrade = event.target.getAttribute("data-grade");
        updateFilter();
      }
      const filterByCommand = (event) => {
        selectedCommand = event.target.getAttribute("data-command");
        updateFilter();
      }

      // grade ui set up

      const gradeElement = document.getElementById("grade-filter");
      const gradeExpand = new Expand({
        view: view,
        content: gradeElement,
        expandIconClass: "esri-icon-filter",
        // group: "top-left",
      });
      gradeExpand.watch("expanded", expanded => {
        if (!expanded) {
          selectedGrade = null;
          updateFilter();
        }
      });
      view.ui.add(gradeExpand, 'top-left');

      // major command ui set up

      const majComElement = document.getElementById("major-command-filter");
      const majCommandExpand = new Expand({
        view: view,
        content: majComElement,
        expandIconClass: "esri-icon-filter",
        // group: "top-left",
      });
      majCommandExpand.watch("expanded", expanded => {
        if (!expanded) {
          selectedCommand = null;
          updateFilter();
        }
      });
      view.ui.add(majCommandExpand, 'top-left');

      // listen click events

      gradeElement.addEventListener('click', filterByGrade);
      majComElement.addEventListener("click", filterByCommand);
      
    });
  </script>
</head>

<body>
  <div id="viewDiv"></div>
  <div id="major-command-filter" class="esri-widget">
    <div class="majorCommand-item visible-command" data-command="30 ABCT">30 ABCT</div>
    <div class="majorCommand-item visible-command" data-command="130 MEB">130 MEB</div>
    <div class="majorCommand-item visible-command" data-command="113 SB">113 SB</div>
    <div class="majorCommand-item visible-command" data-command="60 TC">60 TC</div>
    <div class="majorCommand-item visible-command" data-command="449 TAB">449 TAB</div>
    <div class="majorCommand-item visible-command" data-command="139 REG">139 REG</div>
    <div class="majorCommand-item visible-command" data-command="JFHQ">JFHQ</div>
    <div class="majorCommand-item visible-command" data-command="TEST">TEST</div>
  </div>
  <div id="grade-filter" class="esri-widget">
    <div class="grade-item visible-grade" data-grade="E1">E1</div>
    <div class="grade-item visible-grade" data-grade="E2">E2</div>
    <div class="grade-item visible-grade" data-grade="E3">E3</div>
    <div class="grade-item visible-grade" data-grade="E4">E4</div>
    <div class="grade-item visible-grade" data-grade="E5">E5</div>
    <div class="grade-item visible-grade" data-grade="E6">E6</div>
    <div class="grade-item visible-grade" data-grade="E7">E7</div>
    <div class="grade-item visible-grade" data-grade="E8">E8</div>
  </div>
</body>

</html>