Custom Field List with prefiltering + custom filter view

Custom UI controls and views

by Flexmonster Pivot Table

HTML

<script src="https://cdn.flexmonster.com/flexmonster.js"></script>

<div>
  <h2>
    Creating a custom Field List with prefiltering and a custom filter view
  </h2>
  <p>
    This example shows how to create a custom Field List where users can
    prefilter fields. Also, the sample demonstrates a custom filter view.
  </p>
  <p>
    <b>Step 1.</b> The
    <a href="https://www.flexmonster.com/api/fieldslistopen/" target="_blank"
    >fieldslistopen</a> and
    <a href="https://www.flexmonster.com/api/filteropen/" target="_blank"
    >filteropen</a> events are handled (lines 32-44 in the JavaScript box) 
    to override the default Field List and filter view. Instead, the event 
    handlers call the <code>openFieldList()</code> and <code>openFilter()</code>
    functions to open the custom views.
  </p>
  <p>
    <b>Step 2.</b> The <code>openFieldList()</code> function (lines 108-136)
    calls Flexmonster methods to build the list of available fields. It also
    uses two helper functions: <code>getFieldLocation()</code> (lines 248-265)
    determines the current placement of each field in the slice, and
    <code>createFieldItem()</code> (lines 149-210) renders the field. <br />To
    apply the new slice and filters to the pivot table, the
    <code>applySelectedFields()</code> function (lines 46-90) is called.
  </p>
  <p>
    <b>Step 3.</b> The <code>openFilter()</code> function (lines 138-147)
    creates the custom selection filter view. It calls
    <a href="https://www.flexmonster.com/api/getmembers/" target="_blank"
    >getMembers()</a> to fetch members of the selected field, and then
    <code>createFilterItem()</code> (lines 212-233) to render each member. On
    apply, the <code>applyFilter()</code> function (lines 92-106) keeps only
    selected members in the slice.
  </p>
  <p>
    Learn more about
    <a
      href="https://www.flexmonster.com/doc/creating-a-custom-ui-control-or-view"
     ...

CSS

@import url(https://cdn.flexmonster.com/assets/jsfiddle-styles.css);

h3 {
  display: inline;
}

#fm-pivot-view .fm-fields-view-wrap.fm-fields-opened,
#fm-pivot-view div.fm-ui-modal-overlay {
  display: none !important;
}

#wrapper {
  height: 580px;
  position: relative;
}

#field-list,
#filter-list {
  position: absolute;
  inset: 0 0 0 0;
  margin: auto;
  min-width: 400px;
  width: 60%;
  height: 400px;
  z-index: 3;
  background: white;
  padding: 30px;
  display: none;
  border: 1px solid #d5d5d5;
  box-shadow: 0 0 20px rgb(0 0 0 / 10%);
  transition: width 0.3s ease-in-out;
}

#field-list {
  z-index: 5;
}

#filter-list {
  z-index: 10;
}

#backdrop {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  background-color: #fff;
  opacity: 0.6;
}

#fields,
#filters {
  margin-top: 30px;
  height: 300px;
  padding: 15px;
  overflow: auto;
  border: 1px solid #d5d5d5;
}

#fields h4,
#filters h4 {
  margin-bottom: 0;
  margin-top: 0;
}

.button {
  user-select: none;
  font: inherit;
  transition: none;
  border-collapse: collapse;
  border-spacing: 0;
  font-family: Arial, sans-serif;
  margin: 0;
  text-shadow: none;
  line-height: normal;
  box-sizing: border-box;
  text-transform: uppercase;
  position: relative;
  outline: none;
  border-radius: 4px;
  cursor: pointer;
  text-align: center;
  display: inline-block;
  vertical-align: top;
  font-size: 14px;
  font-weight: bold;
  padding: 10px 12px;
  letter-spacing: 0.5px;
  min-width: 90px;
  border: 1px solid #555;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  margin-right: 20px;
  height: 38px;
  color: unset;
  border-color: unset;
}

.button.apply {
  float: right;
  color: #fff;
  background: #555;
  border: 1px solid #555;
}

.button.apply:hover {
  background-color: #3c3c3c;
  border-color: #3c3c3c;
  cursor:...

JavaScript

const pivot = new Flexmonster({
  container: "pivot-container",
  componentFolder: "https://cdn.flexmonster.com/",
  height: "100%",
  licenseFilePath: "https://cdn.flexmonster.com/jsfiddle.charts.key",
  global: {
    options: {
      showDefaultSlice: false,
    },
  },
  report: {
    dataSource: {
      filename: "data/sales.csv",
    },
    slice: {
      columns: [],
      rows: [],
      measures: [],
      reportFilters: [],
    },
  },
});

const filtersConfig = {};
const fieldList = document.getElementById("field-list");
const fields = document.getElementById("fields");
const filterList = document.getElementById("filter-list");
const filters = document.getElementById("filters");
const backdrop = document.getElementById("backdrop");
let currentHierarchy = null;

pivot.on("fieldslistopen", () => {
  pivot.closeFieldsList();
  openFieldList();
});

pivot.on("filteropen", (event) => {
  const element = document.querySelector(".fm-filter-view");
  if (element) {
    element.remove();
  }
  currentHierarchy = event.hierarchy;
  openFilter(currentHierarchy.uniqueName, true);
});

function applySelectedFields() {
  const slice = {
    columns: [],
    rows: [],
    measures: [],
    reportFilters: [],
  };

  document.querySelectorAll(".field-select").forEach((selectElement) => {
    if (selectElement.value !== "none") {
      const config = JSON.parse(selectElement.value);
      if (config.place == "measures") {
        slice[config.place].push({
          uniqueName: config.uniqueName,
          aggregation: config.aggregation,
        });
      } else {
        slice[config.place].push({
          uniqueName: config.uniqueName,
          filter: {
            exclude: filtersConfig[config.uniqueName],
          },
        });
      }
    }
  });

  if (slice.measures.length > 0) {
    backdrop.style.display = "none";
    pivot.runQuery(slice);
    closeFieldList();
  } else {
   ...