Ext JS 4 – Plugin to Add Icons to a Panel Header
Recently in my app I had multiple grid panels that needed icons added to the header, where the title goes. Instead of duplicating the code in multiple places, I created a simple plugin that I could use on any panel anywhere in my application.
Here is the code of the plugin. It’s really simple, but helps keep my grid/panel code cleaner.
And example usage of a grid config with the plugin:
{
xtype: 'grid',
title: 'My Grid Title',
columns : [
],
plugins: [{
ptype: "headericons",
headerButtons : [
{
xtype: 'button',
iconCls: 'icon-page-white-excel',
scope: this,
handler: this.onExportToExcel
}
]
}]
}
And here is a screenshot, that shows two different panel headers that I have. One with one icon and one with two.
![]()
Version Info: Ext JS 4.1
Ext JS 4: “Link” from One Tab to Another
I have a pretty typical Ext JS app. Tab panels and within each tab border layouts with multiple grids. One thing the app does is manage users and one tab shows user details. Anywhere else in the app that shows a user name, I want to link that user name to the user detail (not in a dialog, but actually switch to the user detail tab). Typically, the user names are listed in grids. Here is what I did to hook up the “links” to the tab.
I started out using an <a> tag, but settled on a <button> tag to avoid the hash being added to the url and messing up my history.
Here is the renderer function for when the links are in a grid. It’s pretty straightforward, just renders the cell with button tag.
userNameLink : function(val) {
return Ext.String.format('<button type="button" class="userNameLink">{0}</button>', val);
}
Now style the link. My css skills leave a lot to be desired. I found this very helpful post which I used for the styling: Styling button elements to look like links
button.userNameLink {
overflow:visible;
margin:0;
padding:0;
border:0;
color: #2B547D;
background:transparent;
font:inherit;
line-height:normal;
text-decoration:underline;
cursor:pointer;
-moz-user-select:text;
}
button.userNameLink::-moz-focus-inner {
padding:0;
border:0;
}
Finally, now to do something with those “links”. Right now they look good, but they aren’t doing anything!
Ext.getBody().on('click', this.handleUserNameLink,
this, {
delegate: 'button.userNameLink'
});
The “handleUserNameLink” function does the heavy lifting of actually switching tabs and defaulting data, but this nifty code adds the handler to every single one of my links w/o me having to add it myself everywhere.
Helpful links:
Version info: Ext JS 4.0.7
Tested on IE6, IE8, Firefox 11, Chrome 18
Create a SQLite database during an ant build
I have a SQLite database that is used by my application. It is not the main database but provides some supporting data for the application. Every time I deploy my application to my local tomcat installation using ant, I want to recreate this database, using a sql script. I do this by executing a sqlite .read command as one step in my build.
- Install sqlite and ensure it is in your path.
- Update my Eclipse Ant installation to include the Ant Contrib jars.
- I unpacked the jars to my eclipse/plugins/org.apache.ant.XXX/lib directory.
- In Eclipse->Window->Preferences->Ant, go to the Runtime section and add the ant-contrib.jar to the classpath.
- Within my ant build file I did the following:
<project name="myproject" basedir="." default="clean-deploy">
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<property file="build.properties"/>
<property environment="env"/>
<!-- assumes you have sqlite3 installed on the local machine and in the path -->
<target name="createsqlitedb" description="build sqlite db">
<propertyregex property="loc" input="${env.CATALINA_HOME}" regexp="\\" replace="\\\\\\\\\\\\\\\\" />
<property name="myapp.web.dir" value="${loc}/webapps/${property.projectname}"/>
<property name="tomcat.conf.dir" value="${loc}/conf"/>
<echo message="src file for sqlitedb: ${myapp.web.dir}${property.sqlitedb.src}"/>
<echo message="dest db for sqlitedb: ${tomcat.conf.dir}${property.sqlitedb.dest}" />
<exec executable = "sqlite3">
<arg value="${tomcat.conf.dir}${property.sqlitedb.dest}" />
<arg value=".read ${myapp.web.dir}${property.sqlitedb.src}"/>
</exec>
</target>
</project>
The build.properties file has the properties in it such as property.sqlitedb.src and property.sqlitedb.dest. The file itself has standard sqlite sql statements in it.
Helpful links:
- Executing the sqlite task in ant: http://www.mentby.com/kyle-kimberley/using-sqlitejdbc-v056-with-ant-build-file.html
- SQLite: http://www.sqlite.org/
- Ant-Contrib: http://ant-contrib.sourceforge.net/
- Adding ant-contrib to Eclipse: http://stackoverflow.com/questions/4011749/ant-problems-net-sf-antcontrib-antcontrib-properties
- Regex stuff for getting the file paths working: http://stackoverflow.com/questions/8077565/trouble-using-replaceregexp-when-replacing-string-dir-location
Spring 3 @Autowired Unit Tests with Mockito
I’ve been wanting to enhance the unit tests I have in my application for awhile. I’m using Spring 3 testing facilities, but most of my tests are “integration” tests. I finally carved out a bit of time to enable better unit tests in my application. This is an example of a unit test of a simple service class using Spring 3 annotations. I am using Mockito to mock the dependencies.
First my service class. Like I said, simple. Just two methods and straightforward logic.
package my.app.service;
import java.util.List;
import my.app.dao.SupervisorDAO;
import my.app.model.Supervisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class SupervisorService {
@Autowired private SupervisorDAO supervisorDao;
@Transactional(readOnly=true)
public List getSupervisors() {
return supervisorDao.getSupervisors();
}
/**
* Determine if the supervisor is responsible for any users for the
* specified department
* @param dbId The dbId of the supervisor
* @param department The department to look for
* @return true if there are users assigned to the superivsor for the department
*/
public boolean isSupervisorResponsibleForUser(int dbId, String department) {
if (dbId == 0) {
throw new IllegalArgumentException("A dbId is required");
}
if (department == null) {
throw new IllegalArgumentException("department is required");
}
boolean hasUsers = false;
int numAssignedUsers = supervisorDao.getUserCountForSupervisor(dbId, department);
if (numAssignedUsers > 0) {
hasUsers = true;
}
return hasUsers;
}
}
The unit test. I need to mock the dao object to create a repeatable unit test of the service class. Here’s the code:
package my.app.service;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import my.app.dao.SupervisorDAO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class SupervisorServiceUnitTest {
@Mock private SupervisorDAO mockSupervisorDao;
@InjectMocks private SupervisorService supervisorService;
@Before
public void init() {
when(mockSupervisorDao.getUserCountForSupervisor(1, "Department1"))
.thenReturn(2);
when(mockSupervisorDao.getUserCountForSupervisor(1, "Department2"))
.thenReturn(0);
}
@Test
public void testIsSupervisorResponsibleForUserTrue() {
boolean isSupervisor = supervisorService.isSupervisorResponsibleForUser(1, "Department1");
assertTrue(isSupervisor);
}
@Test
public void testIsSupervisorResponsibleForUserFalse() {
boolean isSupervisor = supervisorService.isSupervisorResponsibleForUser(1, "Department2");
assertFalse(isSupervisor);
}
@Test(expected=IllegalArgumentException.class)
public void testIsSupervisorResponsibleRequiredDbId() {
supervisorService.isSupervisorResponsibleForUser(0, "Department3");
}
@Test(expected=IllegalArgumentException.class)
public void testIsSupervisorResponsibleRequiredDivision() {
supervisorService.isSupervisorResponsibleForUser(1, null);
}
}
The key things that I learned along the way:
- Use @RunWith(MockitoJUnitRunner.class) to run this test
- Use the @Mock annotation for the classes that need to be mocked within the class you are testing. Use the @InjectMocks annotation on the class you are testing. The @Mock classes are injected into the @InjectMocks class. I guess this should have been obvious, but it wasn’t to me.
It’s a simple class and a simple unit test, but it’s a start. It gets me over the hump of having the correct jars and knowing how to get a test up and running. I am new to the behavior driven style of Mockito, but this works well for me in this unit test. I think it is clean and easy to read.
Some links that were helpful to me (disclaimer, some of these are for older versions of Mockito)
- Mock Unit Testing Services and Daos with Mockito and Spring 3
- Mockito + Spring @Autowired Annotations
- Spring 3 Autowiring and JUnit Testing
- Creating Unitary Tests in Spring 3
Version Info:
- Spring 3.0.5
- Mockito 1.9.0
Ext JS 4 – Cell Editing and Blur Event
I have a grid panel using the cell editing plugin. There is also a Save button on panel top toolbar. When editing a field in the grid and then clicking the save button without tabbing out of the field being edited the blur event of the cell occurred after the Save button handler. It happened consistently in IE8.
I found this very helpful post EditorGridPanel -delay in firing Blur Event causes Bug on the Sencha forums and utilized the same solution, with a slight update for Ext 4. I called plugin.completeEdit() at the beginning of my save handler.
Plugin declaration:
var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
pluginId: 'cellplugin',
clicksToEdit: 1,
listeners : {
scope: this,
// put listeners here
}
});
At the beginning of the save button handler:
onSave : function () {
var grid = this.child('#divGrid'), plugin;
plugin = grid.getPlugin('cellplugin');
plugin.completeEdit();
// now do what is needed for save
}
Ext JS Version: 4.0.7
Ext JS 4: Poor Man’s Input Field Dynamic Help
I wanted to put a dynamic tool tip on some input fields in a form in my application. I wanted to use Ext JS Quicktip, but it wasn’t quite what I wanted, because I wanted the tip to show on focus, not mouse hover. I created a very simple one in Ext JS 4.0.7, by doing the following.
1. After render of my panel I added the following code to define the tip. It is just a basic tip
Ext.define('My.Panel', {
extend: 'Ext.panel.Panel',
// All your configs, initializations, etc.
afterRender : function () {
this.callParent(arguments);
this.fieldHelp = Ext.create('Ext.tip.Tip', {
shadow: false
});
}
});
2. For the input fields where I want the tooltip to show, I added a fieldHelp config and listeners for the focus and blur events.
{
name: 'myField',
fieldLabel: 'Name',
// Usual configs here
fieldHelp: 'Help text specific to this field',
listeners: {
scope: this,
focus: this.onFieldFocus,
blur: this.onFieldBlur
}
}
3. Last, the onFieldFocus and onFieldBlur handlers:
onFieldFocus : function (el) {
var text = el.fieldHelp,
xy;
if (typeof text !== "undefined") {
xy = el.getEl().getAnchorXY('r');
xy[0] += 5;
xy[1] -= 4;
this.fieldHelp.update(text);
this.fieldHelp.fieldId = el.id;
this.fieldHelp.showAt(xy);
}
},
onFieldBlur : function (el) {
if (this.fieldHelp.isVisible() && this.fieldHelp.fieldId === el.id) {
this.fieldHelp.hide();
}
},
And there you have it, simple, dynamic help that appears to the right of a field when the field has focus.