The glue that links the three user views together is the UserController
. It is here that we place all logic for managing user maintenance. You have seen that each view defined earlier is dumb in that there is only presentation logic defined. Actions, validations, and selections are all handled within the UserController
and are explained in the following code:
Ext.define('TTT.controller.UserController', { extend: 'Ext.app.Controller', views: ['user.ManageUsers'], refs: [{ ref: 'userList', selector: 'manageusers userlist' }, { ref: 'userForm', selector: 'manageusers userform' }, { ref: 'addUserButton', selector: 'manageusers #addUserBtn' }, { ref: 'saveUserButton', selector: 'manageusers userform #saveBtn' }, { ref: 'deleteUserButton', selector: 'manageusers userform #deleteBtn' }, { ref: 'userFormFieldset', selector: 'manageusers userform fieldset' }, { ref: 'usernameField', selector: 'manageusers userform textfield[name=username]' }], init: function(application) { this.control({ 'manageusers #addUserBtn': { click: this.doAddUser }, 'userlist': { itemclick: this.doSelectUser, viewready: this.doInitStore }, 'manageusers userform #saveBtn': { click: this.doSaveUser }, 'manageusers userform #deleteBtn': { click: this.doDeleteUser }, 'manageusers userform': { afterrender: this.doAddUser }, 'userlist header tool[type="refresh"]': { click: this.doRefreshUserList } }); }, doInitStore: function() { this.getUserList().getStore().load(); }, doAddUser: function() { var me = this; me.getUserFormFieldset().setTitle('Add New User'), me.getUsernameField().enable(); var newUserRec = Ext.create('TTT.model.User', { adminRole: 'N' }); me.getUserForm().loadRecord(newUserRec); me.getDeleteUserButton().disable(); }, doSelectUser: function(grid, record) { var me = this; me.getUserForm().loadRecord(record); me.getUserFormFieldset().setTitle('Edit User ' + record.get('username')); me.getUsernameField().disable(); me.getDeleteUserButton().enable(); }, doSaveUser: function() { var me = this; var rec = me.getUserForm().getRecord(); if (rec !== null) { me.getUserForm().updateRecord(); var errs = rec.validate(); if (errs.isValid()) { rec.save({ success: function(record, operation) { if (typeof record.store === 'undefined') { // the record is not yet in a store me.getUserList().getStore().add(record); } me.getUserFormFieldset().setTitle('Edit User ' + record.get('username')); me.getUsernameField().disable(); me.getDeleteUserButton().enable(); }, failure: function(rec, operation) { Ext.Msg.alert('Save Failure', operation.request.scope.reader.jsonData.msg); } }); } else { me.getUserForm().getForm().markInvalid(errs); Ext.Msg.alert('Invalid Fields', 'Please fix the invalid entries!'), } } }, doDeleteUser: function() { var me = this; var rec = me.getUserForm().getRecord(); Ext.Msg.confirm('Confirm Delete User', 'Are you sure you want to delete user ' + rec.get('fullName') + '?', function(btn) { if (btn === 'yes') { rec.destroy({ failure: function(rec, operation) { Ext.Msg.alert('Delete Failure', operation.request.scope.reader.jsonData.msg); } }); me.doAddUser(); } }); }, doRefreshUserList: function() { this.getUserList().getStore().load(); } });
The UserController
is defined with a single view to manage users as shown in the following code:
views: [ 'user.ManageUsers' ]
This allows us to define a set of references using the component query language starting with the manageusers
root selector. We can hence reference the save button on the UserForm
by the selector:
'manageusers userform #saveBtn'
The #saveBtn
refers to the component with itemId saveBtn
on the userform
within the manageusers
component.
The init
function defines the listeners that should be processed in the interface. Each button click is matched to an appropriate handler
function. The user list itemclick
event is handled by the doSelectUser
function. The viewready
event on the userlist
triggers the initial load of the grid's store. Each listener event is handled by a single function with a clear purpose. Let's now examine the core functions in detail.
The doAddUser
function is called when the Add User button is clicked. We set the title on the form fieldset
to display Add New User and then enable the username
field as shown in the following code:
me.getUserFormFieldset().setTitle('Add New User'), me.getUsernameField().enable();
We only enable the username
field when adding a new user; the username
field is not editable for existing users as it represents the primary key. We then create a new User model and load the record into the user form:
var newUserRec = Ext.create('TTT.model.User', { adminRole: 'N' }); me.getUserForm().loadRecord(newUserRec);
At this stage the user form would look like the following screenshot:
The Delete button serves no useful purpose for adding a new user and hence we disable it as shown in the following code:
me.getDeleteUserButton().disable();
This gives us the following Add New User interface as shown in the following screenshot:
We could just as easily have hidden the delete button instead of disabling it; your approach will depend on your client specifications.
The doSelectUser
function handles the itemclick
event on the userlist
grid panel. The arguments to this function are the grid itself and the selected record. This makes loading the form with the selected user record a simple task:
var me = this; me.getUserForm().loadRecord(record); me.getUserFormFieldset().setTitle('Edit User ' + record.data.username); me.getUsernameField().disable(); me.getDeleteUserButton().enable();
The fieldset
title is changed to reflect the user being edited and the username
field is disabled. We also ensure the Delete button is enabled as we require the option to delete an existing record. Clicking on the Betty Jones record in the user list would then display the following screenshot:
Readers will note that the Password field is empty. This means that saving a user record via the form will require a password to be set. The backend handler method and service layer also require a valid password when saving a user. In the real world this would not be the case; you do not want an administrator changing the password every time they save user details! A Change Password form, perhaps in a pop-up window, would normally trigger a separate AJAX request to change the user's password.
The doSaveUser
function processes the saving of a user record. In most applications the save
function will contain the most code as validations and user feedback are important steps in the process.
The first step is to retrieve the user record instance that was loaded in the form as shown in the following code:
var rec = me.getUserForm().getRecord();
If valid, the record is updated with the values entered in the form text fields as shown in the following code:
me.getUserForm().updateRecord();
At this stage the user record will be in sync with the fields entered in the form. This means all fields in the form will have been copied to the model instance. We can now validate the user record as given in the following code:
var errs = rec.validate();
If there are no validation errors, the record is saved using the save()
function on the record itself. There are two possible callbacks depending on the returned JSON response. A successful save will trigger the success handler as shown in the following code:
success: function(record, operation) { if (typeof record.store === 'undefined') { // the record is not yet in a store me.getUserList().getStore().add(record); // select the user in the grid me.getUserList().getSelectionModel().select(record,true); } me.getUserFormFieldset().setTitle('Edit User ' + record.data.username); me.getUsernameField().disable(); me.getDeleteUserButton().enable(); }
The success
callback will check if the record exists in the store. If not, the record is added to the User
store and selected in the user list. The Delete button will then be enabled and the fieldset
title set appropriately.
The failure
action will simply inform the user of the cause as shown in the following code:
failure: function(rec, operation) { Ext.Msg.alert('Save Failure', operation.request.scope.reader.jsonData.msg); }
If there are errors encountered during validation, we mark the invalid fields and display a generic error message as shown in the following code:
me.getUserForm().getForm().markInvalid(errs); Ext.Msg.alert('Invalid Fields', 'Please fix the invalid entries!'),
Trying to save a user record without a valid e-mail or password would then display a message as follows:
The final handler processes the delete action. The doDeleteUser
function prompts the user for confirmation before triggering the destroy
function on the record if required:
Ext.Msg.confirm('Confirm Delete User', 'Are you sure you want to delete user ' + rec.data.fullName + '?', function(btn) { if (btn === 'yes') { rec.destroy({ failure: function(rec, operation) { Ext.Msg.alert('Delete Failure', operation.request.scope.reader.jsonData.msg); } }); me.doAddUser(); } });
The User
store will automatically remove the successfully destroyed user model from the store itself. Any failure will inform the user of the reason. Attempting to delete the record for John Smith will result in the message shown in the following code:
Where is this message coming from? It is generated in the service layer UserServiceImpl.remove
method that was coded when implementing the business logic for the delete action. What about trying to delete the currently logged-on user? This will result in the following message:
Once again this is coming from the service layer business logic.
3.139.70.101