Ext または Ext_scaffold でブール値フィールドが壊れていますか?
-
13-09-2019 - |
質問
ext_scaffold を使用して Rails ベースの Web アプリケーションの UI 要素を生成する実験をしています。
ただし、ブール型フィールドの動作に問題が発生しています。たとえば、私がそうするとき、
./script/generate ext_scaffold product name:string description:text sku:integer available:boolean
移行が適切に構築され、ブール型フィールドのチェックボックスを備えたユーザー インターフェイスが生成されます。
ただし、このボックスをオンにすると、オブジェクトが作成されている場合にのみオブジェクトが変更されます。レコードがすでに存在する場合、チェックボックスの状態はフィールドを正確に反映します。ただし、編集は失敗します。つまり、チェックを入れたり外したりしてレコードを保存しても変更されません。
コードを詳しく調べてみると、次のことがわかります。
items: [
{ fieldLabel: scaffoldPanel.labels['product[name]'], name: 'product[name]', xtype: 'textfield' },
// ... other fields ...
{ fieldLabel: scaffoldPanel.labels['product[available]'], name: 'product[available]', xtype: 'checkbox', inputValue: '1' }, { xtype: 'hidden', name: 'product[available]', value: '0' }
],
問題は、Rails または Ext のどちらかが同じ名前の要素で混同されていることだと感じています。いずれの場合も、レコードの作成後にチェック ボックスをクリックしても何も起こりません (オンでもオフでも、フィールドは「0」のままです)。
これを少し試してみたところ、編集後にどのフィールドが true に設定されても、その非表示フィールドをチェックボックスの上に配置すると判明しました。まったく望ましい動作でもありません。
他にこの問題を経験した人はいますか?回避策はありますか?ありがとう。
アップデート:
フィールドのチェックボックスがオンになっている場合でも、送信された POST リクエストではフィールドが false に設定されていることを示すことに注意してください。他のフィールドタイプはすべて適切に更新されています...
更新2:
よし、素晴らしいものを見つけた この問題に対する Semergence の解決策を説明するブログ投稿, しかし、まだこれをうまく機能させることができません...私は彼の解決策を次のように適応させました。
onOk: function() {
// ....
if (scaffoldPanel.getFormPanel().currentMode == 'edit') {
// set up request for Rails create action
submitOptions.params._method = 'PUT';
submitOptions.url = submitOptions.url + '/' + selected.data.id;
}
// ----- checkbox serializer ------
var serializedForm = scaffoldPanel.getFormPanel().getForm();
// because unchecked checkboxes do not submit values, manually force a value of 0
serializedForm.items.each(function(f) {
//alert("Checking \"" + f.getName() "\" field...");
if (f.isFormField && f.getXType() == 'checkbox' && !f.getValue()) {
alert("Auto setting \"" + f.getName() + "\" field to 0...");
serializedForm.getValues()[f.getName()] = '0';
}
});
// ------- end serializer -------
serializedForm.submit(submitOptions);
//scaffoldPanel.getFormPanel().getForm().submit(submitOptions);
},
これで、アラートが適切にスローされ、正しいフィールドが示され、それがゼロに設定されることがアサートされます。
ただし、これは実際に送信される POST リクエストでは発生しません。実際、チェックボックスがオフの場合、POST には値がまったく含まれません。
誰かここで何が起こっているのか理解するのを手伝ってくれませんか?
解決
OK、これは Ext フレームワークの既知のバグであることがわかりました。同じ問題が発生している場合は、Extjs フォーラムにアクセスしてください。そこにはいくつかの解決策が記載されています。最も簡単な実装は、チェックボックス クラスを拡張することです。
# patch.js -- include before creating any checkboxes
Ext.ns('Ext.ux.form');
Ext.ux.form.XCheckbox = Ext.extend(Ext.form.Checkbox, {
offCls:'xcheckbox-off'
,onCls:'xcheckbox-on'
,disabledClass:'xcheckbox-disabled'
,submitOffValue:'false'
,submitOnValue:'true'
,checked:false
,onRender:function(ct) {
// call parent
Ext.ux.form.XCheckbox.superclass.onRender.apply(this, arguments);
// save tabIndex remove & re-create this.el
var tabIndex = this.el.dom.tabIndex;
var id = this.el.dom.id;
this.el.remove();
this.el = ct.createChild({tag:'input', type:'hidden', name:this.name, id:id});
// update value of hidden field
this.updateHidden();
// adjust wrap class and create link with bg image to click on
this.wrap.replaceClass('x-form-check-wrap', 'xcheckbox-wrap');
this.cbEl = this.wrap.createChild({tag:'a', href:'#', cls:this.checked ? this.onCls : this.offCls});
// reposition boxLabel if any
var boxLabel = this.wrap.down('label');
if(boxLabel) {
this.wrap.appendChild(boxLabel);
}
// support tooltip
if(this.tooltip) {
this.cbEl.set({qtip:this.tooltip});
}
// install event handlers
this.wrap.on({click:{scope:this, fn:this.onClick, delegate:'a'}});
this.wrap.on({keyup:{scope:this, fn:this.onClick, delegate:'a'}});
// restore tabIndex
this.cbEl.dom.tabIndex = tabIndex;
} // eo function onRender
,onClick:function(e) {
if(this.disabled || this.readOnly) {
return;
}
if(!e.isNavKeyPress()) {
this.setValue(!this.checked);
}
} // eo function onClick
,onDisable:function() {
this.cbEl.addClass(this.disabledClass);
this.el.dom.disabled = true;
} // eo function onDisable
,onEnable:function() {
this.cbEl.removeClass(this.disabledClass);
this.el.dom.disabled = false;
} // eo function onEnable
,setValue:function(val) {
if('string' == typeof val) {
this.checked = val === this.submitOnValue;
}
else {
this.checked = !(!val);
}
if(this.rendered && this.cbEl) {
this.updateHidden();
this.cbEl.removeClass([this.offCls, this.onCls]);
this.cbEl.addClass(this.checked ? this.onCls : this.offCls);
}
this.fireEvent('check', this, this.checked);
} // eo function setValue
,updateHidden:function() {
this.el.dom.value = this.checked ? this.submitOnValue : this.submitOffValue;
} // eo function updateHidden
,getValue:function() {
return this.checked;
} // eo function getValue
}); // eo extend
// register xtype
Ext.reg('xcheckbox', Ext.ux.form.XCheckbox);
// eo file
新しいチェックボックス用の CSS も必要になります。
.xcheckbox-wrap {
line-height: 18px;
padding-top:2px;
}
.xcheckbox-wrap a {
display:block;
width:16px;
height:16px;
float:left;
}
.x-toolbar .xcheckbox-wrap {
padding: 0 0 2px 0;
}
.xcheckbox-on {
background:transparent url(../javascripts/ext/resources/images/default/menu/checked.gif) no-repeat 0 0;
}
.xcheckbox-off {
background:transparent url(../javascripts/ext/resources/images/default/menu/unchecked.gif) no-repeat 0 0;
}
.xcheckbox-disabled {
opacity: 0.5;
-moz-opacity: 0.5;
filter: alpha(opacity=50);
cursor:default;
}
最後に、ブール値用の新しい xcheckbox を生成し、非表示フィールドを生成しないように ext-scaffold を修正することもできます。ext_scaffold_panel.js を次のように変更しました。
baseParams: scaffoldPanel.baseParams,
items: [
<%= attributes.inject([]) do |items, a|
item = " { fieldLabel: scaffoldPanel.labels['#{class_name.demodulize.underscore}[#{a.name}]']"
item << ", name: '#{class_name.demodulize.underscore}[#{a.name}]'"
item << case a.field_type
when :text_field then [:integer, :float, :decimal].include?(a.type) ? ", xtype: 'numberfield'" : ", xtype: 'textfield'"
when :text_area then ", xtype: 'textarea'"
when :date_select then ", xtype: 'xdatefield'"
when :datetime_select then ", xtype: 'xdatetime'"
when :check_box then ", xtype: 'xcheckbox', inputValue: '1' //// }, { xtype: 'hidden', name: '#{class_name.demodulize.underscore}[#{a.name}]', value: '0'"
end
item << " }"
items << item
end.join(",\n")
%>
],
これがこれで悩んでいる他の人の助けになれば幸いです!