Zakaroonikov
06-28-2007, 06:17 PM
I made some modifications to the Ext.nd.UIView class so that I am able to create a Ext.data.Store object without creating the view. By doing this I was able to get some Ext combo box examples to work with Domino.
I am not sure how useful the code is but here is the wrapper class that I created for the combo boxes. One the to notice is how I make use of Ext.nd.UIView. I pass these parameters to the constructor:
viewName: dataSource, // Ext.data.store from results
callback: this.setCombo.createDelegate(this), // Function to call after data.store is created
createGrid: false // Modification to Ext.nd.UIView code to not create grid if this is set
I have also added a new function to the Ext.util.Format class so that I can strip the prefix of the Ext.nd.UIView data records (it adds a prefix data type to the values). You would need to put something like this in your code or else you would get values like 'tJohn Smith' as a data value instead of 'John Smith' in your combo box list.
Ext.util.Format.stripLeft = function(value, start) {
return String(value).substr(start);
};
Here is the entire code for the class:
/**
* @class JCW.Form.ComboBox
* Represents a combobox field in a form<br><br>
* Usage:<br>
<pre><code>
* Transform on-page combobox field 'light' to Ext combobox with type ahead features
var ucb = new JCW.Form.ComboBox('light');
* Create combo box on field 'comboAjax' using domino viewentries url as datasource and displaying
* first column from results in select list
var cf2 = new JCW.Form.ComboBox( 'comboAjax', '/__CA25687000822467.nsf/Corporate+Extension+List');
* Create combo box on field 'comboTpl' using domino viewentries url as datasource and custom template
* to display 2 values from result in select List (stripLeft(1) is used to remove prefix character from Ext.nd)
var cf = new JCW.Form.ComboBox(
'comboTpl',
'/__CA25687000822467.nsf/Corporate+Extension+List',
{ tpl: [ '<div class="search-item">',
'<h3><span>{Name:stripLeft(1)}<br /></span></h3>{PhExt:stripLeft(1)}',
'</div>']}
);
* Create combo box on field 'comboLocal' using array 'AusState' below as data source and
* ['abbr', 'state'] mapping elements to field names. Configuration parameter col set to 1 tells
* the combo box to display the second element (state) as the element in the list and also what
* is returned to the field
AusStates = [
['ACT', 'Australian Capital Territory'],
['NSW', 'New South Wales'],
['NT', 'Northern Territory'],
['QLD', 'Queensland'],
['SA', 'South Australia'],
['TAS', 'Tasmania'],
['VIC', 'Victoria'],
['WA', 'Western Australia']
];
var arrcb = new JCW.Form.ComboBox('comboLocal',
{ fields: ['abbr', 'state'],
data : AusStates},
{ col: 1}
);
</code></pre>
* @constructor Create Ext.Form.ComboBox on dom ID fieldID
* @param {String} fieldID Dom ID of field to place combo box onto
* @param {String/Object} dataSource (optional) If datasource is not present that source of data is field specified in first parameter
* otherwise it is a string URL or an object containing an array with values and another with
* element to name mappings
* @param {Object} config (optional) Ext.Form.ComboBox config options (see Ext documentation for list)
*/
JCW.Form.ComboBox = function(fieldID, dataSource, config) {
if (fieldID) { // Only proceed if there is a destination field to place ext combobox onto
this.fieldID = fieldID;
this.config = {}; // Combobox configuration object (keep separate from object so we can pass entire configuration across)
Ext.apply(this.config, config); // Update combobox config with pass params
this.setupCombo(dataSource); // Determine type of combobox data source and run the appropriate configuration
}
};
JCW.Form.ComboBox.prototype = {
dominoConfig: {
typeAhead: false,
emptyText: 'Search',
loadingText: 'Loadind Data...',
pageSize: 10,
queryParam: 'StartKey',
listClass: 'x-combo-list',
hideTrigger: true
},
arrayConfig: {
typeAhead: true,
mode: 'local',
triggerAction: 'all',
emptyText:'Search',
selectOnFocus:true,
listClass: 'x-combo-list'
},
htmlConfig: {
typeAhead: true,
mode: 'local',
triggerAction: 'all',
listClass: 'x-combo-list',
forceSelection:true
},
/**
* Using dataSource, determine if source data is from Domino View Entries, a javascript array or the field already has the content and needs
* reformatting
* @param {String/Object} dataSource (optional) If datasource is not present that source of data is field specified in first parameter
* otherwise it is a string URL or an object containing an array with values and another with
* element to name mappings
*/
setupCombo : function (dataSource) {
if (dataSource) { // Datasource is supplied
if(typeof dataSource == 'string') { // If datasource parameter is supplied and is a string then it is a URL so use AJAX to get the data
this.setupDominoCombo(dataSource);
} else if(dataSource.fields && dataSource.data){ // If datasource is an array with a field name mapping
this.setupArrayCombo(dataSource);
}
} else { // No datasource so this is a transformation of a regular combobox to an ext combo box
this.setupHTMLCombo();
}
},
/**
* Using a dom ID for an existing combobox field convert it to use Ext.Form.ComboBox type-ahead capabilities
*/
setupHTMLCombo : function() {
Ext.applyIf(this.config, this.htmlConfig); // Set defaults for field conversion
this.config.transform = this.fieldID; // Set field to transform to passed in field dom id
var comboField = new Ext.form.ComboBox(this.config); // Convert field to ext.form.combobox
},
/**
* Using an object containing an array with the data to add to the combo box and another array mapping element numbers to identifiers
* create an Ext.data.Store for the combobox to use for its type-ahead
* @param {Object} dataSource Object contains an array with data values and another array with element to name mappings
*/
setupArrayCombo : function(dataSource) {
Ext.applyIf(this.config, this.arrayConfig); // Set defaults for array datasource combobox
this.store = new Ext.data.SimpleStore(dataSource); // Create ext data store using supplied object
if(this.store) {
this.config.displayField = this.setDisplayField(); // Determine what element in data array to use when an item is selected and also
// what to display as default element in listing (if no template is supplied)
var comboField = new Ext.form.ComboBox(this.config);
comboField.store = this.store;
comboField.tpl = this.setTemplate(comboField,false); // Get template from supplied config or use the default displaying displayField
comboField.applyTo(this.fieldID); // apply it to the exsting input element
}
},
/**
* Using supplied url to view get the readviewentires and use it as datasource for this combobox
* @param {String} dataSource Url to view (not containing any ? parameters) to get readviewentires from
*/
setupDominoCombo : function(dataSource) {
Ext.applyIf(this.config, this.dominoConfig); // Set defaults for viewentriesd datasource combobox
var DataStore = new Ext.nd.UIView({ // Read-in readviewentires for the supplier url and call this.setCombo on success with
viewName: dataSource, // Ext.data.store from results
callback: this.setCombo.createDelegate(this),
createGrid: false
});
},
/**
* Callback function called by Ext.nd.UIView if data is successfully read from ReadViewEntries for supplied url
* @param {Ext.data.Store} ds Resultset from converted ReadViewEntries query
*/
setCombo : function (ds) {
this.store = ds;
if(this.store) {
this.config.displayField = this.setDisplayField(); // Determine what element in data store to use when an item is selected and also
// what to display as default element in listing (if no template is supplied)
var comboField = new Ext.form.ComboBox(this.config);
comboField.tpl = this.setTemplate(comboField, true); // Get template from supplied config or use the default displaying displayField
comboField.sv = comboField.setValue; // Store original function
comboField.setValue = function(v) {
// Override setValue function of combobox as Ext.nd.UIView stores ReadViewEntries values with 1 character prefix
// This prefix is stripped below before the field value is set (when an item is selected from the combo list)
if(v) return comboField.sv(Ext.util.Format.stripLeft(v, 1));
}
comboField.store = this.store;
comboField.applyTo(this.fieldID); // apply it to the exsting input element
}
},
/**
* If the configuration parameter hasn't been set for displayField then use the element number (either config.col or 0 if it doesn't exist)
* as in index to get the data element name
* @return {String} Element identifier to use for display (including default for combo list if no template is supplied)
*/
setDisplayField : function () {
// Use column number as key for data source if displayField is not set (col number defaults to 0 which is the first column in the view)
if (!this.config.displayField)
// Get element name using this.config.col if it exists otherwise get first element
return this.getIndex(String(this.config.col ? this.config.col : 0));
else
return this.config.displayField;
},
/**
* Setup the template to use for displaying the combo list. Use the config template if supplied otherwise use the default
* @param {Ext.Form.ComboBox} comboField Field to merge into the template being set
* @param {boolean} stripLeft (Optional) True if first character is to be stripped on default template
* @return {String/Ext.Template} Template to use for display of combo list
*/
setTemplate : function (comboField, stripLeft) {
var template;
if (this.config.tpl) { // Use config template if supplied
template = new Ext.Template(this.config.tpl);
// Replace any column numbers in template with their corresponding object index name
// ie {0} becomes {Name} if 'Name' is the first column name described in the lookup
template.html = String(template.html).replace(/\{([\d]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g, this.getIndex.createDelegate(comboField));
} else { // If no template was supplied use the default which is a 1-item div list using displayField as the column name/number for the data
template = '<div class="'+comboField.listClass+'-item">{' + comboField.displayField + (stripLeft ? ':stripLeft(1)' : '') + '}</div>';
}
return template;
},
/**
* Given a numeric key for the data grab the literal identifier for the element in the data list
* @param {String} key Index of element in item's data array
* @return {String} Literal identifier of the data element at this index
*/
getIndex : function(key) {
var keyNumber = key.match(/\d+/); // Remove anything in string that is not numeric
if (keyNumber) {
var idx = parseInt(keyNumber); // Convert numeric portion of string to integer for array lookup
if(this.store.fields.keys.length >= idx+1)
return this.store.fields.keys[idx]; // Use key to locate field name for this element
else
return key;
}
}
};
I am not sure how useful the code is but here is the wrapper class that I created for the combo boxes. One the to notice is how I make use of Ext.nd.UIView. I pass these parameters to the constructor:
viewName: dataSource, // Ext.data.store from results
callback: this.setCombo.createDelegate(this), // Function to call after data.store is created
createGrid: false // Modification to Ext.nd.UIView code to not create grid if this is set
I have also added a new function to the Ext.util.Format class so that I can strip the prefix of the Ext.nd.UIView data records (it adds a prefix data type to the values). You would need to put something like this in your code or else you would get values like 'tJohn Smith' as a data value instead of 'John Smith' in your combo box list.
Ext.util.Format.stripLeft = function(value, start) {
return String(value).substr(start);
};
Here is the entire code for the class:
/**
* @class JCW.Form.ComboBox
* Represents a combobox field in a form<br><br>
* Usage:<br>
<pre><code>
* Transform on-page combobox field 'light' to Ext combobox with type ahead features
var ucb = new JCW.Form.ComboBox('light');
* Create combo box on field 'comboAjax' using domino viewentries url as datasource and displaying
* first column from results in select list
var cf2 = new JCW.Form.ComboBox( 'comboAjax', '/__CA25687000822467.nsf/Corporate+Extension+List');
* Create combo box on field 'comboTpl' using domino viewentries url as datasource and custom template
* to display 2 values from result in select List (stripLeft(1) is used to remove prefix character from Ext.nd)
var cf = new JCW.Form.ComboBox(
'comboTpl',
'/__CA25687000822467.nsf/Corporate+Extension+List',
{ tpl: [ '<div class="search-item">',
'<h3><span>{Name:stripLeft(1)}<br /></span></h3>{PhExt:stripLeft(1)}',
'</div>']}
);
* Create combo box on field 'comboLocal' using array 'AusState' below as data source and
* ['abbr', 'state'] mapping elements to field names. Configuration parameter col set to 1 tells
* the combo box to display the second element (state) as the element in the list and also what
* is returned to the field
AusStates = [
['ACT', 'Australian Capital Territory'],
['NSW', 'New South Wales'],
['NT', 'Northern Territory'],
['QLD', 'Queensland'],
['SA', 'South Australia'],
['TAS', 'Tasmania'],
['VIC', 'Victoria'],
['WA', 'Western Australia']
];
var arrcb = new JCW.Form.ComboBox('comboLocal',
{ fields: ['abbr', 'state'],
data : AusStates},
{ col: 1}
);
</code></pre>
* @constructor Create Ext.Form.ComboBox on dom ID fieldID
* @param {String} fieldID Dom ID of field to place combo box onto
* @param {String/Object} dataSource (optional) If datasource is not present that source of data is field specified in first parameter
* otherwise it is a string URL or an object containing an array with values and another with
* element to name mappings
* @param {Object} config (optional) Ext.Form.ComboBox config options (see Ext documentation for list)
*/
JCW.Form.ComboBox = function(fieldID, dataSource, config) {
if (fieldID) { // Only proceed if there is a destination field to place ext combobox onto
this.fieldID = fieldID;
this.config = {}; // Combobox configuration object (keep separate from object so we can pass entire configuration across)
Ext.apply(this.config, config); // Update combobox config with pass params
this.setupCombo(dataSource); // Determine type of combobox data source and run the appropriate configuration
}
};
JCW.Form.ComboBox.prototype = {
dominoConfig: {
typeAhead: false,
emptyText: 'Search',
loadingText: 'Loadind Data...',
pageSize: 10,
queryParam: 'StartKey',
listClass: 'x-combo-list',
hideTrigger: true
},
arrayConfig: {
typeAhead: true,
mode: 'local',
triggerAction: 'all',
emptyText:'Search',
selectOnFocus:true,
listClass: 'x-combo-list'
},
htmlConfig: {
typeAhead: true,
mode: 'local',
triggerAction: 'all',
listClass: 'x-combo-list',
forceSelection:true
},
/**
* Using dataSource, determine if source data is from Domino View Entries, a javascript array or the field already has the content and needs
* reformatting
* @param {String/Object} dataSource (optional) If datasource is not present that source of data is field specified in first parameter
* otherwise it is a string URL or an object containing an array with values and another with
* element to name mappings
*/
setupCombo : function (dataSource) {
if (dataSource) { // Datasource is supplied
if(typeof dataSource == 'string') { // If datasource parameter is supplied and is a string then it is a URL so use AJAX to get the data
this.setupDominoCombo(dataSource);
} else if(dataSource.fields && dataSource.data){ // If datasource is an array with a field name mapping
this.setupArrayCombo(dataSource);
}
} else { // No datasource so this is a transformation of a regular combobox to an ext combo box
this.setupHTMLCombo();
}
},
/**
* Using a dom ID for an existing combobox field convert it to use Ext.Form.ComboBox type-ahead capabilities
*/
setupHTMLCombo : function() {
Ext.applyIf(this.config, this.htmlConfig); // Set defaults for field conversion
this.config.transform = this.fieldID; // Set field to transform to passed in field dom id
var comboField = new Ext.form.ComboBox(this.config); // Convert field to ext.form.combobox
},
/**
* Using an object containing an array with the data to add to the combo box and another array mapping element numbers to identifiers
* create an Ext.data.Store for the combobox to use for its type-ahead
* @param {Object} dataSource Object contains an array with data values and another array with element to name mappings
*/
setupArrayCombo : function(dataSource) {
Ext.applyIf(this.config, this.arrayConfig); // Set defaults for array datasource combobox
this.store = new Ext.data.SimpleStore(dataSource); // Create ext data store using supplied object
if(this.store) {
this.config.displayField = this.setDisplayField(); // Determine what element in data array to use when an item is selected and also
// what to display as default element in listing (if no template is supplied)
var comboField = new Ext.form.ComboBox(this.config);
comboField.store = this.store;
comboField.tpl = this.setTemplate(comboField,false); // Get template from supplied config or use the default displaying displayField
comboField.applyTo(this.fieldID); // apply it to the exsting input element
}
},
/**
* Using supplied url to view get the readviewentires and use it as datasource for this combobox
* @param {String} dataSource Url to view (not containing any ? parameters) to get readviewentires from
*/
setupDominoCombo : function(dataSource) {
Ext.applyIf(this.config, this.dominoConfig); // Set defaults for viewentriesd datasource combobox
var DataStore = new Ext.nd.UIView({ // Read-in readviewentires for the supplier url and call this.setCombo on success with
viewName: dataSource, // Ext.data.store from results
callback: this.setCombo.createDelegate(this),
createGrid: false
});
},
/**
* Callback function called by Ext.nd.UIView if data is successfully read from ReadViewEntries for supplied url
* @param {Ext.data.Store} ds Resultset from converted ReadViewEntries query
*/
setCombo : function (ds) {
this.store = ds;
if(this.store) {
this.config.displayField = this.setDisplayField(); // Determine what element in data store to use when an item is selected and also
// what to display as default element in listing (if no template is supplied)
var comboField = new Ext.form.ComboBox(this.config);
comboField.tpl = this.setTemplate(comboField, true); // Get template from supplied config or use the default displaying displayField
comboField.sv = comboField.setValue; // Store original function
comboField.setValue = function(v) {
// Override setValue function of combobox as Ext.nd.UIView stores ReadViewEntries values with 1 character prefix
// This prefix is stripped below before the field value is set (when an item is selected from the combo list)
if(v) return comboField.sv(Ext.util.Format.stripLeft(v, 1));
}
comboField.store = this.store;
comboField.applyTo(this.fieldID); // apply it to the exsting input element
}
},
/**
* If the configuration parameter hasn't been set for displayField then use the element number (either config.col or 0 if it doesn't exist)
* as in index to get the data element name
* @return {String} Element identifier to use for display (including default for combo list if no template is supplied)
*/
setDisplayField : function () {
// Use column number as key for data source if displayField is not set (col number defaults to 0 which is the first column in the view)
if (!this.config.displayField)
// Get element name using this.config.col if it exists otherwise get first element
return this.getIndex(String(this.config.col ? this.config.col : 0));
else
return this.config.displayField;
},
/**
* Setup the template to use for displaying the combo list. Use the config template if supplied otherwise use the default
* @param {Ext.Form.ComboBox} comboField Field to merge into the template being set
* @param {boolean} stripLeft (Optional) True if first character is to be stripped on default template
* @return {String/Ext.Template} Template to use for display of combo list
*/
setTemplate : function (comboField, stripLeft) {
var template;
if (this.config.tpl) { // Use config template if supplied
template = new Ext.Template(this.config.tpl);
// Replace any column numbers in template with their corresponding object index name
// ie {0} becomes {Name} if 'Name' is the first column name described in the lookup
template.html = String(template.html).replace(/\{([\d]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g, this.getIndex.createDelegate(comboField));
} else { // If no template was supplied use the default which is a 1-item div list using displayField as the column name/number for the data
template = '<div class="'+comboField.listClass+'-item">{' + comboField.displayField + (stripLeft ? ':stripLeft(1)' : '') + '}</div>';
}
return template;
},
/**
* Given a numeric key for the data grab the literal identifier for the element in the data list
* @param {String} key Index of element in item's data array
* @return {String} Literal identifier of the data element at this index
*/
getIndex : function(key) {
var keyNumber = key.match(/\d+/); // Remove anything in string that is not numeric
if (keyNumber) {
var idx = parseInt(keyNumber); // Convert numeric portion of string to integer for array lookup
if(this.store.fields.keys.length >= idx+1)
return this.store.fields.keys[idx]; // Use key to locate field name for this element
else
return key;
}
}
};