I’ll admit that I’m very fortunate. I work in a field that is my true passion. I am a technologist, and more specifically, a software architect. I also work for a great company that allows me to be creative, efficient, and impactful.
However, a recent article I read just made me realize that my passion has been eaten away by something else.
I used to work late… just because. If I was working on some particularly hairy algorithm, or software problem, I would work until it was complete. I got a rush out of it, and a deep sense of satisfaction that I could turn something complex into something elegantly simple.
I would go home and read technical books, online articles, and samples about up-and-coming languages or tools. I would be constantly writing sample applications in new languages, or playing around with a new database schema editor or programming environment. I would also join discussion groups, and attend local user group meetings just to meet and talk with people who shared my passion.
Most of that is gone now.
Now, my overriding thought is my two girls. They are my passion. Growing up and in my early adulthood, I knew I wanted a family and wanted to be the best father I could be. I thought about how I would raise my children to be competent, intelligent, resourceful adults.
Now that I am actually a father, I’ve realized two things:
Gone are the days of coming home and reading books and magazines about technology. Now I come home and am welcomed by two little girls who scream, “Daddy!! You’re home!!” and want hugs and kisses.
How can you not be passionate about that?
A few weeks ago I was at a gathering of like-minded technologists in my area, and I struck up a quick (thankfully) conversation with a fellow who, in all seriousness, labeled himself a Social Media Ninja. He just let it hang there for a second, waiting for the expected, and inevitable, question, “What is a Social Media Ninja?”
I’ll do my best to correctly paraphrase his response.
Apparently, a Social Media Ninja is someone who has 5000 followers on their Twitter account, shares links to articles that other people post throughout the day, and has an active Facebook fan page.
Huh.
So I guess my 15-year-old niece is a Social Media Ninja. Perhaps she should be out there trying to get the same jobs that this tool – I mean Ninja – is trying to procure.
Not once did he talk about how these amazing, super-human like powers could possibly help a business retain, or gain, customers. He failed to mention that he could affect a company’s revenue stream in any way shape or form. Apparently he just wants someone to hire him so that he can create a Twitter account, and a Facebook fan page and sit there and talk to people all day.
No strategy. No plan. Sorry, that means no results.
However, he does have something cool to put on his business cards.
In an ExtJS ComboBox, it’s fairly easy to implement a search feature where given the user’s entry, you can return a list of possible matches. I outline this mechanism in Sencha ExtJS: Simple Autocomplete Example.
However, recent user feedback was, “If I know the unit I’m looking for, why can’t I just type it in and hit ENTER and skip the whole search feature to find the one I need?”
Doh.
Yes, I was making the users wait – even if for 1 second – for a list of possible matches to be displayed, when 90% of the time they know which one they want to open.
Luckily, I was able to briefly look at the documentation for ComboBox and find out how to accomplish this. You need to set the enableKeyEvents config property to true, and then hook into the keypress event and check for the user pressing the ENTER (or RETURN) key. When the ENTER key is pressed, prevent the query from being executed, and open the item the user entered.
var WidgetSearch = new Ext.form.ComboBox({
minChars: 3,
loadingText: '',
itemSelector: 'div.search-item',
triggerClass: 'x-form-search-trigger',
applyTo: 'search-field',
enableKeyEvents: true,
store: new Ext.data.Store({
proxy: new Ext.data.HttpProxy({url: 'widgets.cfm'}),
reader: new Ext.data.JsonReader({
root: 'data',
totalProperty: 'recordcount'
}, [
{name: 'widget_number', type: 'string'},
{name: 'widget_name', type: 'string'}
])
}),
tpl: new Ext.XTemplate(
'<tpl for="."><div class="search-item">',
'{widget_number} - {widget_name}',
'</div></tpl>'
),
onSelect: function(record){
document.location.href = 'displayWidgetDetails.cfm&wid=' + record.data.widget_number;
},
listeners:
{
// Hook into the keypress event to detect if the user pressed the ENTER key
keypress: function(comboBox, e){
if (e.getCharCode() == e.ENTER) {
// Prevent the default query action since the user
// believes she has entered a proper widget number
comboBox.on('beforequery', function(q){q.cancel=true;},this);
// Redirect browser to widget detail view
document.location.href = 'displayWidgetDetails.cfm&wid=' + WidgetSearch.getValue();
}
}
}
});
A Sencha ExtJS EditorGridPanel automatically visually marks a cell as dirty when a user modifies the value, but that’s it. If you want to know if a row is dirty and take an action based upon that knowledge, you’re on your own.
Since I needed this functionality, I took a stab at it today, and here’s my simplistic example of how to do it.
First, I create a global variable named editedRow which will get updated when the afteredit event is fired on the GridPanel.
var editedRow;
var AutoGrid = new Ext.grid.EditorGridPanel({
// Properties clipped for article;
// view example for full code
});
// After any field is edited, make the row dirty
AutoGrid.on('afteredit', function(){
if (!editedRow){
editedRow = AutoGrid.getSelectionModel().getSelections();
}
}, this);
Now that I’ve stored which row is dirty, every time the user clicks on another cell, I check a) there is a dirty row, and b) if the active row is the dirty row.
// Any time the user mouse downs on a cell,
// check to see if there are any dirty rows
AutoGrid.on('cellmousedown', checkForChanges, this);
function checkForChanges(){
if (!editedRow){
return true; // No dirty rows
} else {
var selectedRow = AutoGrid.getSelectionModel().getSelections();
var selectedRecord = selectedRow[0].data;
var editedRecord;
editedRecord = editedRow[0].data;
if (selectedRecord.model != editedRecord.model){
// Alert the user to save changes
// See example for full code
}
}
}
Then if there is a dirty row, I can prompt the user and ask it to save its changes before editing another row.
Man this took a long time to figure out.
Ok, inside a Sencha ExtJS DataGrid, I have assigned a ComboBox as the editor for one of the columns populated with its own Store of items. I’ve got a ColdFusion Component returning a query object, which is then converted into JSON with the ajaxCFC class.
var ItemCode = Ext.data.Record.create([
{name: 'item_id', type: 'int'}
{name: 'item_code', type: 'string'}
]);
var ItemCodesStore = new Ext.data.Store({
autoLoad:false,
proxy: new Ext.data.MemoryProxy(),
reader: new Ext.data.JsonReader({ root: 'data'; }, ItemCode)
});
// Snippet from ColumnModel of DataGrid
header: 'Code',
dataIndex: 'existingCode',
width: 70,
editor: new Ext.form.ComboBox({
mode: 'local',
displayField: 'item_code',
valueField: 'item_id',
store: ItemCodesStore
})
This is straightforward code. The column represents the existingCode value in the DataGrid’s store, and when the user clicks on an individual cell, a ComboBox is rendered with possible values stored in ItemCodesStore.
My problem is that I want the item_code value displayed at all times. By default, when a user selects an item from the ComboBox, the item_id value will be displayed, because even though I have set displayField:’item_code’ in the ComboBox, the DataGrid has no knowledge of this, and always shows the valueField.
What I had to do was write a custom renderer for that column that does a search in the ItemCodes store for a matching item_id and return the item_code to be rendered instead.
function CodeRenderer(val){
var matching = ItemCodesStore.queryBy(
function(rec,id){
return rec.item_id == val;
});
return (matching.items[0]) ? matching.items[0].data.item_code : '';
};
// Snippet from ColumnModel of DataGrid
header: 'Code',
dataIndex: 'existingCode',
width: 70,
renderer: CodeRenderer,
editor: new Ext.form.ComboBox({
mode: 'local',
displayField: 'item_code',
valueField: 'item_id',
store: ItemCodesStore
})