PDA

View Full Version : [FIXED-29][3.0RC2] Filtered store issues



Condor
16 Jun 2009, 9:19 AM
There are a few issues with filtered stores:
1. You can't remove a record that has been filtered out.
2. Records that are inserted in a filtered store are removed when the filter is cleared (even though they are still joined to the store!).
3. You can't get a record by it's id if it has been filtered out.

For these 3 issues I suggest the following patch:

Ext.override(Ext.data.Store, {
remove : function(record){
var index = this.data.indexOf(record);
if(index > -1){
this.data.removeAt(index);
}
if(this.pruneModifiedRecords){
this.modified.remove(record);
}
if(this.snapshot){
this.snapshot.remove(record);
}
if(index > -1){
this.fireEvent("remove", this, record, index);
}
},
insert : function(index, records){
records = [].concat(records);
for(var i = 0, len = records.length; i < len; i++){
this.data.insert(index, records[i]);
records[i].join(this);
}
if(this.snapshot){
this.snapshot.addAll(records);
}
this.fireEvent("add", this, records, index);
},
getById : function(id){
return (this.snapshot || this.data).key(id);
}
});

Note:
I added the records to the snapshot instead of inserting them because it's impossible to know the correct insert location in the snapshot.

dolittle
18 Jun 2009, 6:25 AM
I like your patch and going to test it.

Maybe a flag in getById will tell the method to search all the record or just the filtered records.
Not sure if this code is correct but you'll get the idea.

getById : function(id, filtered){
if(filtered) {
return this.data.key(id);
} else
return this.snapshot.key(id);
}


Can thouse two be combined?

if(index > -1){
this.data.removeAt(index);
}
if(index > -1){
this.fireEvent("remove", this, record, index);
}

Condor
18 Jun 2009, 6:33 AM
1. You don't have to check for filtered, because clearFilter also deletes the snapshot (and my code is smaller).

2. I modified the code. IMHO the delete event should also be fired if the record wasn't visible (the event could update a recordcount).

3. add() and remove() should probably also update totalLength (wasn't there another bugreport for this?).

dolittle
18 Jun 2009, 6:41 AM
1. You don't have to check for filtered, because clearFilter also deletes the snapshot (and my code is smaller).

I want to be able choose between
1. searching for a record only in the filtered records.
2. searching in the full list of records even when there is a filter.

I think that current code support 1. and your code support 2.

Condor
18 Jun 2009, 6:48 AM
Sorry, I misread your code.

Could you explain why you would only want to search in the filtered set by id?

dolittle
18 Jun 2009, 7:05 AM
Sorry, I misread your code.

Could you explain why you would only want to search in the filtered set by id?

Let's say you have a dataView and a store. You filter the store and the dataView
presents only the filtered records. You get an event from the server telling you that one of the records should be modified and you want to show the user an alert that the record has been modified but show it only if it is presented in the dataView.

Condor
18 Jun 2009, 7:07 AM
Can't you use store.indexOfId for that (returns -1 for filtered records)?

dolittle
18 Jun 2009, 7:12 AM
Can't you use store.indexOfId for that (returns -1 for filtered records)?
yes.

Is your code compatible with find, findBy, getAt, getCount...?

Condor
18 Jun 2009, 7:17 AM
[CODE]Is your code compatible with find, findBy, getAt, getCount...?

find and findBy both return record index numbers and getAt locates the record using the index, so they should only process the filtered/visible records (which they already do).
getCount already refers to the filtered result. To get the total number of records (unfiltered) there is getTotalCount.

dolittle
18 Jun 2009, 10:58 AM
3. add() and remove() should probably also update totalLength (wasn't there another bugreport for this?).

I couldn't find a bugreport for this and you are right just tested and totalLength is wrong.
Should I submit a bug report or will you modify the code in this thread to include in insert

if(index > -1){
this.totalLength--;
}
and similar in insert.

Is it possible to use the snapshot length in getTotalCount instead of manually updating totalLength?

dolittle
18 Jun 2009, 12:00 PM
I think that the ability to get a record that is filtered out need modification in dataView.
I have a filtered store and a dataView. I'm setting a value for a record that is filtered out:

var record = myStore.getById('someId');
record.set('someField', 'someValue');
and getting an error:

ns[i] is undefined
updateIndexes()(-1, -1)
ext-all-debug.js line 21441
updateIndexes get called with -1,-1 because the record is filtered.

// private
onUpdate : function(ds, record){
var index = this.store.indexOf(record);
var sel = this.isSelected(index);
var original = this.all.elements[index];
var node = this.bufferRender([record], index)[0];

this.all.replaceElement(index, node, true);
if(sel){
this.selected.replaceElement(original, node);
this.all.item(index).addClass(this.selectedClass);
}
this.updateIndexes(index, index);
},

mjlecomte
18 Jun 2009, 2:03 PM
What does "filter" mean? Remove is intuitive, akin to destroy.

dolittle
18 Jun 2009, 2:25 PM
@mjlecomte
I'm working on the store code to enhance its functionality.
The goal that the store will filter and sort records automatically when adding or editing a record without refreshing the whole dataView.

I'm adding defaultSort and defaultFilter config options.
The constructor will use these config options to setDefaultSort and setDefaultFilter.
When loading data or adding a record the store will use the above by default if exist.
I'll modified loadRecord and add applyFilter similar to applySort.

Next step is to override afterEdit. I want the record to automatically be filtered according to the defaultFilter and sorted according to the defaultSort without refreshing the dataView. The effect should be like when adding or editing a record in unfiltered store.

Any ideas?

mjlecomte
18 Jun 2009, 3:10 PM
You may be hijacking the OP's thread going down a different line of questioning so I won't entertain your questions for the time being out of respect for the OP. You may want to open up a separate help thread and post a link here if you like. At the moment, my immediate concern is to address any bugs that may or may not exist.

One thing I was asking was to make sure this was a bug in the first place. The question is rather basic: "What does filter mean?". If we use store.remove() it is more obvious that we don't want any traces of that record available in the store, eradicate it. However, I'm not sure it is specifically defined what store.filter() entails. The definition of filter() should be described specifically before we address what filter() does or does not do and what implications it has beyond that.

A test case would be helpful to illustrate what the expectations are. I stopped short, but started something below. It would be useful to add to the code provided what the scenario envisioned is.



<html>
<head>
<title id="page-title">Tools</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script type="text/javascript">

Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';

Ext.onReady(function(){

// example of convert function
function fullName(v, record){
return record.name.last + ', ' + record.name.first;
}

function location(v, record){
return !record.city ? '' : (record.city + ', ' + record.state);
}

var Dude = Ext.data.Record.create([
{name: 'fullname', convert: fullName},
{name: 'firstname', mapping: 'name.first'},
{name: 'lastname', mapping: 'name.last'},
{name: 'city', defaultValue: 'homeless'},
'state',
{name: 'location', convert: location}
]);

// create the data store
var store = new Ext.data.Store({
reader: new Ext.data.JsonReader(
{
idProperty: 'key',
root: 'daRoot',
totalProperty: 'total'
},
Dude
)
});

var key = 0;

var myData = [
{ key: key++,
name: { first: 'Fat', last: 'Albert' }
// notice no city, state provided in data object
},
{ key: key++,
name: { first: 'Cliff', last: 'Claven' },
city: 'Boston', state: 'MA'
},
{ key: key++,
name: { first: 'Fred', last: 'Flintstone' },
city: 'Bedrock', state: 'Stoneridge'
},
{ key: key++,
name: { first: 'Barney', last: 'Rubble' },
city: 'Bedrock', state: 'Stoneridge'
},
{ key: key++,
name: { first: 'Betty', last: 'Rubble' },
city: 'Bedrock', state: 'Stoneridge'
}
];

var json = {
total: key,
daRoot: myData
};

store.loadData(json);

console.info(store);
console.info('store count:',store.getCount(),' <== 5');
console.info('store filter:',store.isFiltered(),' <== undefined/false');
rec = store.getById(4);
console.info('record(id=4):',rec,' - fullname:',rec.data.fullname);

console.info('filtering the store by lastname=Rubble');
store.filter('lastname', 'Rubble');
console.info('store count:',store.getCount(),' <== 2');
console.info('store filter:',store.isFiltered(),' <== true');



});
</script>
</head>
<body>
</body>
</html>

smartree
24 Sep 2009, 1:10 AM
actually, you just need maintain the snapshot & data of the Store when it has been filtered, anything will be normal.

--Maybe reference:
There are 2 solutions is worth to have a look:
One:
http://www.extjs.com/forum/showthread.php?p=189382#post189382 07-01-2008, 03:23 PM
Two:
http://www.extjs.com/forum/showthrea...544#post299544 (http://www.extjs.com/forum/showthread.php?p=299544#post299544) 03-07-2009, 12:27 AM talk from 12-13-2008, 06:44 AM
This is clear...

And another two threads for this filtered store issues:
https://www.extjs.com/forum/showthread.php?t=17305 11-06-2007, 03:51 AM
http://www.extjs.com/forum/showthread.php?t=45150 08-24-2008, 10:13 AM


On the earth, we can feel that a filtered store need a filtering insert.

Jamie Avins
10 Nov 2009, 8:37 AM
Added to svn 5604 for 3.1 release.