mistic100 / jQuery-QueryBuilder

jQuery plugin offering an interface to create complex queries
https://querybuilder.js.org
MIT License
1.68k stars 552 forks source link

Dynamic input, valueGetter and valueGetter for custom operator #927

Closed dpnishant closed 3 years ago

dpnishant commented 3 years ago

Hi,

I have a requirement where I want to create filter with default operators for a "string" type along with 2 additional custom operators. These custom operators should change add custom input fields using custom HTML markup.

As of now I'm able to assign a function to the filter's input attribute and return the custom HTML mark and get/set values from the custom input fields via assigning handlers to the filter's valueGetter and valueSetter attributes.

I'm also able to generate custom input field HTML template using something like this:


input: function (rule, input_name) {
  if (rule.operator && ['custom_operator1', 'custom_operator2'].indexOf(rule.operator.type) !== -1) { ... }
    ...
    return customFilterValueHTML;
  }
},
valueGetter: function (rule) {
  if (rule.operator && ['custom_operator1', 'custom_operator2'].indexOf(rule.operator.type) !== -1) { ... }
    ...
    return inputElement.val();
  }
}

The problem is that when I select a different operator (from the default list e.g. equal, between etc.) the no input field is rendered at all. I was expecting the default input fields to get rendered and the default valueGetter, valueSetter should get invoked as it happens normally. I'm guessing it's likely because I have not added and else block to handle the operator change event. And thats because I have no idea what to return in the else block. As a hack I can keep adding input fields even for the default operators and handle their getter and setters but I feel there's got to be a better way to do this.

Any guidance on this would be super helpful.

mistic100 commented 3 years ago

The input function is only called once not on every operator change.

What you want is not possible out of the box see #284

One hacky solution is to make input returns all the different inputs elements you need (hidden with CSS). Listen to afterUpdateRuleOperator to change their visibility and implement valueGetter and valueSetter accordingly.

dpnishant commented 3 years ago

@mistic100 That's exactly what I did just today and I was able to implement what I wanted using the input function. I used a if condition to check for my custom operator and return a custom markup and for all the default operators I return the a light weight version of the default markup (taken from https://github.com/mistic100/jQuery-QueryBuilder/blob/7e8527d877634e67120a028b0296473057e94ca0/src/template.js#L307-L312). And yes, I'm using the valueGetter and valueSetter for read/write. Thanks for the response.

curunoir commented 2 years ago

Hi @dpnishant , could you please elaborate on how you did manage to have it working ?

I think I have a similar use case but I have an issue of rule value not getting retrieved in getRules if I have replaced the input markup like this

$('#builder-rules').on('afterUpdateRuleOperator.queryBuilder', function (e, rule) {
      if (rule.filter.id && rule.filter.id === 'some_id' && rule.operator.type === 'equal') {
                let inputContainerRule = rule.$el.find('.rule-value-container');
                let existingNameInput = rule.$el.find('.rule-value-container input').attr('name');
                inputContainerRule.html('<input class="form-control" type="text" name="' + existingNameInput + '">');
                rule.filter.type = 'string';
                rule.filter.input = 'text';
                rule.value = 'some value';
            }
        }
    );