Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

  • Blama
    started a topic Best practice needed: ListGrid with setViewState(...)

    Best practice needed: ListGrid with setViewState(...)

    Hi Isomorphic,

    I have the following simple usecase:
    A ListGrid with persisted ViewState information (Fieldstate, Sortstate, Groupstate separately set from DB, Hilites static, no SelectState).

    Right now my flow is:
    1. setHilites(default hilites)
    2. setFields(...)
    3. ViewStateDS.fetch(myUser, listGridName), in CallBack
      • if ViewState found
        1. setFieldState(fieldState)
        2. setSortState(sortState)
        3. setGroupState(groupState)
      • if ViewState not found
        1. setSort(default SortSpecifiers)
        2. setGroup(default groupBy-fieldname)
      • fetchData()


    This way I see a change in the ListGrid structure after the ViewStates is applied or the Default sorts/grouping are set.

    Is there a better way to "design" the ListGrid before showing it? Also, I'm delaying my fetch(...) for the ListGrid-Data until the fetch for ViewState returned, which I don't like.

    What is the proposed way of showing a ListGrid with ViewState?
    One thing I could think of is to pre-fetch all my ViewStates at application start, but I don't know if this helps (and is necessary), as I could imagine that the ResultSet-layer purges these quite big results pretty fast.

    Could you please suggest, Isomorphic?

    Thank you & Best regards,
    Blama

  • Blama
    replied
    Hi Mirko,

    the code is as follows:

    ViewStates.java:
    Code:
    import a.b.c.d.ViewStateHelper;
    
    public class ViewStates {
    	private String selectedState = null;
    	private String fieldState = null;
    	private String sortState = null;
    	private String hiliteState = null;
    	private String groupState = null;
    
    	public ViewStates(String selectedState, String fieldState, String sortState, String hiliteState, String groupState) {
    		if (!ViewStateHelper.NO_UPDATE.equals(selectedState))
    			this.selectedState = selectedState;
    		if (!ViewStateHelper.NO_UPDATE.equals(fieldState))
    			this.fieldState = fieldState;
    		if (!ViewStateHelper.NO_UPDATE.equals(sortState))
    			this.sortState = sortState;
    		if (!ViewStateHelper.NO_UPDATE.equals(hiliteState))
    			this.hiliteState = hiliteState;
    		if (!ViewStateHelper.NO_UPDATE.equals(groupState))
    			this.groupState = groupState;
    	}
    
    	public String getSelectedState() {
    		return selectedState;
    	}
    
    	public String getFieldState() {
    		return fieldState;
    	}
    
    	public String getSortState() {
    		return sortState;
    	}
    
    	public String getHiliteState() {
    		return hiliteState;
    	}
    
    	public String getGroupState() {
    		return groupState;
    	}
    
    	public void setSelectedState(String selectedState) {
    		this.selectedState = selectedState;
    	}
    
    	public void setFieldState(String fieldState) {
    		this.fieldState = fieldState;
    	}
    
    	public void setSortState(String sortState) {
    		this.sortState = sortState;
    	}
    
    	public void setHiliteState(String hiliteState) {
    		this.hiliteState = hiliteState;
    	}
    
    	public void setGroupState(String groupState) {
    		this.groupState = groupState;
    	}
    }
    stripped version of SettingsCache.java:
    Code:
    public class SettingsCache2 {
    	private static SettingsCache2 instance = new SettingsCache2();
    	private Map<String, ViewStates> viewStatesMap = new HashMap<String, ViewStates>();
    	final private DataSource viewstateDS = DataSource.get(DatasourceEnum.T_VIEWSTATE.getValue());
    
    	private SettingsCache2() {
    		refresh();
    	}
    
    	public static SettingsCache2 getInstance() {
    		return instance;
    	}
    
    	public void refresh() {
    		// ViewStates caching:
    		viewstateDS.fetchData(new AdvancedCriteria("USER_ID", OperatorId.EQUALS, User.getUserId()), new DSCallback() {
    			@Override
    			public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
    				if (dsResponse != null && dsResponse.getStatus() == RPCResponse.STATUS_SUCCESS) {
    					for (Record r : dsResponse.getData()) {
    						ViewStates vs = new ViewStates(r.getAttribute("SELECTEDSTATE"), r.getAttribute("FIELDSTATE"), r.getAttribute("SORTSTATE"), r
    								.getAttribute("HILITESTATE"), r.getAttribute("GROUPSTATE"));
    						viewStatesMap.put(r.getAttribute("OBJECT"), vs);
    					}
    				}
    			}
    		}, new DSRequest(DSOperationType.FETCH) {
    			{
    				setProgressiveLoading(true);
    			}
    		});
    	}
    
    	public ViewStates getViewState(String objectName) {
    		return viewStatesMap.get(objectName);
    	}
    
    	public String getSelectedState(String objectName) {
    		if (!viewStatesMap.containsKey(objectName))
    			return null;
    		else
    			return viewStatesMap.get(objectName).getSelectedState();
    	}
    
    	public String getFieldState(String objectName) {
    		if (!viewStatesMap.containsKey(objectName))
    			return null;
    		else
    			return viewStatesMap.get(objectName).getFieldState();
    	}
    
    	public String getSortState(String objectName) {
    		if (!viewStatesMap.containsKey(objectName))
    			return null;
    		else
    			return viewStatesMap.get(objectName).getSortState();
    	}
    
    	public String getHiliteState(String objectName) {
    		if (!viewStatesMap.containsKey(objectName))
    			return null;
    		else
    			return viewStatesMap.get(objectName).getHiliteState();
    	}
    
    	public String getGroupState(String objectName) {
    		if (!viewStatesMap.containsKey(objectName))
    			return null;
    		else
    			return viewStatesMap.get(objectName).getGroupState();
    	}
    
    	public void setViewStates(final String objectName, final String curSelectedState, final String curFieldState, final String curSortState,
    			final String curHiliteState, final String curGroupState) {
    		Record updatedRecord = new Record();
    		updatedRecord.setAttribute("USER_ID", User.getUserId());
    		updatedRecord.setAttribute("OBJECT", objectName);
    
    		if (!ViewStateHelper.NO_UPDATE.equals(curSelectedState))
    			updatedRecord.setAttribute("SELECTEDSTATE", curSelectedState);
    		if (!ViewStateHelper.NO_UPDATE.equals(curFieldState))
    			updatedRecord.setAttribute("FIELDSTATE", curFieldState);
    		if (!ViewStateHelper.NO_UPDATE.equals(curSortState))
    			updatedRecord.setAttribute("SORTSTATE", curSortState);
    		if (!ViewStateHelper.NO_UPDATE.equals(curHiliteState))
    			updatedRecord.setAttribute("HILITESTATE", curHiliteState);
    		if (!ViewStateHelper.NO_UPDATE.equals(curGroupState))
    			updatedRecord.setAttribute("GROUPSTATE", curGroupState);
    
    		viewstateDS.updateData(updatedRecord, new DSCallback() {
    			@Override
    			public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
    				if (Helper.isSuccess(dsResponse)) {
    					if (viewStatesMap.containsKey(objectName)) {
    						ViewStates vs = viewStatesMap.get(objectName);
    						if (!ViewStateHelper.NO_UPDATE.equals(curSelectedState))
    							vs.setSelectedState(curSelectedState);
    						if (!ViewStateHelper.NO_UPDATE.equals(curFieldState))
    							vs.setFieldState(curFieldState);
    						if (!ViewStateHelper.NO_UPDATE.equals(curSortState))
    							vs.setSortState(curSortState);
    						if (!ViewStateHelper.NO_UPDATE.equals(curHiliteState))
    							vs.setHiliteState(curHiliteState);
    						if (!ViewStateHelper.NO_UPDATE.equals(curGroupState))
    							vs.setGroupState(curGroupState);
    						viewStatesMap.put(objectName, vs);
    					} else {
    						ViewStates vs = new ViewStates(curSelectedState, curFieldState, curSortState, curHiliteState, curGroupState);
    						viewStatesMap.put(objectName, vs);
    					}
    				}
    			}
    		});
    	}
    }
    T_VIEWSTATE.ds.xml:
    Code:
    <DataSource dbName="Oracle" tableName="T_VIEWSTATE" ID="T_VIEWSTATE" serverType="sql"
    	defaultTextMatchStyle="exactCase">
    	<fields>
    		<field primaryKey="true" name="USER_ID" type="integer" required="true" />
    		<field primaryKey="true" name="OBJECT" length="30" type="text" escapeHTML="true" required="true" />
    
    		<field foreignKey="V_USER_CREATED_BY.ID" name="CREATED_BY" title="Erstellt von" type="creator" />
    		<field name="CREATED_AT" title="Erstellt am" type="creatorTimestamp" />
    		<field foreignKey="V_USER_MODIFIED_BY.ID" name="MODIFIED_BY" title="Gešndert von" type="modifier" />
    		<field name="MODIFIED_AT" title="Gešndert am" type="modifierTimestamp" />
    
    		<field name="SELECTEDSTATE" length="1500" type="text" escapeHTML="true" />
    		<field name="FIELDSTATE" length="2000" type="text" escapeHTML="true" />
    		<field name="SORTSTATE" length="1000" type="text" escapeHTML="true" />
    		<field name="HILITESTATE" length="1500" type="text" escapeHTML="true" />
    		<field name="GROUPSTATE" length="1000" type="text" escapeHTML="true" />
    	</fields>
    	<serverObject lookupStyle="new" className="server.worker.T_VIEWSTATE" />
    	<operationBindings>
    		<operationBinding operationType="fetch" outputs="OBJECT, SELECTEDSTATE, FIELDSTATE, SORTSTATE, HILITESTATE, GROUPSTATE" />
    		<operationBinding operationType="update" canSyncCache="false" />
    		<operationBinding operationType="add" requiresRole="updateOnly" />
    		<operationBinding operationType="remove" requiresRole="noRemove" />
    	</operationBindings>
    </DataSource>
    T_VIEWSTATE.java:
    Code:
    public class T_VIEWSTATE {
    
    	public DSResponse fetch(DSRequest dsRequest, HttpServletRequest servletRequest) throws Exception {
    		dsRequest.addToCriteria("USER_ID", DefaultOperators.Equals, User.getUserId(servletRequest));
    		return dsRequest.execute();
    	}
    
    	public DSResponse add(DSRequest dsRequest, HttpServletRequest servletRequest) throws Exception {
    		return dsRequest.execute();
    	}
    
    	public DSResponse update(DSRequest dsRequest, HttpServletRequest servletRequest) throws Exception {
    		@SuppressWarnings({ "unchecked", "unused" })
    		Map<String, Object> critMap = dsRequest.getCriteria();
    		@SuppressWarnings("unchecked")
    		Map<String, Object> valueMap = dsRequest.getValues();
    		valueMap.put("USER_ID", User.getUserId(servletRequest));
    		dsRequest.setValues(valueMap);
    		//TODO: Testcase: Generates exception
    //		dsRequest.addToCriteria("USER_ID", DefaultOperators.Equals, User.getUserId(servletRequest));
    		if (dsRequest.getCriteriaValue("OBJECT") == null)
    			return new DSResponse(dsRequest.getDataSource()).setOperationType(DataSource.OP_UPDATE).setFailure("Please specify the component you want to update the settings for.");
    
    //		dsRequest.setAllowMultiUpdate(true);
    		DSResponse updateResp = dsRequest.execute();
    		if (Helper.oneRow(updateResp))
    			return updateResp;
    		else if (Helper.zeroRows(updateResp)) {
    			DSRequest addReq = new DSRequest(DatasourceEnum.T_VIEWSTATE.getValue(), DataSource.OP_ADD, dsRequest.getRPCManager());
    			addReq.setValues(valueMap);
    			
    			DSResponse addResp = addReq.execute();
    			if (Helper.oneRow(addResp)) {
    				addResp.setOperationType(DataSource.OP_UPDATE);
    				return addResp;
    			}
    		}
    		return new DSResponse().setFailure("There was some error updating the viewstate.");
    	};
    };
    CREATE TABLE:
    Code:
    DROP SEQUENCE t_viewstate_id ;
    CREATE TABLE t_viewstate
      (
        id            INTEGER CONSTRAINT NNC_viewstate_id NOT NULL ,
        tenant_id     INTEGER CONSTRAINT NNC_viewstate_tenant_id NOT NULL ,
        user_id       INTEGER CONSTRAINT NNC_viewstate_user_id NOT NULL ,
        object        VARCHAR2 (30 CHAR) CONSTRAINT NNC_viewstate_object NOT NULL ,
        selectedstate VARCHAR2 (1500 CHAR) ,
        fieldstate    VARCHAR2 (2000 CHAR) ,
        sortstate     VARCHAR2 (1000 CHAR) ,
        hilitestate   VARCHAR2 (1500 CHAR) ,
        groupstate    VARCHAR2 (1000 CHAR) ,
        created_by    INTEGER CONSTRAINT NNC_viewstate_creaby NOT NULL ,
        created_at    DATE DEFAULT SYSDATE CONSTRAINT NNC_viewstate_creaat NOT NULL ,
        modified_by   INTEGER CONSTRAINT NNC_viewstate_modby NOT NULL ,
        modified_at   DATE DEFAULT SYSDATE CONSTRAINT NNC_viewstate_modat NOT NULL
      ) ;
    COMMENT ON TABLE t_viewstate
    IS
      'Persists the viewstate of ListGrids in the application.' ;
      ALTER TABLE t_viewstate ADD CONSTRAINT PK_viewstate PRIMARY KEY ( tenant_id, id ) ;
      ALTER TABLE t_viewstate ADD CONSTRAINT UC_viewstate_user_object UNIQUE ( user_id , object ) ;
      ALTER TABLE t_viewstate ADD CONSTRAINT FK_viewstate_user FOREIGN KEY ( tenant_id, user_id ) REFERENCES t_user ( tenant_id, id ) ;
    CREATE SEQUENCE t_viewstate_ID START WITH 1 NOCACHE ORDER ;
    CREATE OR REPLACE TRIGGER t_viewstate_B_I_R BEFORE
      INSERT ON t_viewstate FOR EACH ROW WHEN (NEW.id IS NULL) BEGIN :NEW.id := t_viewstate_ID.NEXTVAL;
    END;
    /
    I'd like a "Munich SmartGWT User Group Meeting" very much. Please mail me at blama@gmx.net.

    Best regards,
    Blama

    Leave a comment:


  • ex70375
    replied
    Hi Blama,

    first of all. many thanks for sharing your work!!! This saves me a lot of time.

    May I ask you to publish the class ViewStates and SettingsCache . :-)
    How is the design of your viewstate database table? How did you define the fields.

    Cheers Mirko

    P.S.: I am also from Munich. maybe we can even meet or communicate via email.

    Leave a comment:


  • Blama
    replied
    Hi mirko,

    what I do is to cache the ListGrid settings for the current user at startup (where I show no ListGrid, yet).
    Then I use this:

    Code:
    public class Mylist extends ListGridVS {
    	public LeadlistMyLeads() {
    		// TODO: ggf. GroupState -> true, (wait for fix: http://forums.smartclient.com/showthread.php?t=29462)
    		// Last 5 parameters: Selected-, Field-, Sort-, Hilite-, Group-State
    		super("Mylist", false, true, true, false, false);
    		setDataSource( ... );
    		setAutoFetchData(false);
    		setShowFilterEditor(true);
    		setGroupByMaxRecords(200);
    		setGroupStartOpen(GroupStartOpen.ALL);
    		setCanGroupBy(true);
    
    		// many field definitions
    		
    		setHilites(new Hilite[] { ... }); // NOT persisting, see super()
    		setGroupByField( ... ); // NOT persisting, see super()
    		setFields( ... );
    
    		if (!viewStateHelper.applySavedViewStates()) {
    			setSort(new SortSpecifier[] { ... });
    		}
    		fetchData(null, new ListGridIsLoadedCallBack(viewStateHelper));
    	};
    }
    ListGridVS.java:
    Code:
    public abstract class ListGridVS extends ListGrid {
    	final protected DataSource viewstateDS = DataSource.get(DatasourceEnum.T_VIEWSTATE.getValue());
    	final protected ViewStateHelper viewStateHelper;
    
    	public ListGridVS(String listGridObjectName) {
    		super();
    		this.viewStateHelper = new ViewStateHelper(listGridObjectName, this, false, true, true, false, true);
    		setListGridObjectName(listGridObjectName);
    		configure();
    	}
    
    	public ListGridVS(String listGridObjectName, boolean configureSelectedState, boolean configureFieldState, boolean configureSortState,
    			boolean configureHiliteState, boolean configureGroupState) {
    		super();
    		this.viewStateHelper = new ViewStateHelper(listGridObjectName, this, configureSelectedState, configureFieldState, configureSortState,
    				configureHiliteState, configureGroupState);
    		setListGridObjectName(listGridObjectName);
    		configure();
    	}
    
    	private void configure() {
    		addViewStateChangedHandler(new ViewStateChangedHandler() {
    			@Override
    			public void onViewStateChanged(ViewStateChangedEvent event) {
    				viewStateHelper.saveViewState();
    			}
    		});
    	}
    
    	public String getListGridObjectName() {
    		return viewStateHelper.getObjectName();
    	}
    
    	public void setListGridObjectName(String listGridObjectName) {
    		viewStateHelper.setObjectName(listGridObjectName);
    		viewStateHelper.setSaveSettingsFromNowOn(false);
    	}
    
    	public class ListGridIsLoadedCallBack implements DSCallback {
    		ViewStateHelper viewStateHelper;
    
    		public ListGridIsLoadedCallBack(ViewStateHelper viewStateHelper) {
    			super();
    			this.viewStateHelper = viewStateHelper;
    		}
    
    		@Override
    		public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
    			this.viewStateHelper.setSaveSettingsFromNowOn(true);
    		}
    	};
    }
    ViewStateHelper.java:
    Code:
    public class ViewStateHelper {
    	public static final String NO_UPDATE = "<NOUPDATE>";
    	private boolean saveSettingsFromNowOn = false;
    	private String objectName;
    	private ListGrid listgrid;
    	private boolean configureSelectedState;
    	private boolean configureFieldState;
    	private boolean configureSortState;
    	private boolean configureHiliteState;
    	private boolean configureGroupState;
    
    	// Persisted settings
    	private ViewStates viewStates;
    
    	public ViewStateHelper(String objectName, ListGrid listgrid, boolean configureSelectedState, boolean configureFieldState,
    			boolean configureSortState, boolean configureHiliteState, boolean configureGroupState) {
    		this.objectName = objectName;
    		this.viewStates = SettingsCache.getInstance().getViewState(objectName);
    		this.listgrid = listgrid;
    		this.configureSelectedState = configureSelectedState;
    		this.configureFieldState = configureFieldState;
    		this.configureSortState = configureSortState;
    		this.configureHiliteState = configureHiliteState;
    		this.configureGroupState = configureGroupState;
    	}
    
    	public boolean hasSavedViewStates() {
    		return viewStates != null;
    	}
    
    	public String getObjectName() {
    		return objectName;
    	}
    
    	public void setObjectName(String objectName) {
    		this.objectName = objectName;
    		this.viewStates = SettingsCache.getInstance().getViewState(objectName);
    	}
    
    	public void saveViewState() {
    		if (saveSettingsFromNowOn) {
    			String curSelectedState = (configureSelectedState && (viewStates == null || !listgrid.getSelectedState().equals(
    					viewStates.getSelectedState()))) ? listgrid.getSelectedState() : NO_UPDATE;
    			String curFieldState = (configureFieldState && (viewStates == null || !listgrid.getFieldState().equals(viewStates.getFieldState()))) ? listgrid
    					.getFieldState() : NO_UPDATE;
    			String curSortState = (configureSortState && (viewStates == null || !listgrid.getSortState().equals(viewStates.getSortState()))) ? listgrid
    					.getSortState() : NO_UPDATE;
    			String curHiliteState = (configureHiliteState && (viewStates == null || !listgrid.getHiliteState()
    					.equals(viewStates.getHiliteState()))) ? listgrid.getHiliteState() : NO_UPDATE;
    			String curGroupState = (configureGroupState && (viewStates == null || !listgrid.getGroupState().equals(viewStates.getGroupState()))) ? listgrid
    					.getGroupState() : NO_UPDATE;
    
    			if ((configureSelectedState && !curSelectedState.equals(NO_UPDATE)) || (configureFieldState && !curFieldState.equals(NO_UPDATE))
    					|| (configureSortState && !curSortState.equals(NO_UPDATE)) || (configureHiliteState && !curHiliteState.equals(NO_UPDATE))
    					|| (configureGroupState && !curGroupState.equals(NO_UPDATE))) {
    				// Send new values. NO_UPDATE will be handled here.
    				SettingsCache.getInstance().setViewStates(objectName, curSelectedState, curFieldState, curSortState, curHiliteState, curGroupState);
    				// Set current saved settings to current in order to recognize the next change
    				viewStates = new ViewStates(listgrid.getSelectedState(), listgrid.getFieldState(), listgrid.getSortState(),
    						listgrid.getHiliteState(), listgrid.getGroupState());
    			}
    		}
    	}
    
    	public boolean applySavedViewStates() {
    		if (viewStates != null) {
    			if (configureSelectedState && viewStates.getSelectedState() != null)
    				listgrid.setSelectedState(viewStates.getSelectedState());
    			if (configureFieldState && viewStates.getFieldState() != null)
    				listgrid.setFieldState(viewStates.getFieldState());
    			if (configureHiliteState && viewStates.getHiliteState() != null)
    				listgrid.setHiliteState(viewStates.getHiliteState());
    			if (configureGroupState && viewStates.getGroupState() != null)
    				listgrid.setGroupState(viewStates.getGroupState());
    
    			//See http://forums.smartclient.com/showthread.php?p=116180#post116180 for the order of calls
    			if (configureSortState && viewStates.getSortState() != null)
    				listgrid.setSortState(viewStates.getSortState());
    			return true;
    		}
    		return false;
    	}
    
    	public void setSaveSettingsFromNowOn(boolean saveSettingsFromNowOn) {
    		this.saveSettingsFromNowOn = saveSettingsFromNowOn;
    	}
    }
    As my settingsCache has the settings when constructing the grid, I see no visual glitches (no roundtrip delay for the fetch), although they might still be there.

    @Isomorphic:
    I never draw() anything. My normal pseudocode flow is:
    Code:
    VLayout vL = new VLayout(){
    {
    	ListGridSubclass lgs = new ListGridSubclass();
    	// This includes either a fetch at the end or is setAutoFetch(true)
    	addMember(lgs);
    }};
    ...
    Is there a way in this setup where I can make sure that a Grid is only shown when the design is finished with respect to shown fields. The data may still be missing.

    Thank you & best regards,
    Blama

    Leave a comment:


  • Isomorphic
    replied
    For the least duplicated work, don't draw() the ListGrid until you've applied all the *State variables.

    Clearly you also should not fetch before applying all *State variables, since the sort direction changing would cause a re-fetch, as could some other field settings (like optionDataSource).

    Leave a comment:


  • ex70375
    replied
    hi blama,

    did you get any advice or best practice from Isomorphic? I have to add the same functionality in my application next week and I've just asked myself the same questions.

    best regards,
    mirko

    Leave a comment:

Working...
X