Boolean Campos quebrado em Ext ou Ext_scaffold?
-
13-09-2019 - |
Pergunta
Eu estou experimentando com o uso ext_scaffold para gerar elementos de UI para uma aplicação web Rails-backed.
No entanto, estou tendo problemas com o comportamento dos campos boolean. Por exemplo, quando eu faço
./script/generate ext_scaffold product name:string description:text sku:integer available:boolean
Ele constrói a migração corretamente e gera uma interface de usuário com uma caixa de seleção para o campo booleano.
Se assinalar esta opção, no entanto, apenas modifica o objeto se ele está sendo criado. Se o registro já existe, o estado da caixa de seleção reflete com precisão o campo. No entanto, a edição está falhando -. Ou seja, marcando ou desmarcando-lo e salvar o registro não mudá-lo
Mergulhando no código, encontramos:
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' }
],
Eu sinto o problema é que tanto Rails ou Ext está confuso com os elementos com nomes idênticos. De qualquer maneira, depois de um registro foi criado, clicando na caixa de seleção não faz nada (marcada ou desmarcada, os '0'. Restos de campo)
Depois de brincar um pouco com isso, acaba por se colocar nesse campo escondido ACIMA a caixa de seleção, não importa o que o campo agora fica definido para true após a edição. Não comportamento exatamente desejado tanto.
Tem mais alguém experimentou este problema? Há soluções alternativas? Obrigado.
UPDATE:
Note que, mesmo com a caixa de seleção para o campo marcado, o pedido enviado POST indica o campo é definido como falso. Todos os outros tipos de campo estão sendo atualizado de forma adequada ...
UPDATE2:
Tudo bem, encontrei um grande post descrevendo a solução da Semergence para este problema , mas eu ainda não sou muito capaz de chegar a este trabalho ... Eu adaptei a sua solução da seguinte forma:
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);
},
Agora o alerta é jogado corretamente, indicando o campo correto e afirmando que será definido como zero.
Exceto isso não ocorre para baixo na solicitação post que na verdade é enviado -. Na verdade, se a caixa de seleção estiver desmarcada, ele não tem um valor no POST em tudo
Alguém pode me ajudar a entender o que está acontecendo aqui?
Solução
OK, acontece que este é um bug conhecido com o quadro Ext. Andar até os fóruns ExtJS Se você está tendo o mesmo problema, várias soluções descritas lá. O mais simples de implementar é apenas para estender a classe caixa:
# 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
Você também vai precisar de algum css para as novas caixas de seleção:
.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;
}
Finalmente, você pode querer correção ext-andaime para gerar esses novos xcheckboxes para booleans e também para não gerar o campo escondido. Eu modifiquei ext_scaffold_panel.js da seguinte forma:
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")
%>
],
Espero que isso ajude ninguém lutando com isso!