Announcement

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

    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

    #2
    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

    Comment


      #3
      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).

      Comment


        #4
        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

        Comment


          #5
          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.

          Comment


            #6
            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

            Comment

            Working...
            X