ExtJ を使用してデータ サービスを利用するための簡単なプロトタイプを構築しようとしています (同時に ExtJ を学習するためでもあります)。
(ExtJS の基本的な知識を持って) プロトタイプを開発しているときに、いくつかの問題に遭遇しました。質問を投稿する前に、以下をざっと見ていただきたいと思います。
以下は、サービスと対話するメイン クラスです。特定の UI コンポーネントが ajax 通信中にマスク/マスク解除されることを確認したかったのです。
Ext.define('Sample.provider.SvcClient', {
TestConnectivity: function(prms){
debugger;
Ext.Ajax.on('beforerequest', function(conn,o,result) {
prms.BeforeRequest(conn,o,result);
});
Ext.Ajax.on('requestcomplete',function(conn,o,result) {
prms.RequestComplete(conn,o,result);
});
Ext.Ajax.on('requestexception',function(conn,o,result) {
prms.RequestException(conn,o,result);
});
Ext.Ajax.request({
url: prms.Url,
method: prms.HttpMethod,
headers: {
'Authorization' : 'Basic ' + prms.Credentials
},
success: prms.Success,
failure: prms.Failure,
callback: prms.Callback
});
}
});
特に ajax 通信中のコントロールのマスキングを支援するために、SvcClient の拡張機能を開発しました。
Ext.define('Sample.util.ClientProxy', {
CtlToMask : null,
DoTestConnection: function(ctlToMask, callback, url, userName, pwd) {
debugger;
var proxy = this;
proxy.CtlToMask = ctlToMask;
var client = new Sample.provider.SvcClient();
var params = {
Url: url,
HttpMethod: "GET",
Credentials: Sample.util.Conversions.Base64.encode(userName + ":" + pwd),
CtlToMask: proxy.CtlToMask,
Scope:proxy,
BeforeRequest: function(conn,o,result,Scope) {
debugger;
if(Scope.CtlToMask !=null) {
if(Scope.CtlToMask.getEl() != undefined)
Scope.CtlToMask.getEl().mask('Testing Connectivity...', 'x-mask-loading');
else
Scope.CtlToMask.mask('Testing Connectivity...', 'x-mask-loading');
}
},
RequestComplete: function(conn,o,result) {
if(this.CtlToMask !=null) {
if(this.CtlToMask.getEl() != undefined)
this.CtlToMask.getEl().unmask(true);
else
this.CtlToMask.unmask(true);
}
},
RequestException: function(conn,o,result) {
if(this.CtlToMask !=null) {
if(this.CtlToMask.getEl() != undefined)
this.CtlToMask.getEl().unmask(true);
else
this.CtlToMask.unmask(true);
}
}
};
client.TestConnectivity(params);
}
});
以下に示すようなコントローラーがあります。
Ext.define('Sample.controller.Locations', {
extend: 'Ext.app.Controller',
models: ['Location', 'Country'],
views: [
'portal.location.Menu',
'portal.location.Edit'
],
init: function() {
this.control({
'locationsMenu':{
OpenAddNewSvcPopup: this.OnOpenAddNewSvcPopup
},
'locationsEdit':{
TestSvcConnectivity: this.OnTestSvcConnectivity,
render: function () { },
afterrender: function () { },
boxready: function () { }
}
});
},
OnOpenAddNewSvcPopup: function(){
var newLoc = Ext.create('Sample.model.Location', {
UserName: 'admin',
Uri: 'http://localhost/DataServicesBase/Data.svc'
});
var v = Ext.create('widget.locationsEdit',{ mode:'add'});
v.down('form').loadRecord(newLoc);
},
OnTestSvcConnectivity: function(ctl){
var proxy = new Sample.util.ClientProxy();
proxy.DoTestConnection(
ctl,
this.OnTestSvcConnectivityCallback,
ctl.down("#Uri").value + '/Countries',
ctl.down("#UserName").value,
ctl.down("#Password").value
);
},
OnTestSvcConnectivityCallback: function(options,success,result){
if(success) {
//show the result
}
else {
//Show error in window
}
}
});
ビューは次のようになります。
Ext.define('Sample.view.portal.location.Edit', {
extend: 'Ext.window.Window',
alias: 'widget.locationsEdit',
//title: 'Edit Service Location',
layout: 'fit',
autoShow: true,
title: 'Edit Service Location',
bodyStyle: 'border:0px',
closeAction:'destroy',
config:{
mode: 'edit'
},
constructor: function(configs){
this.callParent(arguments);
this.initConfig(configs);
if(this.mode == "add") this.setTitle('Add New Service Location');
},
initComponent: function() {
this.items = [
{
xtype: 'form',
items: [
{
xtype: 'textfield',
name: 'Id',
itemId: 'Id',
fieldLabel: 'Unique Name',
labelStyle: 'font-weight:bold',
allowBlank: false,
maxLength: 64,
width: 300
},
{
xtype: 'textfield',
name : 'Uri',
itemId: 'Uri',
fieldLabel: 'URI',
maxLength: 300,
width: 500,
allowBlank: false
},
{
xtype: 'textfield',
name : 'UserName',
itemId: 'UserName',
fieldLabel: 'User Name',
allowBlank: false,
maxLength: 64,
width: 200
},
{
xtype: 'textfield',
name : 'Password',
itemId: 'Password',
fieldLabel: 'Password',
allowBlank: false,
maxLength: 64,
width: 200
}
],
bodyStyle: 'padding:5px;'
}
];
this.buttons = [
{
text: 'Test Connectivity',
action: 'test',
scope: this,
handler: this.OnTestSvcConnectivity
},
{
text: 'Save',
action: 'save'
},
{
text: 'Cancel',
scope: this,
handler: this.close
}
];
this.callParent();
this.addEvents('TestSvcConnectivity') //custom event
},
OnTestSvcConnectivity: function(){
this.fireEvent('TestSvcConnectivity', this); //will be raised to controller
}
});
Q1
(ポップアップから) [接続のテスト] ボタンをクリックすると、このアプローチは初めて正常に機能します。同じボタンを 2 回クリックすると、(BeforeRequest) ハンドラーが 2 回起動します。3 回目のクリックで、ハンドラーが 3 回起動されます。私のコードの間違いは何ですか。
Q2
ポップアップをキャンセルしてもう一度「接続のテスト」をクリックすると、機能しません。ハンドラーは、以前のポップアップ インスタンスの「何らかの」種類の参照 (または状態) を引き続き維持します。見つからなかったため、オブジェクト メンバーに対して「未定義」をスローします。これをデバッガーで確認したところ、現在のポップアップ インスタンスではなく、前のポップアップ インスタンスの ID が表示されました。ハンドラーは常に、インスタンス化された最初のポップアップを尊重しようとします。
Q3
このサンプル プロトタイプで従おうとしているパターンには、落とし穴や問題がありますか。ExtJS の MVC 機能を使用して開発を試みており、上記のような非常に基本的な問題に直面しないように、スタンドと適切なパターン/プラクティスを使用していることを確認しています。