rtucek/vue-query-builder

RuleSlot exact rule identification

Closed this issue · 6 comments

Hi, first of all thank you for such a great library!

I am facing an issue where I have multiple rules using the same component.
I noticed this behavior when trying to get data into the (custom) component of a (custom / scoped) RuleSlot. Within this component, I have a drop-down that eventually will fetch data from a DB / API. In the end there will be ~30 rules that have a dropdown selection, and in my opinion it is not worth creating 30 custom (pretty much duplicate) dropdown components. Therefor I am trying to use a single component in multiple rules, with different data fetched in the dropdown.

One of the main issue is the identification of the exact rule based on the data that is being forwarded into the RuleSlot:
src/QueryBuilderRule.vue#L81 and src/QueryBuilderRule.vue#L42
Only with this information currently provided, the exact rule can only be found out by matching the ruleComponent (and ruleData, dependend if initialValue is different):

    ruleName() {
      return this.rules
        .find(r => r.component === this.ruleCtrl.ruleComponent)
        .name;
    },

however, as I have multiple rules that have the same component, this won't work (it only give back the first element in the rules array it finds).

To fix this behavior, the identifier from the rules would be needed inside the RuleSlot.

Basically in the get ruleSlotProps (src/QueryBuilderRule.vue#L42) adding one item to the object being forwarded to the RuleSlot:

  get ruleSlotProps(): RuleSlotProps {
    return {
      ruleComponent: this.component,
      ruleData: this.query.value,
      ruleIdentifier: this.query.identifier
      updateRuleData: (ruleData: any) => this.ruleUpdate(ruleData),
    };
  }

When this ruleIdentifier is available in the RuleSlot the ruleName (and exact rule) can be found:

.find(r => r.identifier=== this.ruleCtrl.ruleIdentifier)

Thank you!

Hi @DJManuel and thank you very much for your feedback.

One thing I can't follow is this statement:

To fix this behavior, the identifier from the rules would be needed inside the RuleSlot.

How, would the component's identifier help you in the RuleSlot context to avoid having several components of the same type?
Assume you'd have already support for it today, can you give me some sample code of how you'd make use of it for solving your problem?

Pertaining the problem you're trying to solve:

I am facing an issue where I have multiple rules using the same component.
I noticed this behavior when trying to get data into the (custom) component of a (custom / scoped) RuleSlot. Within this component, I have a drop-down that eventually will fetch data from a DB / API. In the end there will be ~30 rules that have a dropdown selection, and in my opinion it is not worth creating 30 custom (pretty much duplicate) dropdown components. Therefor I am trying to use a single component in multiple rules, with different data fetched in the dropdown.

You may want to check #47 which seem to be related. I think my suggestion with a concrete code sample should help - it basically extends a dropdown component. Is that what you're looking for?

Thank you for your quick resonse,

One thing I can't follow is this statement:
To fix this behavior, the identifier from the rules would be needed inside the RuleSlot.

The reason for this is to clearly identify the exact rule based on its identifier (that is unique) instead of the component name (that is the same for multiple components with different data). The reason for the exact identification of the rule is due to having an additional element in the rule where data is stored that is needed within the dropdown component.

I have created a codesanbox here.
The example in the sandbox isn't exactly corresponding to the use-case, however the general concept is shown.

In the example, the 3 rules in the query should be text dropdown1, text dropdown2 and text dropdown3, but with the limited matching capability all of them are shown as "text dropdown1". Also, when checking what data there is available in the dropdowns, you can see it is only the data from the dropDown1.

The main difference between this sandbox example and the implementation I am doing is that instead of passing the data directly through the "dbdata" element / props, I would only pass an arguments for a vuex getter call to get the correct data for the specific dropdown.

Thank you!

Have you looked at this code sandbox sample I referred you to in the linked thread above?

Here's the link:
Edit Dynamic dropdown

The only difference is that you have to declare some logic from where the data shall be passed onto your component. In this sample, I demonstrate it with individual AJAX requests via axios upon the component's mount event. Note that the Dropdown.vue gets dynamically extended with a dedicated "data factory".

That said, all you'd want to do is to pass a slightly different for logic for...

  • ...querying your database
  • ...inject data that you've already at hand via Vuex or prop

If it doesn't solve your problem, please let me know why 😉

Yes, I have had a look at it but there are a few issues that I found with this implementation.
The code duplication with more than 30 different dropdown components is quite large, in the implementation this adds 10 lines and this results in total to 300 additional lines that are completely duplicate.

Also, I have tried to implement it and it didn't work as expected.
The component doesn't load properly without any log output on what fails.

I have created a PR #83 for this change to be implemented.

Thank you!

Hey there, thanks for the great work. I have the exact same issue, and although your "extend" trick can do the job, I think it would make more sense to have the option to directly pass props to the components. Maybe something like that:

 {
          identifier: property.nf_id,
          name: property.name,
          component: ColumnFilter,
          initialValue: null,
          componentProps: {
               //....
          }
        }

Having the identifier also works but then again it required additional work. What do you guys think? I'm happy to collaborate on this

I've just merged #83 and released it with v1.2.0.

Kudos to @DJManuel for his contribution 🎉