i have custom fields for CGridView. Every column is different Custom Field with it's id. Displaying them is just fine. Problem begins when i try to apply filter for these fields.
I have 4 filter with names CustomField[5]
, CustomField[6]
, CustomField[8]
and CustomField[12]
indexed by it's id. After filtering, yii generates wrong query:
As you can see, it's making loop till last element (since largest id is 12, so it is looping till 12). But if i add letter (making index as string) it generates correct query:
Filter dropdown is generated with code:
echo CHtml::dropDownList(
"CustomField[{$column->id}]",
$this->getFilterValue($column),
['' => ''] + CustomFieldValue::getValue($column),
$column->tagOptions
);
It generates this html:
<tr class="filters">
<td>
<select id="CustomField_5" name="CustomField[5]">
<option selected="selected" value=""></option>
<option value="29">Olympic Male Fly -58</option>
<option value="33">Olympic Female Bantam -57</option>
</select>
</td>
<td>
<select id="CustomField_6" name="CustomField[6]">
<option selected="selected" value=""></option>
<option value="4">Quarter-finals</option
</select>
</td>
<td>
<select id="CustomField_8" name="CustomField[8]">
<option selected="selected" value=""></option>
<option value="3">Bronze</option>
<option value="1">Gold</option>
<option value="4">Participation</option>
</select>
</td>
<td>
<select id="CustomField_12" name="CustomField[12]">
<option selected="selected" value=""></option>
<option value="2">Silver</option>
<option value="1">Gold</option>
</select>
</td>
</tr>
Any idea what is wrong how to fix it?
The Problem
This is an issue with the way jquery.ba-bbq.js
's deparam
function handles the url parameters. If the parameters are passed as a url string i.e &a=b&c=d..
, it creates an object out of them. In the process it treats any parameters that are numerically indexed as arrays and pads them with empty elements.
Here's the result of serialize
on your filter html:
CustomField[5]=&CustomField[6]=&CustomField[8]=&CustomField[12]=
And here's the result of $.param.querystring
on the serialized string
CustomField[]=&CustomField[]=&CustomField[]=&CustomField[]=&CustomField[]=&
CustomField[]=&CustomField[]=&CustomField[]=&CustomField[]=&CustomField[]=&
CustomField[]=&CustomField[]=&CustomField[]=
$(function(){
$("#clickme").on("click", function(){
var data = $(".filters select").serialize();
$("#serialized").html(decodeURIComponent(data) + "\n\n" + decodeURIComponent($.param.querystring("", data)));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://raw.githubusercontent.com/yiisoft/yii/master/framework/web/js/source/jquery.ba-bbq.js"></script>
<div class="filters">
<select id="CustomField_5" name="CustomField[5]">
<option selected="selected" value=""></option>
<option value="29">Olympic Male Fly -58</option>
<option value="33">Olympic Female Bantam -57</option>
</select>
<select id="CustomField_6" name="CustomField[6]">
<option selected="selected" value=""></option>
<option value="4">Quarter-finals</option>
</select>
<select id="CustomField_8" name="CustomField[8]">
<option selected="selected" value=""></option>
<option value="3">Bronze</option>
<option value="1">Gold</option>
<option value="4">Participation</option>
</select>
<select id="CustomField_12" name="CustomField[12]">
<option selected="selected" value=""></option>
<option value="2">Silver</option>
<option value="1">Gold</option>
</select><br/>
<button id ="clickme">Serialize</button>
</div>
<pre><div id="serialized"></div></pre>
The Solutions
Prefixing your indexes with a string solves the problem since it results in the parameter CustomField
being treated as an object not an array.
An alternative solution would be to ensure that your custom fields have continuous indexes i.e 0,1,2,3
.
Also, you could just ignore any empty CustomField
parameters in your controller action.