Announcement

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

    this.addAt is not a function

    We have a list grid which is not databound.
    We are passing the client only datasource and fields using setDataSource and setFields.
    We are using setData to load the records.
    Now consider a case where while creating the grid object, we want to add an empty record to it.
    For that we are using addData(<empty record>, new DSCallback()< anonymous implementation>) method.
    Doing this throws javascript exception "this.addAt is not a function"

    We were not getting this problem before we upgraded to SmartGWT 2.5.
    This issue is replicable on FF and IE where empty records needs to be added while creating the grid.

    Can you please provide solution for this ?

    #2
    It may have been introduced by an upgrade, but it could still be incorrect usage. If you think this is a framework bug, please provide a minimal, standalone test case.

    Comment


      #3
      Entry Point Class
      Code:
      public void onModuleLoad() {
      		
      		EditableListGrid1 grid = new EditableListGrid1();
      		grid.setWidth100();
      		grid.setHeight100();
      		grid.setDataSource(getDataSource());
      		grid.setFields(getFields());
      		grid.makeEditable(true);
      		
      		VLayout layout = new VLayout(10);
      		layout.setMargin(20);
      		layout.setWidth100();
      		layout.setHeight100();
      		layout.addMember(grid);
      		
      		layout.draw();
      	}
      
      private ListGridField[] getFields() {
      		ListGridField field1 = new ListGridField("field1", "A", 100);
      		field1.setCanFilter(true);
      		ListGridField field2 = new ListGridField("field2", "B", 100);
      		field2.setCanFilter(true);
      		ListGridField field3 = new ListGridField("field3", "C", 100);
      		field3.setCanFilter(true);
      		ListGridField field4 = new ListGridField("field4", "D", 100);
      		field4.setCanFilter(true);
      		ListGridField field5 = new ListGridField("field5", "E", 100);
      		field5.setCanFilter(true);
      		ListGridField field6 = new ListGridField("field6", "F", 100);
      		field6.setCanFilter(true);
      		ListGridField field7 = new ListGridField("field7", "G", 100);
      		field7.setCanFilter(true);
      		ListGridField field8 = new ListGridField("field8", "H", 100);
      		field8.setCanFilter(true);
      		ListGridField[] fields = new ListGridField[]{field1, field2, field3, field4, field5, field6, field7, field8};
      		return fields;
      	}
      	
      	private DataSource getDataSource() {
      		DataSourceTextField field1 = new DataSourceTextField("field1", "A", 100);
      		field1.setCanFilter(true);
      		DataSourceTextField field2 = new DataSourceTextField("field2", "B", 100);
      		field2.setCanFilter(true);
      		DataSourceTextField field3 = new DataSourceTextField("field3", "C", 100);
      		field3.setCanFilter(true);
      		DataSourceTextField field4 = new DataSourceTextField("field4", "D", 100);
      		field4.setCanFilter(true);
      		DataSourceTextField field5 = new DataSourceTextField("field5", "E", 100);
      		field5.setCanFilter(true);
      		DataSourceTextField field6 = new DataSourceTextField("field6", "F", 100);
      		field6.setCanFilter(true);
      		DataSourceTextField field7 = new DataSourceTextField("field7", "G", 100);
      		field7.setCanFilter(true);
      		DataSourceTextField field8 = new DataSourceTextField("field8", "H", 100);
      		field8.setCanFilter(true);
      		
      		DataSource ds = new DataSource();
      		ds.setFields(field1, field2, field3, field4, field5, field6, field7, field8);
      		ds.setClientOnly(true);
      		return ds;
      	}
      Extension to ListGrid which is used in entry point
      Code:
      import java.util.Date;
      
      import com.google.gwt.user.client.Random;
      import com.smartgwt.client.data.DSCallback;
      import com.smartgwt.client.data.DSRequest;
      import com.smartgwt.client.data.DSResponse;
      import com.smartgwt.client.data.Record;
      import com.smartgwt.client.types.Autofit;
      import com.smartgwt.client.types.EditCompletionEvent;
      import com.smartgwt.client.types.ListGridEditEvent;
      import com.smartgwt.client.types.ListGridFieldType;
      import com.smartgwt.client.types.Overflow;
      import com.smartgwt.client.types.RowEndEditAction;
      import com.smartgwt.client.widgets.events.DrawEvent;
      import com.smartgwt.client.widgets.events.DrawHandler;
      import com.smartgwt.client.widgets.events.KeyPressEvent;
      import com.smartgwt.client.widgets.events.KeyPressHandler;
      import com.smartgwt.client.widgets.grid.ListGrid;
      import com.smartgwt.client.widgets.grid.ListGridField;
      import com.smartgwt.client.widgets.grid.ListGridRecord;
      import com.smartgwt.client.widgets.grid.events.CellClickEvent;
      import com.smartgwt.client.widgets.grid.events.CellClickHandler;
      import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
      import com.smartgwt.client.widgets.grid.events.DataArrivedHandler;
      import com.smartgwt.client.widgets.grid.events.EditorExitEvent;
      import com.smartgwt.client.widgets.grid.events.EditorExitHandler;
      import com.smartgwt.client.widgets.grid.events.RowEditorExitEvent;
      import com.smartgwt.client.widgets.grid.events.RowEditorExitHandler;
      
      public class EditableListGrid1 extends ListGrid {
      
      	private static final String PROP_NEED_TO_SELECT_FIRST_ROW = "needToSelectFirstRow";
      	private static final String IS_EMPTY_RECORD = "isEmptyRecord";
      	private static final String EDIT_DATA_STYLE = "editData";
      	private boolean canAddNewRow = true;
      	private String styleName;
      	private InternalHandler handler = new InternalHandler();
      	private boolean canPerformDelete = false;
      	private int firstEditColumnIndex = 0;
      	
      	public EditableListGrid1(int maxRow) {
      		setOverflow(Overflow.VISIBLE);
      		setAutoFitData(Autofit.VERTICAL);
      		setAutoFitMaxRecords(maxRow);
      	}
      	
      	public EditableListGrid1() {
      		this(true);
      	}
      
      	public EditableListGrid1(boolean noDefault) {
      		setLeaveScrollbarGap(false);
      		setCanEdit(false);
      		setCanDragSelectText(true);
      		if(noDefault) {
      	        setSaveLocally(true);
      	        setAutoFetchData(true);  
      		}
      		
      		addDrawHandler(new DrawHandler() {
      		
      			@Override
      			public void onDraw(DrawEvent event) {
      				Boolean canEdit = EditableListGrid1.this.getCanEdit();
      				Boolean canAddNewRow2 = EditableListGrid1.this.getCanAddNewRow();
      				if(canEdit != null && canEdit == true && canAddNewRow2 != null && canAddNewRow2 == true) {
      					EditableListGrid1.this.ensureLastRowEmpty();
      				} else {
      					EditableListGrid1.this.removeEmptyRecord();
      				}
      			}
      		});
      		
      		addEditorExitHandler(new EditorExitHandler() {
      		
      			@Override
      			public void onEditorExit(final EditorExitEvent event) {
      				int rowNum = event.getRowNum();
      				ListGridRecord record = getRecord(rowNum);
      
      				if(record == null) {
      					return ;
      				}
      				if((isLastEmptyRow(record) && isRecordEmpty(record, rowNum))) {
      					clearRowErrors(rowNum);
      					return ;
      				}
      			}
      		});
      	}
      
      	public void initialize() {
              setAlternateRecordStyles(true);  
              setCellHeight(22);
              setCanEdit(false);  
              setModalEditing(true);
              setAutoSaveEdits(false);
              setEditEvent(ListGridEditEvent.DOUBLECLICK);  
              setListEndEditAction(RowEndEditAction.NEXT);
              setEmptyMessageStyle("emptyMessage");
      	
      		addKeyPressHandler(handler);
      		
      		addRowEditorExitHandler(handler);
      		
      		addDataArrivedHandler(handler);
      		
      		addCellClickHandler(handler);
      		
      	}
      	
      	@Override
      	public void setFields(ListGridField...fields) {
      		
      		ListGridField[] gridFields = fields;
      		firstEditColumnIndex = 0;
      		for(ListGridField field : gridFields) {
      			if(field.getCanEdit()) {
      				break;
      			}
      			firstEditColumnIndex++;
      		}
      	}
      	
      
      	public Boolean getCanAddNewRow() {
      		return canAddNewRow;
      	}
      	
      	public void setCanAddNewRow(boolean canAddNewRow) {
      		this.canAddNewRow = canAddNewRow;
      	}
      
      	public void makeEditable(boolean editable) {
      		if(getCanEdit() != null && getCanEdit() == editable) {
      			return ;
      		}
      		setCanEdit(editable);
      		if(styleName == null) {
      			styleName = getStyleName();
      			if(styleName == null) {
      				styleName = "";
      			}
      		}
      		if(editable) {
      			setStyleName(EDIT_DATA_STYLE);
      		} else {
      			setStyleName(styleName);
      		}
      		
      		if(editable) {
      			ensureLastRowEmpty();
      		} else {
      			removeEmptyRecord();
      		}
      	}
      	
      	public void removeEmptyRecord() {
      		ListGridRecord[] records = getRecords();
      		if(records.length == 0) {
      			return ;
      		}
      		int recordIndex = 0;
      		for(ListGridRecord record : records) {
      			if(!isRecordEmpty(record, recordIndex)) {
      				recordIndex++;
      				continue ;
      			}
      			removeData(record);
      			break;
      		}
      	}
      
      	public boolean addEmptyRecord(final boolean shouldEditing) {
      		final ListGridRecord newRecord = createEmptyRecord();
      		addData(newRecord, new DSCallback() {
      		
      			@Override
      			public void execute(DSResponse response, Object rawData, DSRequest request) {
      				if(shouldEditing && firstEditColumnIndex >= 0) {
      					int recordIndex = getRecordIndex2(newRecord);
      					startEditing(recordIndex, firstEditColumnIndex, false);
      				}
      			}
      		});
      		return true;
      	}
      
      	protected ListGridRecord createEmptyRecord() {
      		ListGridRecord newRecord = new ListGridRecord();
      		int id = (int) (Random.nextDouble() * -100000);
      		newRecord.setAttribute("DS_ID", new Integer(id));
      		newRecord.setAttribute(IS_EMPTY_RECORD, Boolean.TRUE);
      		newRecord.setAttribute("Active Status", "Y");
      		ListGridField[] fields = getAllFields(); // including hidden fields
      		for(ListGridField field : fields) {
      			newRecord.setAttribute(field.getName(), getDefaultValueForField(field));
      		}
      		return newRecord;
      	}
      
      	@SuppressWarnings("deprecation")
      	private Object getDefaultValueForField(ListGridField field) {
      		if(field.getType() == ListGridFieldType.TIME) {
      			return new Date(1900, 1, 1, 0, 0);
      		} else  if(field.getType() == ListGridFieldType.DATE) {
      			return null;
      		} else  if(field.getType() == ListGridFieldType.TEXT) {
      			return "";
      		} 
      		return null;
      	}
      	
      
      	public boolean ensureLastRowEmpty() {
      		return ensureLastRowEmpty(false);
      	}
      	
      	public boolean ensureLastRowEmpty(boolean editing) {
      		Record[] records = getRecords();
      		if(!getCanAddNewRow()) {
      			return false;
      		}
      		boolean emptyRowExist = false;
      		for (int i = 0; i < records.length; i++) {
      			if(!isRecordEmpty((ListGridRecord) records[i], i)){
      				records[i].setAttribute(IS_EMPTY_RECORD, Boolean.FALSE);
      			} else if(isLastEmptyRow((ListGridRecord) records[i])){
      				emptyRowExist = true;
      			}
      		}
      		if(!emptyRowExist) {
      			return addEmptyRecord(editing);
      		}
      		return false;
      	}
      
      	public boolean isRowEmpty(int rowNum) {
      		ListGridRecord record = getRecord(rowNum);
      		return isRecordEmpty(record, rowNum);
      	}
      	
      	public boolean isLastEmptyRow(int recordNum) {
      		return isLastEmptyRow(getRecord(recordNum));
      	}
      	
      	private boolean isLastEmptyRow(Record recordNum) {
      		return (recordNum.getAttributeAsBoolean(IS_EMPTY_RECORD) == Boolean.TRUE);
      	}
      
      	@SuppressWarnings("deprecation")
      	private boolean isRecordEmpty(ListGridRecord record, int recordIndex) {
      		ListGridRecord emptyRecord = createEmptyRecord();
      		ListGridField[] fields = getFields();
      		boolean lastRowEmpty = true;
      		if(isNewRecord(record)){
      			return false;
      		}
      		for(ListGridField field : fields) {
      			Object editedCell = getEditedCell(recordIndex, field.getName());
      			Object defaultValue = emptyRecord.getAttributeAsObject(field.getName());
      			if(editedCell != null && field.getType() == ListGridFieldType.TIME) {
      				Date edited = (Date) editedCell;
      				defaultValue = emptyRecord.getAttributeAsDate(field.getName());
      				Date defalt = (Date) defaultValue;
      				if(edited.getHours() != defalt.getHours() || edited.getMinutes() != defalt.getMinutes()) {
      					lastRowEmpty = false;
      					break;
      				}
      			} else if(editedCell != null && (String.valueOf(editedCell).trim().length() > 0	
      					&& !String.valueOf(editedCell).equalsIgnoreCase(String.valueOf(defaultValue)))){
      				lastRowEmpty = false;
      				break;
      			}
      		}
      		return lastRowEmpty;
      	}
      
      	public void startEditingNewRecord() {
      		if(!getCanEdit() || !getCanAddNewRow() || firstEditColumnIndex < 0) {
      			return ;
      		}
      		boolean editing = false;
      		int recIndex = 0;
      		for(Record record : getRecords()) {
      			ListGridRecord listGridRecord = (ListGridRecord) record;
      			if(isRecordEmpty(listGridRecord, recIndex)) {
      				startEditing(recIndex, firstEditColumnIndex, false);
      				editing = true;
      				break;
      			}
      			recIndex++;
      		}
      		if(!editing) {
      			addEmptyRecord(true);
      		}
      	}
      	
      	private class InternalHandler implements KeyPressHandler, RowEditorExitHandler, DataArrivedHandler, CellClickHandler {
      		
      		private boolean editingRequried;
      
      		@Override
      		public void onKeyPress(final KeyPressEvent event) {
      			processKeyPressEvent(event);
      		}
      
      		/**
      		 * @param event
      		 */
      		private void processKeyPressEvent(KeyPressEvent event) {
      			if(event.getKeyName().equals("f2") && getCanEdit()) {
      				ListGridRecord selectedRecord = getSelectedRecord();
      				if(selectedRecord != null && firstEditColumnIndex >= 0) {
      					int recordIndex = getRecordIndex2(selectedRecord);
      					startEditing(recordIndex, firstEditColumnIndex, false);
      				}
      			} else if (event.getKeyName().equals("f9")) {
      				startEditingNewRecord();
      			}
      		}
      		
      		@Override
      		public void onRowEditorExit(final RowEditorExitEvent event) {
      			processRowEditorExitEvent(event);
      		}
      
      		/**
      		 * @param event
      		 */
      		private void processRowEditorExitEvent(RowEditorExitEvent event) {
      			final int rowNum = event.getRowNum();
      			int colTotal = getAllFields().length;
      			if(isCanPerformDelete()) {
      				colTotal--;
      			}
      			boolean newRowAdded = false;
      			// if last row
      			newRowAdded = ensureLastRowEmpty();
      			ListGridRecord record = getRecord(rowNum);
      			if(newRowAdded) {
      				record.setAttribute(IS_EMPTY_RECORD, Boolean.FALSE);
      			}
      			if(event.getEditCompletionEvent().getValue().equals(EditCompletionEvent.ESCAPE.getValue()) && isNewRecord(record)) {
      				event.cancel();
      				endEditing();
      				return ;
      			} else  if(event.getEditCompletionEvent().getValue().equals(EditCompletionEvent.ARROW_UP.getValue())
      						|| event.getEditCompletionEvent().getValue().equals(EditCompletionEvent.ARROW_DOWN.getValue())) {
      				event.cancel();
      			}
      		}
      
      		@Override
      		public void onDataArrived(final DataArrivedEvent event) {
      			processDataArrivedEvent(event);
      		}
      
      		/**
      		 * @param event
      		 */
      		private void processDataArrivedEvent(DataArrivedEvent event) {
      			if(editingRequried) {
      				editingRequried = false;
      				if(firstEditColumnIndex >= 0) {
      					startEditing(event.getEndRow(), firstEditColumnIndex, false);
      				}
      			}
      			Boolean needToSelectFirstRow = getAttributeAsBoolean(PROP_NEED_TO_SELECT_FIRST_ROW);
      			if(needToSelectFirstRow != null && needToSelectFirstRow) {
      				_selectFirstRow();
      			}
      		}
      
      		@Override
      		public void onCellClick(final CellClickEvent event) {
      			processCellClickEvent(event);
      		}
      
      		/**
      		 * @param event
      		 */
      		private void processCellClickEvent(final CellClickEvent event) {
      			if(!isCanPerformDelete() || !getCanEdit() || event.getColNum() > 0){
      				return ;
      			}
      			final int rowNum = event.getRowNum();
      			if(isRowEmpty(rowNum)){
      				return ;
      			}
      		}
      
      	}
      	
      	
      	private boolean isNewRecord(Record record) {
      		return (record == null || record.getAttribute("DS_ID") == null) ? false : (Integer.valueOf(record.getAttribute("DS_ID")) < 0);
      	}
      	
      	@Override
      	public void setData(ListGridRecord[] records) {
      		if(isDrawn()) {
      			super.setData(records);
      			if(getCanEdit() && getCanAddNewRow()) {
      				ensureLastRowEmpty();
      			}
      		}
      	}
      	
      	@Override
      	public void setData(Record[] records) {
      		if(isDrawn()) {
      			super.setData(records);
      			if(getCanEdit() && getCanAddNewRow()) {
      				ensureLastRowEmpty();
      			}
      		}
      	}
      
      	
      	public boolean isCanPerformDelete() {
      		return canPerformDelete;
      	}
      
      	private void _selectFirstRow() {
      		setProperty(PROP_NEED_TO_SELECT_FIRST_ROW, false);
      		ListGridRecord[] records = getRecords();
      		if(records.length > 0) {
      			deselectAllRecords();
      			selectRecord(records[0]);
      		}
      	}
      	
      	public int getRecordIndex2(ListGridRecord record) {
      		if(record == null) {
      			return -1;
      		}
      		int recordIndex = getRecordIndex(record);
      		if(recordIndex < 0) {
      			String dsId = record.getAttribute("DS_ID");
      			if(dsId != null) {
      				int count = 0;
      				for(ListGridRecord record2 : getRecords()) {
      					String targetDsId = record2.getAttribute("DS_ID");
      					if(targetDsId != null && targetDsId.equals(dsId)) {
      						recordIndex = count;
      						break;
      					}
      					count ++;
      				}
      			}
      		}
      		return recordIndex;
      	}
      
      }
      Last edited by pratik.thaker; 11 Oct 2011, 23:13.

      Comment


        #4
        This is a huge pile of code. To demonstrate a bug, create a *minimal* test caseq so it's clear that this does not result from a usage error.

        Comment


          #5
          Hi Isomorphic

          I have trimmed down the extended class. Only sufficient modifications are there to reproduce the issue.

          Code:
          public EditableListGrid1() {
          		setLeaveScrollbarGap(false);
          		setCanEdit(false);
          		setCanDragSelectText(true);
          		setSaveLocally(true);
          		setAutoFetchData(true);  
          		
          		setAlternateRecordStyles(true);  
          		setCellHeight(22);
          		setCanEdit(false);  
          		setModalEditing(true);
          		setAutoSaveEdits(false);
          		setEditEvent(ListGridEditEvent.DOUBLECLICK);  
          		setListEndEditAction(RowEndEditAction.NEXT);
          		setEmptyMessageStyle("emptyMessage");
          		
          		addDrawHandler(new DrawHandler() {
          			
          			@Override
          			public void onDraw(DrawEvent event) {
          				Boolean canEdit = EditableListGrid1.this.getCanEdit();
          				if(canEdit != null && canEdit == true) {
          					EditableListGrid1.this.addEmptyRecord();
          				}
          			}
          		});
          	}
          
          	public void makeEditable(boolean editable) {
          		setCanEdit(editable);
          		if(editable) {
          			addEmptyRecord();
          		}
          	}
          
          	public void addEmptyRecord() {
          		addData(new ListGridRecord());
          	}
          Last edited by pratik.thaker; 12 Oct 2011, 03:40.

          Comment


            #6
            Hi Isomorphic,

            Can you please provide some solution on this ?

            Comment


              #7
              Hi Pratik,
              Sorry for the brief delay - we've been dealing with a lot of paid support requests over the last few days.

              The usage you're trying to achieve here is confusing. It looks like you're mixing two approaches:

              - You have 'autoFetchData' set to true, which will cause the ListGrid to fetch data from the dataSource, using a ResultSet. You also are calling 'addData()' which adds a record to the dataSource.
              - However on top of this you have 'saveLocally' set to true, which is intended to prevent edits being saved to the DataSource (so is typically set in cases where the dataSource is intended just as a schema, to define the fields to show, and actual data is explicitly set to an array of records via 'setData(<record list>)'), and in your description it sounds like you are calling 'setData()' to populate your grid with records.

              If you remove the 'saveLocally' setting, the bug goes away.

              What exactly are you trying to achieve here? From your description it sounds like 'autoFetchData' should not be set to true, since you intend to populate the grid via an explicit call to 'setData()', and the dataSource is present just to describe the fields to show.
              In this case, the 'addData()' api should also not be used, as that would add a record to the DataSource. If you want to initially show an empty record in the grid you can simply call 'setData(...)' and pass in an array with a single, empty ListGridRecord embedded in it.

              Comment


                #8
                Thanks Isomorphic.

                After removing setAutoFetchData(true), problem was resolved.
                We required setSaveLocally because we want to use addData since there are so many records in the grid. If we remove setSaveLocally then addData is not taking effect.

                Comment

                Working...
                X