text: /*global define */
  define(['jquery', 'underscore', 'backbone',
          'models/filters/Filter',
          'models/filters/FilterGroup',
          'views/filters/FilterGroupView',
        'views/filters/FilterView'],
    function($, _, Backbone, Filter, FilterGroup, FilterGroupView, FilterView) {
    'use strict';
  
    /**
    * @class FilterGroupsView
    * @classdesc Creates a view of one or more FilterGroupViews
    * @classcategory Views/Filters
    * @name FilterGroupsView
    * @extends Backbone.View
    * @constructor
    */
    var FilterGroupsView = Backbone.View.extend(
      /** @lends FilterGroupsView.prototype */{
  
      /**
      * The FilterGroup models to display in this view
      * @type {FilterGroup[]}
      */
      filterGroups: [],
  
      /**
      * The Filters Collection that contains the same Filter
      * models from each FilterGroup and any additional Filter Models that may not be in
      * FilterGroups because they're not displayed or applied behind the scenes.
      * @type {Filters}
      */
      filters: null,
  
      /**
      * @inheritdoc
      */
      tagName: "div",
  
      /**
      * @inheritdoc
      */
      className: "filter-groups tabbable",
  
      /**
      * If true, displays the FilterGroups in a vertical list
      * @type {Boolean}
      */
      vertical: false,
  
      /**
      * @inheritdoc
      */
      events: {
        "click .remove-filter" : "handleRemove",
        "click .clear-all"     : "removeAllFilters"
      },
  
      /**
      * @inheritdoc
      */
      initialize: function (options) {
  
        if( !options || typeof options != "object" ){
          var options = {};
        }
  
        this.filterGroups = options.filterGroups || new Array();
        this.filters = options.filters || null;
  
        if( options.vertical == true ){
          this.vertical = true;
        }
  
        this.parentView = options.parentView || null;
  
      },
  
      /**
      * @inheritdoc
      */
      render: function () {
  
        //Since this view may be re-rendered at some point, empty the element and remove listeners
        this.$el.empty();
        this.stopListening();
  
        //Create an unordered list for all the filter tabs
        var groupTabs = $(document.createElement("ul")).addClass("nav nav-tabs filter-group-links");
  
        //Create a container div for the filter groups
        var filterGroupContainer = $(document.createElement("div")).addClass("tab-content");
  
        //Add the filter group elements to this view
        this.$el.append(groupTabs, filterGroupContainer);
  
        var divideIntoGroups = true;
  
        _.each( this.filterGroups, function(filterGroup){
  
          //If there is only one filter group specified, and there is no label or icon,
          // then don't divide the filters into separate filter groups
          if( this.filterGroups.length == 1 && !this.filterGroups[0].get("label") &&
              !this.filterGroups[0].get("icon") ){
            divideIntoGroups = false;
          }
  
          if( divideIntoGroups ){
            //Create a link to the filter group
            var groupTab  = $(document.createElement("li")).addClass("filter-group-link");
            var groupLink = $(document.createElement("a"))
                                .attr("href", "#" + filterGroup.get("label").replace( /([^a-zA-Z0-9])/g, "") )
                                .attr("data-toggle", "tab");
  
            //Add the FilterGroup icon
            if( filterGroup.get("icon") ){
              groupLink.append( $(document.createElement("i")).addClass("icon icon-" + filterGroup.get("icon")) );
            }
  
            //Add the FilterGroup label
            if( filterGroup.get("label") ){
              groupLink.append(filterGroup.get("label"));
            }
  
            //Insert the link into the tab and add the tab to the tab list
            groupTab.append(groupLink);
            groupTabs.append(groupTab);
  
            //Create a tooltip for the link
            groupTab.tooltip({
              placement: "top",
              title: filterGroup.get("description"),
              trigger: "hover",
              delay: {
                show: 800
              }
            });
  
            //Make all the tab widths equal
            groupTab.css("width", (100 / this.filterGroups.length) + "%");
          }
  
          //Create a FilterGroupView
          var filterGroupView = new FilterGroupView({
            model: filterGroup
          });
  
          //Render the FilterGroupView
          filterGroupView.render();
  
          //Add the FilterGroupView element to this view
          filterGroupContainer.append(filterGroupView.el);
  
          //Store a reference to the FilterGroupView in the tab link
          if( divideIntoGroups ){
            groupLink.data("view", filterGroupView);
          }
  
          //If a new filter is ever added to this filter group, re-render this view
          this.listenTo( filterGroup.get("filters"), "add remove", this.render );
  
        }, this);
  
        if( divideIntoGroups ){
          //Mark the first filter group as active
          groupTabs.children("li").first().addClass("active");
  
          //When each filter group tab is shown, perform any post render function, if needed.
          this.$('a[data-toggle="tab"]').on('shown', function (e) {
            //Get the filter group view
            var filterGroupView = $(e.target).data("view");
  
            //If there is a post render function, call it
            if( filterGroupView && filterGroupView.postRender ){
              filterGroupView.postRender();
            }
  
          });
        }
  
        //Mark the first filter group as active
        var firstFilterGroupEl = filterGroupContainer.find(".filter-group").first();
        firstFilterGroupEl.addClass("active");
        var activeFilterGroup = firstFilterGroupEl.data("view");
  
        //Call postRender() now for the active FilterGroup, since the `shown` event
        // won't trigger until/unless it's hidden then shown again.
        if( activeFilterGroup ){
          activeFilterGroup.postRender();
        }
  
        //Add a header element above the filter groups
        this.$el.prepend( $(document.createElement("div")).addClass("filters-header") );
  
        //Render the applied filters
        this.renderAppliedFiltersSection();
  
        //Render an "All" filter
        this.renderAllFilter();
  
        if( this.vertical ){
          this.$el.addClass("vertical");
        }
  
      },
  
      /**
      * Renders the section of the view that will display the currently-applied filters
      */
      renderAppliedFiltersSection: function(){
  
        //Add a title to the header
        var appliedFiltersContainer = $(document.createElement("div")).addClass("applied-filters-container"),
            headerText = $(document.createElement("h5"))
                          .addClass("filters-title")
                          .text("Current search")
                          .append( $(document.createElement("a"))
                                    .text("Clear all")
                                    .addClass("clear-all")
                                    .prepend( $(document.createElement("i"))
                                                .addClass("icon icon-remove icon-on-left") ));
  
        //Make the applied filters list
        var appliedFiltersEl = $(document.createElement("ul")).addClass("applied-filters");
  
        //Add the applied filters element to the filters header
        appliedFiltersContainer.append(headerText, appliedFiltersEl);
        this.$(".filters-header").append(appliedFiltersContainer);
  
        //Get all the nonNumeric filter models
        var nonNumericFilters = this.filters.reject(function(filterModel){
          return (filterModel.type == "NumericFilter" || filterModel.type == "DateFilter");
        });
        //Listen to changes on the "values" attribute for nonNumeric filters
        _.each(nonNumericFilters, function(nonNumericFilter){
          this.listenTo(nonNumericFilter, "change:values", this.updateAppliedFilters);
  
          if( nonNumericFilter.get("values").length ){
            this.updateAppliedFilters(nonNumericFilter, { displayWithoutChanges: true });
          }
        }, this);
  
        //Get the numeric filters and listen to the min and max values
        var numericFilters = _.where(this.filters.models, { type: "NumericFilter" });
        _.each(numericFilters, function(numericFilter){
  
          if( numericFilter.get("range") == true ){
            this.listenTo(numericFilter, "change:min change:max", this.updateAppliedRangeFilters);
  
            var filterDefaults = numericFilter.defaults();
  
            if( numericFilter.get("min") != filterDefaults.min ||
                numericFilter.get("max") != filterDefaults.max ||
                numericFilter.get("values").length ){
              this.updateAppliedRangeFilters(numericFilter, { displayWithoutChanges: true });
            }
          }
          else{
            this.listenTo(numericFilter, "change:values", this.updateAppliedRangeFilters);
  
            if( numericFilter.get("values")[0] != numericFilter.defaults().values[0] ){
              this.updateAppliedRangeFilters(numericFilter, { displayWithoutChanges: true });
            }
          }
  
        }, this);
  
        //Get the date filters and listen to the min and max values
        var dateFilters = _.where(this.filters.models, { type: "DateFilter" });
        _.each(dateFilters, function(dateFilter){
          this.listenTo(dateFilter, "change:min change:max", this.updateAppliedRangeFilters);
  
          if( dateFilter.get("min") != dateFilter.defaults().min ||
              dateFilter.get("max") != dateFilter.defaults().max ){
            this.updateAppliedRangeFilters(dateFilter, { displayWithoutChanges: true });
          }
        }, this);
  
        //When a Filter has been removed from the Filters collection, remove it's DOM element from the page
        this.listenTo(this.filters, "remove", function(removedFilter){
          this.removeAppliedFilterElByModel(removedFilter);
        });
  
      },
  
      renderAllFilter: function(){
  
        //Create an "All" filter that will search the general `text` Solr field
        var filter = new Filter({
          fields: ["text"],
          label: "Search",
          description: "Search the datasets by typing in any keyword, topic, creator, etc.",
          placeholder: "Search these datasets"
        });
        this.filters.add( filter );
  
        //Create a FilterView for the All filter
        var filterView = new FilterView({
          model: filter
        });
        this.listenTo(filter, "change:values", this.updateAppliedFilters);
  
        //Render the view and add the element to the filters header
        filterView.render();
        this.$(".filters-header").prepend(filterView.el);
  
      },
  
      postRender: function(){
  
        var groupTabs = this.$(".filter-group-links");
  
        //Check if there is a difference in heights
        var maxHeight = 0;
  
        _.each( groupTabs.find("a"), function(link){
  
          if( $(link).height() > maxHeight ){
            maxHeight = $(link).height();
          }
  
        });
  
        //Set the height of each filter group link so they are all equal
        _.each( groupTabs.find("a"), function(link){
  
          if( $(link).height() < maxHeight ){
            $(link).height(maxHeight + "px");
          }
  
        });
      },
  
      /**
      * Renders the values of the given Filter Model in the current filter model
      *
      * @param {Filter} filterModel - The FilterModel to display
      * @param {object} options - Additional options for this function
      * @property {boolean} options.displayWithoutChanges - If true, this filter will display even if the value hasn't been changed
      */
      updateAppliedFilters: function(filterModel, options){
        
        //Create an options object if one wasn't sent
        if( typeof options != "object" ){
          var options = {};
        }
  
        //If the value of this filter has changed, or if the displayWithoutChanges option
        // was passed, and if the filter is not invisible, then display it
        if( !filterModel.get("isInvisible") &&
            ((filterModel.changed && filterModel.changed.values) ||
            options.displayWithoutChanges) ){
  
          //Get the new values and the previous values
          var newValues      = options.displayWithoutChanges? filterModel.get("values") : filterModel.changed.values,
              previousValues = options.displayWithoutChanges? [] : filterModel.previousAttributes().values,
              //Find the values that were removed
              removedValues  = _.difference(previousValues, newValues),
              //Find the values that were added
              addedValues    = _.difference(newValues, previousValues);
  
          //If a filter has been added, display it
          _.each(addedValues, function(value){
  
            //Add the applied filter to the view
            this.$(".applied-filters").append( this.createAppliedFilter(filterModel, value) );
  
          }, this);
  
          //Iterate over each removed filter value and remove them
          _.each(removedValues, function(value){
  
            //Find all applied filter elements with a matching value
            var matchingFilters = this.$(".applied-filter[data-value='" + value + "']");
  
            //Iterate over each filter element with a matching value
            _.each(matchingFilters, function(matchingFilter){
  
              //If this is the filter element associated with this filter model, then remove it
              if( $(matchingFilter).data("model") == filterModel ){
                $(matchingFilter).remove();
              }
  
            });
  
          }, this);
  
        }
  
        //Toggle the applied filters header
        this.toggleAppliedFiltersHeader();
  
      },
  
      /**
       * Hides or shows the applied filter list title/header, as well as the help
       * message that lets the user know they can add filters when there are none
       */
      toggleAppliedFiltersHeader: function(){
  
        //If there is an applied filter
        if( this.$(".applied-filter").length ){
          // hide the "add some filters" help text
          //$(this.parentView.helpTextContainer).css("display", "none");
          // show the Clear All button
          this.$(".filters-title").css("display", "block");
        }
        //If there are no applied filters
        else{
          // show the "add some filters" help text
        //  $(this.parentView.helpTextContainer).css("display", "block");
          // hide the Clear All button
          this.$(".filters-title").css("display", "none");
        }
  
      },
  
      /**
      * When a NumericFilter or DateFilter model is changed, update the applied filters in the UI
      * @param {DateFilter|NumericFilter} filterModel - The model whose values to display
      * @param {object} [options] - Additional options for this function
      * @property {boolean} [options.displayWithoutChanges] - If true, this filter will display even if the value hasn't been changed
      */
      updateAppliedRangeFilters: function(filterModel, options){
  
        if( !filterModel ){
          return;
        }
  
        if( typeof options === "undefined" || !options ){
          var options = {};
        }
  
        //If the Filter is invisible, don't render it
        if( filterModel.get("isInvisible") ){
          return;
        }
  
        //If the minimum and maximum values are set to the default, remove the filter element
        if( filterModel.get("min") == filterModel.get("rangeMin") &&
            filterModel.get("max") == filterModel.get("rangeMax")){
  
          //Find the applied filter element for this filter model
          _.each(this.$(".applied-filter"), function(filterEl){
  
            if( $(filterEl).data("model") == filterModel ){
              //Remove the applied filter element
              $(filterEl).remove();
            }
  
          }, this);
  
        }
        //If the values attribue has changed, or if the displayWithoutChanges attribute was passed
        else if( (filterModel.changed && (filterModel.changed.min || filterModel.changed.max)) ||
                  options.displayWithoutChanges ){
  
          //Create the filter label for ranges of numbers
          var filterValue = filterModel.getReadableValue();
  
          //Create the applied filter
          var appliedFilter = this.createAppliedFilter(filterModel, filterValue);
  
          //Keep track if this filter is already displayed and needs to be replaced
          var replaced = false;
  
          //Check if this filter model already has an applied filter in the UI
          _.each(this.$(".applied-filter"), function(appliedFilterEl){
  
            //If this applied filter already is displayed, replace it
            if( $(appliedFilterEl).data("model") == filterModel ){
              //Replace the applied filter element with the new one
              $(appliedFilterEl).replaceWith(appliedFilter);
              replaced = true;
            }
  
          }, this);
  
          if( !replaced ){
            //Add the applied filter to the view
            this.$(".applied-filters").append(appliedFilter);
          }
  
        }
  
        this.toggleAppliedFiltersHeader();
  
      },
  
      /**
      * Creates a single applied filter element and returns it. Filters can
      *  have multiple values, so one value is passed to this function at a time.
      * @param {Filter} filterModel - The Filter model that is being added to the display
      * @param {string|number|Boolean} value - The new value set on the Filter model that is displayed in this applied filter
      * @returns {jQuery} - The complete applied filter element
      */
      createAppliedFilter: function(filterModel, value){
  
        //Create the filter label
        var filterLabel = filterModel.get("label"),
            filterValue = value;
  
        //If the filter type is Choice, get the choice label which can be different from the value
        if( filterModel.type == "ChoiceFilter" ){
          //Find the choice object with the given value
          var matchingChoice = _.findWhere(filterModel.get("choices"), { "value" : value });
  
          //Get the label for that choice
          if(matchingChoice){
            filterValue = matchingChoice.label;
          }
        }
        //Create the filter label for boolean filters
        else if( filterModel.type == "BooleanFilter" ){
  
          //If the filter is set to false, remove the applied filter element
          if( filterModel.get("values")[0] === false ){
  
            //Iterate over the applied filters
            _.each(this.$(".applied-filter"), function(appliedFilterEl){
  
              //If this is the applied filter element for this model,
              if( $(appliedFilterEl).data("model") == filterModel ){
                //Remove the applied filter element from the page
                $(appliedFilterEl).remove();
              }
  
            }, this);
  
            //Exit the function at this point since there is nothing else to
            // do for false BooleanFilters
            return;
          }
          else if( filterModel.get("values")[0] === true ){
            if( !filterLabel ){
              filterLabel = filterModel.get("fields")[0];
              filterValue = "";
            }
          }
  
        }
        else if( filterModel.type == "ToggleFilter" ){
  
          if( filterModel.get("values")[0] == filterModel.get("trueValue") ){
            if( filterModel.get("label") && filterModel.get("trueLabel") ){
              filterValue = filterModel.get("trueLabel");
            }
            else if( !filterModel.get("label") && filterModel.get("trueLabel") ){
              filterLabel = "";
              filterValue = filterModel.get("trueLabel");
            }
            else if( filterModel.get("label") ){
              filterLabel = "";
              filterValue = filterModel.get("label");
            }
          }
          else{
            if( filterModel.get("label") && filterModel.get("falseLabel") ){
              filterValue = filterModel.get("falseLabel");
            }
            else if( !filterModel.get("label") && filterModel.get("falseLabel") ){
              filterLabel = "";
              filterValue = filterModel.get("falseLabel");
            }
            else if( filterModel.get("label") ){
              filterLabel = "";
              filterValue = filterModel.get("label");
            }
          }
  
        }
        //If this Filter model is a full-text search, don't display a label
        else if( filterModel.get("fields").length == 1 && filterModel.get("fields")[0] == "text"){
          filterLabel = "";
        }
        //isPartOf filters should just display the label, not the value
        else if( filterModel.get("fields").length == 1 && filterModel.get("fields")[0] == "isPartOf" ){
          filterValue = "";
        }
        //If the filter value is just an asterisk (i.e. `match anything`), just display the label
        else if( filterModel.get("values").length == 1 && filterModel.get("values")[0] == "*" ){
          filterValue = "";
        }
        else if( !filterLabel ){
          filterLabel = filterModel.get("fields")[0];
        }
  
        //Create the applied filter element
        var removeIcon    = $(document.createElement("a"))
                              .addClass("icon icon-remove remove-filter icon-on-right")
                              .attr("title", "Remove this filter"),
            appliedFilter = $(document.createElement("li"))
                              .addClass("applied-filter label")
                              .append(removeIcon)
                              .data("model", filterModel)
                              .attr("data-value", value);
  
        //Create an element to contain both the label and value
        var filterLabelEl = $(document.createElement("span")).addClass("label");
        var filterValueEl = $(document.createElement("span")).addClass("value").text(filterValue);
  
        var filterTextContainer = $(document.createElement("span"))
                                   .append(filterLabelEl, filterValueEl);
  
        //If there is both a label and value, separated them with a colon
        if( filterLabel && filterValue ){
          filterLabelEl.text( filterLabel + ": ");
        }
        //Otherwise just use the label text only
        else if( filterLabel ){
          filterLabelEl.text(filterLabel);
        }
  
        //Add the filter text to the filter element
        appliedFilter.prepend(filterTextContainer);
  
        // Add a tooltip to the filter
        if(filterModel.get("description")){
  
          appliedFilter.tooltip({
            placement: "right",
            title: filterModel.get("description"),
            trigger: "hover",
            delay: {
              show: 700
            }
          });
  
        }
  
        return appliedFilter;
      },
  
  
      /**
      * Adds a custom filter that likely exists outside of the FilterGroups but needs
      * to be displayed with these other applied fitlers.
      *
      * @param {Filter} filterModel - The Filter Model to display
      */
      addCustomAppliedFilter: function(filterModel){
  
        //If the Filter is invisible, don't render it
        if( filterModel.get("isInvisible") ){
          return;
        }
  
        //If this filter already exists in the applied filter list, exit this function
        var alreadyExists = _.find( this.$(".applied-filter.custom"), function(appliedFilterEl){
          return $(appliedFilterEl).data("model") == filterModel;
        });
  
        if( alreadyExists ){
          return;
        }
  
        //Create the applied filter element
        var removeIcon    = $(document.createElement("a"))
                              .addClass("icon icon-remove remove-filter icon-on-right")
                              .attr("title", "Remove this filter"),
            filterText    = $(document.createElement("span")).text(filterModel.get("label")),
            appliedFilter = $(document.createElement("li"))
                              .addClass("applied-filter label custom")
                              .append(filterText, removeIcon)
                              .data("model", filterModel)
                              .attr("data-value", filterModel.get("values"));
  
        if( filterModel.type == "SpatialFilter" ){
          filterText.prepend( $(document.createElement("i"))
                                .addClass("icon icon-on-left icon-" + filterModel.get("icon")) );
  
        }
  
        //Add the applied filter to the view
        this.$(".applied-filters").append(appliedFilter);
  
        //Display the filters title
        this.toggleAppliedFiltersHeader();
  
      },
  
      /**
      * Removes the custom applied filter from the UI.
      *
      * @param {Filter} filterModel - The Filter Model to display
      */
      removeCustomAppliedFilter: function(filterModel){
  
        _.each(this.$(".custom.applied-filter"), function(appliedFilterEl){
          if( $(appliedFilterEl).data("model") == filterModel ){
            $(appliedFilterEl).remove();
            this.trigger("customAppliedFilterRemoved", filterModel);
          }
        }, this);
  
        //Hide the filters title
        this.toggleAppliedFiltersHeader();
  
      },
  
      /**
      * When a remove button is clicked, get the filter model associated with it
      /* and remove the filter from the filter group
      *
      * @param {Event} - The DOM Event that occured on the filter remove icon
      */
      handleRemove: function(e){
  
        // Ensure tooltips are removed
        try{
          if(e.delegateTarget){
            $(e.delegateTarget).find(".tooltip").remove();
          }
        }
        catch(e) {
          console.log("Could not remove tooltip from filter label, error message: " + e);
        };
  
        //Get the applied filter element and the filter model associated with it
        var appliedFilterEl = $(e.target).parents(".applied-filter"),
            filterModel =  appliedFilterEl.data("model");
  
        if( appliedFilterEl.is(".custom") ){
          this.removeCustomAppliedFilter(filterModel);
        }
        else{
          //Remove the filter from the filter group model
          this.removeFilter(filterModel, appliedFilterEl);
        }
  
      },
  
      /**
      * Remove the filter from the UI and the Search collection
      * @param {Filter} filterModel The Filter to remove from the Filters collection
      * @param {Element} appliedFilterEl The DOM Element for the applied filter on the page
      * @param {object} options Additional options for this function
      * @param {boolean} options.removeSilently If true, the Filter model will be removed siltently from the Filters collection.
      *  This is useful when removing multiple Filters at once, and triggering a remove/change/reset event after all have
      *  been removed.
      */
      removeFilter: function(filterModel, appliedFilterEl, options){
  
        var removeSilently = false;
  
        //Parse all the additional options for this function
        if( typeof options == "object" ){
          removeSilently = typeof options.removeSilently != "undefined"? options.removeSilently : false;
        }
  
  
        if( filterModel ){
  
          //NumericFilters and DateFilters get the min and max values reset
          if( filterModel.type == "NumericFilter" || filterModel.type == "DateFilter" ){
  
            //Set the min and max values
            filterModel.set({
              min: filterModel.get("rangeMin"),
              max: filterModel.get("rangeMax"),
              values: filterModel.defaults().values
            });
  
            if( !removeSilently ){
              //Trigger the reset event
              filterModel.trigger("rangeReset");
            }
  
          }
          //For all other filter types
          else{
            //Get the current value
            var modelValues = filterModel.get("values"),
                thisValue   = $(appliedFilterEl).data("value");
  
            //Numbers that are set on the element `data` are stored as type `number`, but when `number`s are
            // set on Backbone models, they are converted to `string`s. So we need to check for this use case.
            if( typeof thisValue == "number" ){
              //Convert the number to a string
              thisValue = thisValue.toString();
            }
  
            //Remove the value that was in this applied filter
            var newValues = _.without(modelValues, thisValue),
                setOptions = {};
  
            if( removeSilently ){
              setOptions.silent = true;
            }
  
            //Updates the values on the model
            filterModel.set("values", newValues, setOptions);
          }
  
        }
  
      },
  
      /**
      * Gets all the applied filters in this view and their associated filter models
      *   and removes them.
      */
      removeAllFilters: function(){
  
        //Iterate over each applied filter in the view
        _.each( this.$(".applied-filter"), function(appliedFilterEl){
  
          var $appliedFilterEl = $(appliedFilterEl);
  
          if( $appliedFilterEl.is(".custom") ){
            this.removeCustomAppliedFilter( $appliedFilterEl.data("model") );
          }
          else{
  
            //Remove the filter from the fitler group
            this.removeFilter( $appliedFilterEl.data("model"), appliedFilterEl, { removeSilently: true } );
  
          }
  
          //Remove the applied filter element from the page
          $appliedFilterEl.remove();
  
        }, this);
  
        //Trigger the reset event on the Filters collection
        this.filters.trigger("reset");
  
        //Toggle the applied filters header
        this.toggleAppliedFiltersHeader();
  
      },
  
      /**
      * Remove the applied filter element for the given model
      * This only removed the element from the page, it doesn't update the model at all or
      * trigger any events.
      * @param {Filter} - The Filter model whose elements will be deleted
      */
      removeAppliedFilterElByModel: function(filterModel){
  
        //Iterate over each applied filter element and find the matching filters
        this.$(".applied-filter").each(function(i, el){
          if( $(el).data("model") == filterModel ){
            //Remove the element from the page
            $(el).remove();
          }
        });
  
        //Toggle the applied filters header
        this.toggleAppliedFiltersHeader();
  
      }
  
    });
    return FilterGroupsView;
  });
  