PDA

View Full Version : Filters are broken in Sencha Touch 2?



KJedi
24 Dec 2011, 12:39 AM
Hello,

I have a page where filters are set, then I have a store which is loaded with a new data from the server. Here's how I do it:
1) On the filters page I have controls for setting values. Controller listens tothose events and creates the custom this.filter object. Basically that is a list of filters:

{
isOffer: true
categoryId: 15
}
2) When the page with results is shown, I do the following:

onShowSearchResult: function(){
if (this.filterChanged) { //this is to avoid sending requests if nothing was actually changed
this.getStore('Deals').setParams(this.filter);
this.getStore('Deals').load();
this.filterChanged = false;
}
}
3) In the store with deals I created the method:

setParams: function (params) {
this.filters.clear();
for (var key in params) {
this.filters.add(new Ext.util.Filter({
property: key,
value: params[key]
}));
}
}
It actually clears all filters and add only those I need.
4) This results in a correct XHR request:
GET /deal
_dc:1324713983633
page:1
start:0
limit:25
filter:[{"property":"isOffer","value":false}]
5) I get the data back and in the loadRecords method (Sencha internals) everything is fine - 25 records are loaded, but then since filterOnLoad is true by default it tries to filter the data and here's where we get problems.
The filter I have is {"property":"isOffer","value":false}. I have a lot of models that come from server that have isOffer=false.
By the way, here's is the model definition:

Ext.define('CJ.model.Deal', {
"extend": "Ext.data.Model",
"proxy": {
"type": "rest",
"reader": {
"type": "json",
"root": "items"
},
"url": "/deal"
},
"idProperty": "dealId",
"fields": [
{
"name": "dealId",
"type": "int"
},
.....
{
"name": "isOffer",
"type": "boolean"
},
....
],
6) After filtering I see no records in the store (yeah, they are in the snapshot, but that's not what I'm talking about).
7) Problem occurs because Sencha creates the filterFn and value matcher that are used in filterBy function. This is correct, but instead of checking model.data properties, they are checking just model properties:

createFilterFn: function() {
var me = this,
matcher = me.createValueMatcher(),
property = me.property;

return function(item) {
return matcher.test(me.getRoot.call(me, item)[property]);///see below values from here
};
},

me.getRoot.call(me, item) evaluates to

Ext.apply.create.Class
data: Object
active: false
dateCreated: Date
dealId: 4
description: "6207975156 87870"
distance: 0
isOffer: false
isPrivate: true
lat: 46.973
lng: 31.986361
name: "5662478639"
price: 48
state: true
viewCount: 0
watchCount: 0
__proto__: Object
dirty: false
editing: false
id: "CJ.model.Deal-4"
index: 3
internalId: "4"
modified: Object
phantom: false
raw: Object
store: Ext.apply.create.Class
__proto__: TemplateClass
property ="isOffer"
matcher is
/^false/i
The whole expression evaluates to false because there is no property isOffer in the model, it is in model.data. But normally it should evaluate to true - isOffer is false in this given model!!!

Is it a severe sencha bug with completely broken filtering for models or I'm just doing something wrong?

mitchellsimoens
24 Dec 2011, 7:52 AM
Filtering works for me:


Ext.regModel('Contact', {
fields: ['isOffer', 'firstName', 'lastName']
});

var store = Ext.create('Ext.data.Store', {
model: 'Contact',

sorters: 'firstName',
getGroupString : function(record) {
return record.get('firstName')[0];
},

proxy : {
type : 'ajax',
url : 'data.json',
reader : {
type : 'json'
}
}
});

store.filter('isOffer', false);

store.load();

Ext.create('Ext.Panel', {
fullscreen: true,
layout: 'fit',
items: {
xtype: 'list',
store: store,
disclosure: true,
itemTpl: '<div class="contact2"><strong>{firstName}</strong> {lastName}</div>'
}
});

That shows only those records that have isOffer as false.

KJedi
24 Dec 2011, 8:45 AM
I found the problem.
When I'm creating filter myself, I am not setting the root property. Everything is fixed by adding one line to the code:

this.filters.clear();
for (var key in params) {
this.filters.add(new Ext.util.Filter({
property: key,
value: params[key],
root: 'data'
}));
}
Yes, this is my problem, but given that filters are most commonly used in the stores and stores may only contain models, isn't it a good idea to set this option to 'data' by default to make the framework behave more predictable?

I cannot thing of a usecase when someone filters anything except models, do you? If not, I'd like this to be recorded as a feature request :)

mitchellsimoens
24 Dec 2011, 9:23 AM
Yes, this is my problem, but given that filters are most commonly used in the stores and stores may only contain models, isn't it a good idea to set this option to 'data' by default to make the framework behave more predictable?

I cannot thing of a usecase when someone filters anything except models, do you? If not, I'd like this to be recorded as a feature request :)

You can filter a custom Ext.util.MixedCollection but 99.9% of the cases out there will be filtering on a Store. Therefor I tend to agree with this so I am opening a ticket and letting the core devs ultimately decide on this change.

I use MixedCollections in my code more often than not... they are actually quite useful. Like the items property on a component, it's a MixedCollection and I have use-cases that I've filtered and sorted them based on app logic and that made it quite easy.