Announcement

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

    Error Message

    Hi,

    I've built a custom FormItem derived class and whenever I call this.setError(), my error gets displayed but the styling
    is different than for built-in ISC components. For example, DateItem will display its error and have the item surrounded
    by a red box (embedded within a listGrid). My custom FormItem derived class will render the error message, but I don't
    get the red box around my component.

    I tried looking at the code but couldn't find anything. Is there anything particular I need to do get the same behavior?

    I'm using version 8 nightly build.

    Thanks,

    #2
    Can you show your custom formItem code and a screenshot of the styling issue you're seeing?

    Comment


      #3
      The idea is that we have a foreign-key picker field. Upon the user returning from the picker, multiple values on the underlying
      record get set. One is the actual display value for the field per say, but we also update non visible fields which is typically the
      foreign-key field per say (what we call candidate - could be more than one field).

      The styling issue occurs when embedded within a listGrid, when there's a validation error.

      From the attached screen snapshot, the expected behavior would be to have the picker validation appear like it appears for the
      invalid 'Start Date' field, that is with a red box around it. Our picker's validation appears but without the red box around it ...

      Here's the code to our custom validator which gets attached (at the DS level) to all fields which are of type 'MyPickerBoxItem':

      Code:
      //--------------------------------------------------------------------------------------------------------------------------------
      /**
       * Global validator for foreignKey item fields
       */
      //--------------------------------------------------------------------------------------------------------------------------------
      function MyPickerBoxValidator(item, validator, value, record)
      {
      	// always valid when no form is available to validate against
      
      	if (!item.form)
      		return true;
      
      	// if contains no value, FK's integrity is valid
      
      	if (!item.getValue())
      	 	return true;
      
      	// if FK was set properly, integrity is valid
      
      	var isSet = item.isSet();
      
      	return isSet;
      }
      Here's the code to the actual MyPickerBoxItem class:

      Code:
      //--------------------------------------------------------------------------------------------------------------------------------
      /**
       * This widget extends a specialized TextItem which handles foreign key selections.
       * 
       * @class Extends TextItem which wraps foreign-key "picker-box" functionnality
       * @extends TextItem
       * @see <a href="http://www.smartclient.com/docs/6.5.1/a/b/c/go.html#class..TextItem">TextItem</a> base class definition
       */
      //--------------------------------------------------------------------------------------------------------------------------------
      
      var MyPickerBoxItem = isc.defineClass('MyPickerBoxItem', 'TextItem');
      
      //-----------------------------
      // Instance class members
      //-----------------------------
      MyPickerBoxItem.addProperties
      (
      	/** @lends MyPickerBoxItem.prototype */
      {
      	//-----------------------------
      	// Properties
      	//-----------------------------
      
      	showPickerIcon : true,
      	pickerIconSrc : 'pickerbox/cleared.png',
      	pickerIconWidth : 16,
      	pickerIconHeight : 16,
      
      	/**
      	 * Property determines whether or not component should have its data saved.
      	 *  
      	 * @field
      	 * @type Boolean
      	 * @default true
      	 */
      	shouldSaveValue : true,
      
      	/**
      	 * Property determines searcher field name. Determined once during init() cycle.
      	 *  
      	 * @field
      	 * @type String
      	 * @default null
      	 */
      	pbSearchFieldName : null,
      
      	/**
      	 * Property determines selector view name to be used for searcher.
      	 *  
      	 * @field
      	 * @type String
      	 * @default null
      	 */
      	pbSelectorViewName : null,
      
      	/**
      	 * Array of column names for candidate fields.
      	 *
      	 * @field
      	 * @type Array of Strings
      	 * @default null
      	 */
      	pbCandidateFields : null,
      
      	/**
      	 * Array of column names for candidate fields.
      	 *
      	 * @field
      	 * @type Array of Strings
      	 * @default null
      	 */
      	pbDisplayFields : null,
      
      	//-----------------------------
      	// Methods
      	//-----------------------------
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Initializes the form item. Overrides the ISC framework <b>init()</b> method. This method is called automatically
      	 * by the ISC framework when this object gets created. This method must not be called explicitly.<br><br>
      	 * 
      	 * @inner
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	init : function()
      	{
      		// determine search field name associated with this picker box item
      
      		this.pbSearchFieldName = this.name.substring(this.name.indexOf('.') + 1);
      
      		// if embedded within list, validate on form exit
      
      		if (this.form.grid)
      			this.validateOnExit = true;
      
      		// let base class do its thing
      
      		this.Super('init', arguments);
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Returns true if this picker is set, false otherwise. Examines underlying candidate values to figure this out.
      	 * 
      	 * @return {Boolean}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	isSet : function()
      	{
      		for (var i = 0; i < this.pbCandidateFields.length; ++i)
      		{
      			var value;
      			if ((value = this.getAssociatedValue(this.pbCandidateFields[i])) == null)
      				return false;
      		}
      
      		return true;
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Sets the value for this picker component.
      	 * 
      	 * @param {String|Object} value
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	setValue : function(value)
      	{
      		if (isAn.Object(value))
      		{
      			// update display value (self)
      
      			if (value[this.pbSearchFieldName])
      			{
      				// update underlying storage (required for cases where form was destroyed, ie: focus changed)
      
      				this.setAssociatedValue(this.name, value[this.pbSearchFieldName]);
      
      				// update actual U/I form field
      
      				this.setValue(value[this.pbSearchFieldName]);
      			}
      
      			// update underlying associated values (candidate and other display fields)
      
      			this.setAssociatedValues(value);
      
      			// if hosted within listGrid, redraw for changes to be visible
      
      			if (this.form.grid)
      				this.form.grid.markForRedraw('ListGridRecord programatically updated');
      		}
      		else
      			this.Super('setValue', arguments);
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Sets the associated values for this picker component. This includes candidate fields as well as sibling display fields
      	 * which also relate to the foreign key currently selected. If record is null, all associated values are cleared.
      	 * 
      	 * @param {Object} record
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	setAssociatedValues : function(record)
      	{
      		var fldCollections = [ this.pbCandidateFields, this.pbDisplayFields ];
      
      		for (var i = 0; i < fldCollections.length; ++i)
      		{
      			for (var j = 0; j < fldCollections[i].length; ++j)
      			{
      				var fldNamePicker = fldCollections[i][j];
      				var fldNameSearcher = fldCollections[i][j].substring(this.name.indexOf('.') + 1);
      
      				var value = null;
      				if (record && record[fldNameSearcher])
      					value = record[fldNameSearcher];
      
      				this.setAssociatedValue(fldNamePicker, value);
      			}
      		}
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Sets the associated value for the given field.
      	 * 
      	 * @param {String} fieldName
      	 * @param {Object} value
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	setAssociatedValue : function(fieldName, value)
      	{
      		if (this.form.dataSource.fields[fieldName])
      		{
      			if (this.form.grid && this.form.grid.data)
      			{
      				var row;
      				if ((row = this.form.grid.getEditRow()) != null)
      			 		this.form.grid.data[row][fieldName] = value;
      			}
      			else
      				this.form.valuesManager.setValue(fieldName, value);
      		}
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Gets the associated value for the given field.
      	 * 
      	 * @param {String} fieldName
      	 * @return {Object}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	getAssociatedValue : function(fieldName)
      	{
      		if (this.form.dataSource.fields[fieldName])
      		{
      			if (this.form.grid && this.form.grid.data)
      			{
      				var row;
      				if ((row = this.form.grid.getEditRow()) != null)
      					return this.form.grid.data[row][fieldName];
      			}
      			else if (this.form.valuesManager)
      				return this.form.valuesManager.getValue(fieldName);
      		}
      
      		return null;
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Called internally by the ISC framework when user inputs data into the picker box.
      	 * 
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
          keyPress : function (item, form, keyName, characterValue)
      	{
      		// clear underlying associated values (candidate and other display fields)
      
      		if (characterValue || keyName == 'Delete' || keyName == 'Backspace')
      		{
      			if (this.isSet())
      				this.setAssociatedValues(null);
      		}
      
      		this.Super('keyPress', arguments);
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Shows associated MyBrowser for user to choose appropriate value. Called internally by the ISC framework
      	 * when user clicks the picker button.
      	 * 
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
          showPicker : function (modal, icon, pickerProperties, rect)
      	{
      		this.doSearch();
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Shows associated MyBrowser for user to choose appropriate value.
      	 * 
      	 * @inner
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	doSearch : function()
      	{
      		// setup search criteria / values
      
      		var searchCriteria = {};
      		var pickerValues = {};
      
      		var searchValue;
      		if ((searchValue = this.getValue()) != null)
      		{
      			searchCriteria[this.pbSearchFieldName] = { isText : true, value : searchValue };
      			pickerValues[this.pbSearchFieldName] = searchValue;
      		}
      
      		// keep handle to picker-box for later usage within JS closure
      
      		var thisPickerBox = this;
      
      		// create view loader and load view metadata
      
      		var viewLoader = MyLoaderView.create({});
      
      		viewLoader.loadView(this.pbSelectorViewName, null, // no params
      			function(rpcResponse, data, rpcRequest)
      			{
      				// make sure valid response was received from server
      
      				if (rpcResponse == null || rpcResponse.httpResponseCode != 200 || data == null)
      				{
      					MyApplication.dumpServerResponseError('MyPickerBoxItem.doSearch(viewLoad) failed.',
      						rpcRequest.actionURL, rpcRequest.httpMethod, rpcRequest.params, rpcRequest.data,
      						rpcResponse.httpResponseCode, rpcResponse.httpResponseText);
      
      					return;
      				}
      
      				// extract table name from view meta
      
      				thisPickerBox.tableName = viewLoader.meta.tableName;
      
      				// build criteria using SQL LIKE syntax
      
      				var where = MyLoaderAbstract.getWhereProperty(searchCriteria, true);
      
      				// load data matching given criteria
      
      				var selectorLoader = MyLoaderSelector.create({ viewLoader : viewLoader });
      
      				selectorLoader.load(where,
      					function(dsResponse, data, dsRequest)
      					{
      						// make sure valid response was received from server
      
      						if (dsResponse == null || dsResponse.httpResponseCode != 200 || data == null)
      						{
      							MyApplication.dumpServerResponseError('MyPickerBoxItem.doSearch(selectorLoad) failed.',
      								dsResponse.context.actionURL, dsResponse.context.httpMethod, dsResponse.context.params,
      								selectorLoader.viewLoader.dataSource.latestRawClientDataSent,
      								dsResponse.httpResponseCode, selectorLoader.viewLoader.dataSource.latestRawServerDataReceived);
      
      							return;
      						}
      
      						// prepare searcher parameters
      
      						var contextTitle;
      						if (thisPickerBox.grid)
      							contextTitle = thisPickerBox.grid.dataSource.title;
      						else
      							contextTitle = thisPickerBox.form.dataSource.title;
      
      						var selectorData = data;
      
      						// if no meta specified, bail out
      
      						if (viewLoader.meta == null)
      							return;
      
      						// show browser to have user choose from
      
      						if (!isAn.emptyString(viewLoader.meta.searcherViewName))
      						{
      							// create/load associated searcher
      
      							var searcherLoader = MyLoaderView.create({ viewName : viewLoader.meta.searcherViewName });
      
      							searcherLoader.load(null, // no meta params
      								function(dsResponse, data, dsRequest)
      								{
      									thisPickerBox.showSelector(selectorLoader, searcherLoader,
      										selectorData, pickerValues, contextTitle);
      								});
      						}
      						else
      							thisPickerBox.showSelector(selectorLoader, null, selectorData, pickerValues, contextTitle);
      					});
      			});
      	},
      
      	//----------------------------------------------------------------------------------------------------------------------------
      	/**
      	 * Actually shows the selector data browser.
      	 *
      	 * @inner
      	 * @param {SelectorLoader} selectorLoader Associated selector loader
      	 * @param {SearcherLoader} searcherLoader Associated searcher loader
      	 * @param {Object} data Initial listGrid data
      	 * @param {Object} pickerValues from picker box
      	 * @param {String} contextTitle
      	 * @return {void}
      	 */
      	//----------------------------------------------------------------------------------------------------------------------------
      	showSelector : function(selectorLoader, searcherLoader, data, pickerValues, contextTitle)
      	{
      		// keep handle to picker-box for later usage within JS closure
      
      		var thisPickerBox = this;
      
      		// show selector associated with picker-box
      
      		MyBrowser.showFromPickerBox(selectorLoader,
      			searcherLoader, data, pickerValues, contextTitle,
      			function(cancelled, record)
      			{
      				// upon record selection from selector, update picker box
      
      				if (!cancelled)
      					thisPickerBox.setValue(record);
      			});
      	}
      });
      Attached Files

      Comment


        #4
        Hmm, this is a pretty ordinary subclass of TextItem, which you should be able to verify will show that outline. Take a look at these properties which control error styling and try using the Developer Console to verify they are still set to their defaults, and Firebug to see whether the indicated CSS styleNames are being applied to the cell.

        Comment


          #5
          Thanks,

          I'll look into it, although this is obviously not a top priority for us at this time.

          I'll get back if I can't figure it out and if it becomes a show stopper for product management.

          Kind regards,

          Comment

          Working...
          X