PDA

View Full Version : [Re-Opened]I Need To Load A Combo With A Parameter ??



chalu
18 Aug 2010, 10:04 PM
This has been a show stopper for me, I have a Class that acts like a repository of stores in my app, its called DataCenter, I did this so I can build my stores (for combos) once and then use them all over the app from there.


public class DataCenter extends BaseObservable {
public static final String SEMESTERTYPE_LIST_STORE = "semestertype_list_store";
public static final String PROGRAMME_LEVELS_LIST_STORE = "programme_levels_list_store";

....


private void semesterTypeListStore() {
RpcProxy<ListLoadResult<SemesterType>> rpcProxy = new RpcProxy<ListLoadResult<SemesterType>>() {
@Override
public void load(Object loadConfig, AsyncCallback<ListLoadResult<SemesterType>> callback) {
rpcService.listSemesterTypes(callback);
}
};

ListLoader<ListLoadResult<ModelData>> loader;
loader = new BaseListLoader<ListLoadResult<ModelData>>(rpcProxy, new BeanModelReader());
ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
Registry.register(SEMESTERTYPE_LIST_STORE, store);
}

private void programmeLevelsListStore() {
RpcProxy<ListLoadResult<ProgrammeLevel>> rpcProxy = new RpcProxy<ListLoadResult<ProgrammeLevel>>(){
@Override
public void load(Object loadConfig, AsyncCallback<ListLoadResult<ProgrammeLevel>> callback) {
rpcService.listProgrammeLevels((ListLoadConfig) loadConfig, callback);
}
};

ListLoader<ListLoadResult<ModelData>> loader;
loader = new BaseListLoader<ListLoadResult<ModelData>>(rpcProxy, new BeanModelReader());
ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
Registry.register(PROGRAMME_LEVELS_LIST_STORE, store);
}
}


With this, my combos are loaded thus :




ComboBox<BeanModel> semesterCb = new ComboBox<BeanModel>();
semesterCb.setValueField("id");
semesterCb.setDisplayField("name");
semesterCb.setForceSelection(true);
semesterCb.setFieldLabel("Semester");
semesterCb.setTriggerAction(ComboBox.TriggerAction.ALL);
semesterCb.setStore((ListStore<BeanModel>) Registry.get(DataCenter.SEMESTERTYPE_LIST_STORE));



So I can just use setStore((ListStore<BeanModel>) Registry.get(DataCenter.SEMESTERTYPE_LIST_STORE));
wherever I need to list Semester in a combo, and it works perfect.
The problem however arises when I need to pass a parameter to the server with which the combo should be loaded, here is what I tried :


// I am trying to list the levels (years of study) in a University program
ComboBox<BeanModel> levelCb = new ComboBox<BeanModel>();
levelCb.setValueField("id");
levelCb.setDisplayField("name");
levelCb.setForceSelection(true);
levelCb.setFieldLabel("Level");
levelCb.setTriggerAction(ComboBox.TriggerAction.ALL);

ListStore<BeanModel> leveListStore = Registry.get(DataCenter.PROGRAMME_LEVELS_LIST_STORE);
levelCb.setStore(leveListStore);
BaseListLoadConfig cfg = new BaseListLoadConfig();
cfg.set("programme", programme); // I need to tell the server to list levels for this "progrmme"
leveListStore.getLoader().load(cfg);



When the form window opens, the leveListStore is loaded and with logging I can see on the server that the "programme" is sent along with the request, however when the "trigger" button of the combo is clicked, the "programme" is not sent to the server (obviously), so I end up with a NullPointer exception in my processing. The question is how do I send parameters when loading the combos WITHOUT breaking the structure of DataCenter, maybe a way to override the triggerAction (without a subclass) for such combo.

I looked at the code in onTriggerClick method of ComboBox in GXT and noticed that it uses the allQuery field which is just a String, so I have decided to also try to send maybe the id of the "programme" as a string instead of the "programme" object itself, but how is it passed to the server method, as a parameter ??

Please I need help with this. Cheers.

sven
19 Aug 2010, 1:06 AM
I would add a BeforeLoad listener to your loader and modify the LoadConfig and add theparameter there.

chalu
19 Aug 2010, 1:26 AM
Still experimenting for a solution, I am now trying to use the allQuery approach with the hope that the "value" of the allQuery will be sent to the server as noted in the GXT docs, here is what I am doing:


ComboBox<BeanModel> levelCb = new ComboBox<BeanModel>();
levelCb.setValueField("id");
levelCb.setDisplayField("name");
levelCb.setForceSelection(true);
levelCb.setFieldLabel("Level");
levelCb.setTriggerAction(ComboBox.TriggerAction.ALL);
levelCb.setAllQuery(String.valueOf( programme.getId() )); // I expect the id value will get sent as we load the combo
levelCb.setStore((ListStore<BeanModel>) Registry.get(DataCenter.PROGRAMME_LEVELS_LIST_STORE));


I modified the rpc proxy for the combo store loader to account for that fact that we now expect to pass along the allQuery string :


RpcProxy<ListLoadResult<ProgrammeLevel>> rpcProxy = new RpcProxy<ListLoadResult<ProgrammeLevel>>() {
@Override
public void load(Object id, AsyncCallback<ListLoadResult<ProgrammeLevel>> callback) {
rpcService.listProgrammeLevels(String.valueOf(id), callback);
}
};


But I don't get it at the server :


public ListLoadResult<ProgrammeLevel> listProgrammeLevels(String progId) {
logger.info("Programme : " + progId);
return new BaseListLoadResult<ProgrammeLevel>(new ArrayList<ProgrammeLevel>());
}


The logger output however is strange:


INFO: Programme : com.extjs.gxt.ui.client.data.BasePagingLoadConfig@e4

sven
19 Aug 2010, 1:30 AM
The output is not strange. You are calling String.valueOf on a BasePagingLoadConfig instance, the loadconfig.

So you get a string representation of this BasePagingLoadConfig

chalu
20 Aug 2010, 3:19 AM
Thanks seven, but I am confused about this, is there a way to get what was set as the allQuery value at the server or to add / attach the parameter to the LoadConfig object. I am sure it is possible, just can't figure it out yet ??

The LoadConfig approach is supposed to be the ideal, with something like this, right :


// Our combo stores are built in one place, stored in Registry, and then assigned as needed
ListStore<BeanModel> store = Registry.get(DataCenter.PROGRAMME_LEVELS_LIST_STORE);
combo.setStore(leveListStore);

BaseListLoadConfig cfg = new BaseListLoadConfig();
cfg.set("programme", programme); // I need to tell the server to list levels for this "progrmme", I could use it's id too
store.getLoader().load(cfg); // I don't want to call this, it should occur when the combo drop-down is clicked

sven
20 Aug 2010, 3:43 AM
Whats wrong with this:


store.getLoader().addListener(Loader.BeforeLoad, new Listener<LoadEvent>(){
public void handleEvent(LoadEvent le){
le.<ModelData> getConfig().set("programme", programme);
}
});

chalu
25 Aug 2010, 7:19 AM
Thanks seven, this worked very well, although I sent the programme id instead of the whole project. Secondly, I must say that I have never seen this syntax :

le.<ModelData>
Thanks very much.

chalu
31 Aug 2010, 5:31 AM
Ok, I had to re-open this for a slightly different use case. The solution proffered above works just once because we are listening for Loader.BeforeLoad which is called once before the combo is loaded and no longer called after-wards. However there are use cases where U want to pass the said parameter often, like in the case of linked combos (load the combo with the value of a selection from another combo), in the case we can't use the Loader.BeforeLoad event, it has to be Events.Change or SelectionChange. Events.Change will be better because it "assumes" the user has made a selection but it waits for the combo to blur / loose focus before it triggers, sometimes U make a selection and wait in vain for Events.Change which never triggers until U click out of the combo or into another field.

However Events.Change does not allow me do the magic we did inside Loader.BeforeLoad, i.e


evt.<ModelData> getConfig().set("programme", programme);

and this is because evt.<ModelData> getConfig() seems to always evaluate to null within the handler for Events.Change (and even SelectionChange). Here is what I am doing :


// we want the loanTypeCb combo to load using the value of the clientCb
// i.e load all loan types for selected client
clientCb.addListener(Events.Change, new Listener<BaseEvent>(){
public void handleEvent(BaseEvent evt) {
// we get a null here, there's no load config on the store
// ...getStore().getLoader() is no better ???
loanTypeCb.getStore().getLoadConfig().set("client", "clientCbValue");
}
});

sven
31 Aug 2010, 5:32 AM
Can you please post a fully working, minimal testcase that implements EntryPoint about what you are actually doing?

chalu
31 Aug 2010, 5:57 AM
Alright I'll do that, thanks for your quick response

chalu
8 Sep 2010, 2:51 AM
I have attempted to recreate the problem in this exported Eclipse project source (still having problems with eclipse ..)

chalu
11 Sep 2010, 10:48 AM
Here is the testcase code for my use case, the test passes - meaning that combo.getStore().getLoadConfig(); is null when it should not.
[/CODE]


import java.util.ArrayList;
import java.util.List;

import com.extjs.gxt.ui.client.data.BaseModel;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.google.gwt.junit.client.GWTTestCase;

public class GWTAppTest extends GWTTestCase {

@Override
public String getModuleName() {
return "sample.GWTApp";
}

public void testNothing() {
int num = 10;
assertEquals(2, num / 5);
}

public void testCombobox() {
List<BaseModel> models = new ArrayList<BaseModel>();
BaseModel m = new BaseModel();
m.set("name", "Charles Odili");
models.add( m );
m = new BaseModel();
m.set("name", "Ehis Ibhade");
models.add(m);

ListStore<BaseModel> store = new ListStore<BaseModel>();
store.add(models);

final ComboBox<BaseModel> combo = new ComboBox<BaseModel>();
combo.setStore(store);

assertNotNull(combo.getStore().getLoader());
assertNull(combo.getStore().getLoadConfig());
}

}

chalu
14 Sep 2010, 12:31 AM
Please has anyone looked at the above sample test case yet, or am I missing something

sven
22 Sep 2010, 5:13 AM
That testcase cannot pass because your store has no loader set and loader should be null ( which it is for me).
Also the loadconfig is only set after a successfull load.

sven
22 Sep 2010, 5:16 AM
In your FailingLinkedCombos.zip you are changing the loadconfig in your ListStore, you should not do that. You need to modify the loadconfig of your loader.