PDA

View Full Version : FieldContainer.removeAll cannot destory its children items



abbish
22 Apr 2013, 1:14 AM
I have some fieldcontainer in formpanel like the following pseudocode




form {
xtype: formpanel,
items: [
account_1 {
xtype: fieldcontainer,
items:[
username {
xtype: textfield
},
password {
xtype: passwordfield
},
country {
xtype: combobox
}
]
},
account_2 {
xtype: fieldcontainer,
items:[
username {
xtype: textfield
},
password {
xtype: passwordfield
},
country {
xtype: combobox
}
]
},
account_3 {
xtype: fieldcontainer,
items:[
username {
xtype: textfield
},
password {
xtype: passwordfield
},
country {
xtype: combobox
}
]
}
]
}



My program allow user to add or remove the account fieldcontainer to add more accounts for one submit, but i found a problem that the account's data also be submited when i remove the account fieldcontainer with its removeAll(true) method, i only need to each its items and destory them one by one, is this a bug ?

thanks all

abbish
22 Apr 2013, 6:15 PM
RT

slemmon
23 Apr 2013, 5:31 PM
I'm not seeing that issue in 4.2. Are you holding on to a reference to the field items somewhere else? Older version of ExtJS?



var panel = Ext.create('Ext.form.Panel', {
title: 'FieldContainer Example',
width: 550,
bodyPadding: 10,


items: [{
xtype: 'fieldcontainer',
fieldLabel: 'Last Three Jobs',
labelWidth: 100,


// The body area will contain three text fields, arranged
// horizontally, separated by draggable splitters.
layout: 'hbox',
items: [{
xtype: 'textfield',
flex: 1
}, {
xtype: 'splitter'
}, {
xtype: 'textfield',
flex: 1
}, {
xtype: 'splitter'
}, {
xtype: 'textfield',
flex: 1
}]
}],
renderTo: Ext.getBody(),
tbar: [{
text: 'Remove All'
, handler: function (btn) {
panel.down('fieldcontainer').removeAll(true);
}
}, {
text: 'Check All'
, handler: function (btn) {
console.log(panel.down('fieldcontainer').items.getCount());
}
}]
});

abbish
23 Apr 2013, 5:40 PM
I'm not seeing that issue in 4.2. Are you holding on to a reference to the field items somewhere else? Older version of ExtJS?



var panel = Ext.create('Ext.form.Panel', {
title: 'FieldContainer Example',
width: 550,
bodyPadding: 10,


items: [{
xtype: 'fieldcontainer',
fieldLabel: 'Last Three Jobs',
labelWidth: 100,


// The body area will contain three text fields, arranged
// horizontally, separated by draggable splitters.
layout: 'hbox',
items: [{
xtype: 'textfield',
flex: 1
}, {
xtype: 'splitter'
}, {
xtype: 'textfield',
flex: 1
}, {
xtype: 'splitter'
}, {
xtype: 'textfield',
flex: 1
}]
}],
renderTo: Ext.getBody(),
tbar: [{
text: 'Remove All'
, handler: function (btn) {
panel.down('fieldcontainer').removeAll(true);
}
}, {
text: 'Check All'
, handler: function (btn) {
console.log(panel.down('fieldcontainer').items.getCount());
}
}]
});


Thanks your reply first
I used Ext version also 4.2, you can enter some data before submit the form then go to check the POST data content, then removeAll and submit again, the POST data is still has data who has been removed

abbish
23 Apr 2013, 5:55 PM
Ext.define('Platform.ux.form.AddableFieldContainer', { extend: 'Ext.panel.Panel',


xtype: 'addablefieldcontainer',


requires: ['Ext.form.FieldContainer'],


componentIdPrefix: 'addable-fieldcontainer-',


fields: [],
data: [],
addButtonText: 'Add',
deleteButtonText: 'Delete',
displayHeader: true,


defaultFieldContainerNum: 3,


fieldContainerConfig: {},


fieldContainerCount: 0,
fieldContainerIndex: 0,


/*
beforeCreateFieldContainer: function(container, index, panel){},
afterCreateFieldContainer: function(container, index, panel){},
beforeDeleteFieldContainer: function(container, index, panel){},
afterDeleteFieldContainer: function(container, index, panel){},
*/


beforeCreateFieldContainer: null,
afterCreateFieldContainer: null,
beforeDeleteFieldContainer: null,
afterDeleteFieldContainer:null,


initComponent : function(){


var me = this;


Ext.applyIf(me, {
border: 0,
layout: {
type: 'vbox',
align: 'left'
},
bodyStyle: 'background: #fff;',
bodyPadding: '10',
margin: '5 0 5 0',
minHeight: '100%',
minWidth: '100%',
autoScroll: true,
id: me.componentIdPrefix+'panel'
});


me.tbar = [
{
text: me.addButtonText,
iconCls: 'icon-add-16',
handler: me.addFieldContainer
},
{
text: me.deleteButtonText,
iconCls: 'icon-delete-16',
handler: me.removeFieldContainer
}
];


this.callParent(arguments);


if(me.data.length <= 0)
{
me.createDefaultFieldContainer();


}
else
{
Ext.each(me.data, function(data, index) {
me.add(me.createFieldContainer(data));
});
}


},


createDefaultFieldContainer: function(){
for(var i = 0; i < this.defaultFieldContainerNum; i++)
{
this.add(this.createFieldContainer());
}
},


createFieldContainer: function(data){


var me = this;


var fields = {
header: [],
items: []
};


Ext.each(me.fields, function(field, index){


fields.items[index] = Ext.clone(field.items);


fields.items[index].name = field.name+'['+me.fieldContainerIndex+']';
fields.items[index].id = me.componentIdPrefix+field.id+'-'+me.fieldContainerIndex;


if(typeof(fields.items[index].multiSelect) != 'undefined' && fields.items[index].multiSelect)
{
fields.items[index].name += '[]';
}


if(Ext.isEmpty(fields.header[index]))
{
fields.header[index] = {};
}


if(typeof(field.label) != 'undefined')
{
fields.header[index].label = field.label;
}
else
{
fields.header[index].label = '';
}


if(typeof(field.items.width) != 'undefined')
{
fields.header[index].width = field.items.width;
}
else
{
fields.header[index].width = '';
}


if(typeof(field.items.flex) != 'undefined')
{
fields.header[index].flex = field.items.flex;
}
else
{
fields.header[index].flex = '';
}
});


if(me.displayHeader == true && me.fieldContainerCount == 0 && !Ext.getCmp(me.componentIdPrefix+'header'))
{
var header = Ext.create('Ext.form.FieldContainer', {
id: me.componentIdPrefix+'header',
layout: {
type: 'hbox',
align: 'stretch'
},
defaults: {
padding: '0 5 0 0',
},
items:[
{
xtype: 'label',
width: 35,
text: ''
}
]
});


Ext.each(fields.header, function(obj, index){


header.add({
xtype: 'label',
text: obj.label,
width: obj.width,
flex: obj.flex,
});
});


me.add(header);
}


var containerConfig = {};


if(typeof(me.beforeCreateFieldContainer) == 'function')
{
me.beforeCreateFieldContainer(containerConfig, me.fieldContainerIndex, me);
}


var container = Ext.create('Ext.form.FieldContainer', {
id: me.componentIdPrefix+'field-'+me.fieldContainerIndex,
layout: {
type: 'hbox',
align: 'stretch'
},
defaults: {
padding: '0 5 0 0',
},
items:[
{
name: me.componentIdPrefix+'delete-'+me.fieldContainerIndex,
fieldContainerDeletebox: true,
containerIndex: me.fieldContainerIndex,
xtype: 'checkbox',
width: 30,
}
]
});


Ext.applyIf(container, me.fieldContainerConfig);
Ext.applyIf(container, me.containerConfig);


Ext.each(fields.items, function(item, index){


item.containerIndex = me.fieldContainerIndex;
item.cls = 'input-field-component';


if(!Ext.isEmpty(data) && typeof(item.setDefaultValue) == 'function')
{
item.setDefaultValue(data, me);
}


container.add(item);


});


me.add(container);


me.fieldContainerCount ++;
me.fieldContainerIndex ++;
},


addFieldContainer: function(btn, eOpt){


var panel = btn.findParentByType('panel');


panel.createFieldContainer();
},


removeFieldContainer: function(btn, eOpt){


var panel = btn.findParentByType('panel');


var rs = Ext.ComponentQuery.query('checkbox', panel);


Ext.each(rs, function(checkbox, index){


if(typeof(checkbox.fieldContainerDeletebox) == 'boolean')
{
if(checkbox.getValue())
{
var cmp = panel.getComponent(panel.componentIdPrefix+'field-'+checkbox.containerIndex);
var rs = cmp.query('*[cls=input-field-component]');


Ext.Array.each(rs, function(item, index){
item.destroy();
});


cmp.destroy();


panel.fieldContainerCount --;
}
}


});


if(panel.fieldContainerCount <= 0)
{
panel.createDefaultFieldContainer();
}
}
});

This is my component to allow user to add or remove field container line dynamic
Key point see the removeFieldContainer method, it should be use removeAll to destroy all items in the fieldcontainer, but it cannot destroy actually, the data also will be post to backend.

slemmon
24 Apr 2013, 8:41 AM
See if this simple example demonstrates the issue. It seems to be working ok for me. One possible difference is I'm not destroying() components, but rather using removeAll(true):



Ext.create('Ext.form.Panel', {
title: 'Simple Form',
bodyPadding: 5,
width: 350,


// The form will submit an AJAX request to this URL when submitted
url: 'save-form.php',


// Fields will be arranged vertically, stretched to full width
layout: 'anchor',
defaults: {
anchor: '100%'
},


// The fields
items: [{
xtype: 'fieldcontainer',
layout: 'anchor',
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank: false
},{
fieldLabel: 'Last Name',
name: 'last',
allowBlank: false
}]
}],


tbar: [{
text: 'Remove All from fieldcontainer'
, handler: function (btn) {
btn.up('form').down('fieldcontainer').removeAll(true);
}
}],


// Reset and Submit buttons
buttons: [{
text: 'Reset',
handler: function() {
this.up('form').getForm().reset();
}
}, {
text: 'Submit',
formBind: true, //only enabled once the form is valid
disabled: true,
handler: function() {
var form = this.up('form').getForm();
if (form.isValid()) {
form.submit({
success: function(form, action) {
Ext.Msg.alert('Success', action.result.msg);
},
failure: function(form, action) {
Ext.Msg.alert('Failed', action.result.msg);
}
});
}
}
}],
renderTo: Ext.getBody()
});

Qtx
12 Jul 2013, 6:30 AM
I have the same issue with field container in 4.2. The field container seems not to propagate any actions to its fields - neither disabling nor destroying.

I have a dynamic search mask, where the fields can be dynamically added or removed. Some search criteria are added in a fieldcontainer, e.g. begin date, end date. By removing the criteria, it is still in the request.

This fix helps:


listeners: {
beforedestroy: function(cont, opts) {
// This is very important!
// When using the field container, it does not propagate
// any actions to the fields - neither disabling nore
// distroying.
cont.removeAll(true);
}
}



But, I would say, that this behavior should be per default. If a fieldcontainer is destroyed, then its elements should be also destroyed and unregistered from the Basic (Form).

slemmon
12 Jul 2013, 12:53 PM
Looks like this issue has been fixed in 4.2.1.



Ext.widget('form', {
renderTo: document.body,
height: 300,
width: 300,
url: 'dummy.url',
items: [{
xtype: 'fieldcontainer',
layout: 'hbox',
items: [{
xtype: 'textfield',
name: 'firstTextfield'
}, {
xtype: 'textfield',
name: 'secondTextfield'
}]
}],
tbar: [{
text: 'Destroy Fieldcontainer',
handler: function (btn) {
var form = btn.up('form');


form.remove(form.down('fieldcontainer'));
}
}],
bbar: [{
text: 'Submit',
handler: function (btn) {
btn.up('form').getForm().submit();
}
}]
});