1

I am new to view, so perhaps this is by design, but just in case. I have a component that takes a list of facets and then splits them up for a nice display. The code looks like this:

import { getFacets } from "@/logic/get-facets";
import {
  defineComponent,
  getCurrentInstance,
  ref,
  toRefs,
} from "@vue/composition-api";

import Filters from "@/components/filters/filters.component.vue";

export default defineComponent({
  name: "Chooser",
  components: { Filters },
  emits: ["onFilter"],
  props: {
    categoryName: {
      type: String,
      required: true,
    },
    facets: {
      type: Array,
      required: true,
    },
    loading: {
      type: Boolean,
      default: () => false,
    },
  },
  setup(props) {
    const instance = getCurrentInstance();
    const expanded = ref(false);
    const filters = ref([]);
    const scenarios = ref([]);
    const { facets } = toRefs(props);
    const { criteria } = getFacets(facets.value);

    const expand = () => {
      expanded.value = !expanded.value;
    };

    const addFilter = (attribute: any) => {
      let index = -1;
      for (let i = filters.value.length - 1; i >= 0; i--) {
        const filter = filters.value[i];
        if (filter.facetName !== attribute.facetName) continue;
        index = i;
        filters.value.splice(i, 1);
      }
      if (index === -1) filters.value.push(attribute);

      instance.proxy.$emit("onFilter", filters.value);
    };

    return { expanded, criteria, filters, scenarios, expand, addFilter };
  },
});

The getFacets method looks like this:

import { ref } from "@vue/composition-api";

class Facet {
  key: string;
  value: FacetItem[];
}

class FacetItem {
  facetName: string;
  count: number;
  value: string;
  from: string;
  to: string;
}

export function getFacets(facets: any) {
  const criteria = ref([]);

  const facet = facets.find((item: Facet) => item.key === "Criteria/Attribute");

  let currentCriterionName = "";
  let criterion: any = {};
  let count = 0;
  (<Facet>facet).value
    .sort((a, b) => a.value.localeCompare(b.value))
    .forEach((item: FacetItem) => {
      const value = item.value;
      const [c, a] = value.split(":");

      if (c !== currentCriterionName) {
        if (criterion.name) criteria.value.push(criterion);

        criterion = {
          name: c,
          attributes: [],
          active: false,
        };

        currentCriterionName = c;
      }

      criterion.attributes.push({
        name: a,
        facetName: value,
        to: item.to,
        from: item.from,
        count: item.count,
      });
      count++;
    });

  if (count === facet.value.length) criteria.value.push(criterion);

  return { criteria };
}

As you can see, my component expects a facets array that is required (along with a categoryName and optional loading boolean). The initial array looks like this:

[
  {
    "key":"Criteria/Attribute",
    "value":[
        {
          "count":5,
          "value":"Capacity:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":11,
          "value":"Capacity:Large",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Capacity:Medium",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":19,
          "value":"Capacity:Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":8,
          "value":"Coffee at the press of a button?:Yes",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Extraction Quality:Amazing",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Extraction Quality:Exceptional",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":24,
          "value":"Extraction Quality:Good",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":6,
          "value":"Extraction Quality:Very Good",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":16,
          "value":"Milk Frother:Automatic",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":10,
          "value":"Milk Frother:None",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":22,
          "value":"Milk Frother:Steam Wand",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":10,
          "value":"Noise:Buzzing",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":10,
          "value":"Noise:Loud",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":23,
          "value":"Noise:Quiet",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Noise:Silent",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":3,
          "value":"Size:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":6,
          "value":"Size:Large",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":31,
          "value":"Size:Medium",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":8,
          "value":"Size:Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":2,
          "value":"Speed:Instant",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":28,
          "value":"Speed:Quick Heat",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Speed:Slow",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Speed:Standard",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":7,
          "value":"Style:Designer",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":8,
          "value":"Style:Minimalist",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":20,
          "value":"Style:Modern",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Style:Professional",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        }
    ],
    "__typename":"KeyValuePairOfStringAndListOfFacetModel"
  }
]

In this component, when one of the items is clicked, it performs a search which returns a new set of facets. Here is an example of the new array:

[
  {
    "key":"Criteria/Attribute",
    "value":[
        {
          "count":5,
          "value":"Capacity:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Extraction Quality:Good",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Milk Frother:None",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Noise:Silent",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Speed:Slow",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Style:Minimalist",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":3,
          "value":"Size:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":2,
          "value":"Size:Medium",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        }
    ],
    "__typename":"KeyValuePairOfStringAndListOfFacetModel"
  }
]

This is all served from a parent component. The initial array is produced when the page loads, when the filter is clicked above, it then calls a method that updates the array which the Chooser component uses.

<chooser
  :categoryName="category.name"
  :facets="result.search.facets"
  :loading="loading"
  @onFilter="search($event)"
>
</chooser>

The problem is, even though I can do this {{ result.search.facets }} in the parent component and see the array change, the Chooser remains exactly the same. Is there something I must do in order for the Chooser to update when the array changes?

3
  • Are you mutating result.search.facets array or completely replacing it? Commented Aug 2, 2021 at 14:05
  • criteria should be computed so it is rebuild (by executing getFacets function) each time the fasets prop changes. Commented Aug 2, 2021 at 14:16
  • completely replacing it Commented Aug 2, 2021 at 14:22

1 Answer 1

1

Try not only to update an array but also to update a link of filters variable. I think that the problem is that Vue does not always detect changes on elements of array. Here is what is written in docs about it.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.