Custom Plugin requires an edit of the Rule's structure in order to work
VanHiro opened this issue · comments
The Problem
I created a custom plugin but to make it work I need to edit the Rule's structure from the file querybuilder-standalone itself.
The plugin adds a button like the one from the plugin not-group inside each rule. The function of this plugin is to transform an input like this 'field = "value"' into this 'UPPER( field ) = "VALUE"'. The problem with this solution is that, in order to reuse this query (get/set SQL), I need to modify the structure of the Rule itself in the query-builder.
You can find this question also in stackoverflow:
https://stackoverflow.com/questions/69646450/jquery-querybuilder-editing-the-rules-structure-in-the-file-query-builder-stan
The Code
The edits I would need to make are the following:
You can find the original code at line 2242 of the file query-builder.standalone.js
if (model.filter) {
model.filter.to_upper = item.to_upper; /* <---This is the line I added myself */
model.operator = self.getOperatorByType(item.operator, !options.allow_invalid);
if (!model.operator) {
model.operator = self.getOperators(model.filter)[0];
}
}
And this:
Original code between line 6215 and 6232
var id = self.getSQLFieldID(field, value);
//The following line is the code I need
var to_upper = data.to_upper;
/**
* Modifies the rule generated from the SQL expression
* @event changer:sqlToRule
* @memberof module:plugins.SqlSupport
* @param {object} rule
* @param {object} AST
* @returns {object}
*/
var rule = self.change('sqlToRule', {
id: id,
field: field,
operator: opVal.op,
value: opVal.val,
//The following line us the code I need
to_upper: to_upper
}, data);
'to_upper' is a property I set to false by default and to true when its related button it's clicked.
The Question
How could I do this without adding these code to query-builder itself?
The plugin upper-rule
/**
* @class ToUpperRule
* @memberof
* @description Adds a "toUpper" checkbox in front of group conditions.
* @param {object} [options]
* @param {string} [options.icon_checked='glyphicon glyphicon-checked']
* @param {string} [options.icon_unchecked='glyphicon glyphicon-unchecked']
*/
QueryBuilder.define('upper-rule', function(options) {
var self = this;
this.on('afterInit', function() {
self.$el.on('click.queryBuilder', '[data-upper=rule]', function() {
var $rule = $(this).closest(QueryBuilder.selectors.rule_container);
var rule = self.getModel($rule);
rule.to_upper = !rule.to_upper;
});
self.model.on('update', function(e, node, field) {
if (node instanceof Rule && field === 'to_upper') {
self.updateRuleToUpper(node);
}
});
});
// Init "toUpper" property
this.on('afterAddRule', function(e, rule) {
rule.__.to_upper = false;
});
if (!options.disable_template) {
this.on('getRuleTemplate.filter', function(h) {
var $h = $($.parseHTML(h.value));
$h.find(QueryBuilder.selectors.rule_header).prepend(
'<button type="button" class="upper btn btn-xs btn-default" data-upper="rule">' +
'<i class="' + options.icon_unchecked + '"></i> ' + self.translate('UPPER') +
'</button>'
);
h.value = $h.prop('outerHTML');
});
}
// Export "toUpper" to JSON
this.on('ruleToJson.filter', function(e, rule) {
e.value.to_upper = rule.to_upper;
});
// Read "toUpper" and hide or show based on the rule's type
this.on('jsonToRule.filter', function(e,rule) {
if (rule.to_upper)
e.value.to_upper = rule.to_upper;
if (e.value.filter.type != "string" || e.value.filter.plugin != null) {
e.value.$el.find('.rule-header').find('.upper').hide();
rule.to_upper = false;
} else if (e.value.filter.type == 'string') {
e.value.$el.find('.rule-header').find('.upper').show();
}
});
// Export "toUpper" to SQL
this.on('ruleToSQL.filter', function(e, rule) {
if(rule != undefined && rule.to_upper && (rule.type === "string" && rule.value[0] != undefined)) {
if (rule.value[0] instanceof Array) {
rule.value[0][0] = rule.value[0][0].toUpperCase();
var b = rule.value[0][0];
} else {
rule.value[0] = rule.value[0].toUpperCase();
var b = rule.value[0];
}
var operatorAndVal = e.value.replace(rule.field, "").toUpperCase().replace(rule.value,b);
return e.value = " UPPER(" + rule.field + ") " + operatorAndVal;
}
});
// Parse "UPPER" function from sqlparser
this.on('parseSQLNode.filter', function(e) {
if (e.value.right != null && e.value.left.name === 'UPPER') {
e.value.to_upper = true;
e.value.left = e.value.left.arguments.value[0];
delete e.value.left.name;
}
});
// Request to create sub-rule if the "UPPER" flag is set
this.on('sqlGroupsDistinct.filter', function(e, data, i) {
if (data.to_upper && i > 0) {
debugger;
e.value = true;
}
});
}, {
icon_unchecked: 'glyphicon glyphicon-unchecked',
icon_checked: 'glyphicon glyphicon-check',
disable_template: false
});
/**
* @name toUpper
* @instance
* **/
Utils.defineModelProperties(Rule, ['to_upper']);
QueryBuilder.selectors.rule_upper = QueryBuilder.selectors.rule_header + ' [data-upper=rule]';
QueryBuilder.extend({
updateRuleToUpper: function(rule) {
var options = this.plugins['upper-rule'];
rule.$el.find(QueryBuilder.selectors.rule_upper)
.toggleClass('active', rule.to_upper)
.find('i').attr('class', rule.to_upper ? options.icon_checked : options.icon_unchecked);
/**
* After the rule's upper flag has been modified
* @event afterUpdateGroupToUpper
* @memberof module:plugins.UpperGroup
* @param {Rule} rule
*/
this.trigger('afterUpdateRuleUpper', rule);
this.trigger('rulesChanged');
}
});
First of all I don't understand what you are trying to achieve with model.filter.to_upper = item.to_upper;
The filter
is the object from the configuration, it is shared accross all rules using this filter, surely you don't want to alter it with the data from one rule.
ruleToJson
is what is used to parse additional data from JSON, and you already implemented it.
Now for the modification in the SQL plugin, it is very simple, you are exactly modifying the params of the sqlToRule
event, so just use this event.
this.on('sqlToRule.filter', function(e, data) {
e.value.to_upper = data.to_upper;
});
With only this addition in your plugin it seems to work as intended
Indeed, it works like a charm. I did not consider the potential of the event right there. Thank you for the helpful prompt.