PDA

View Full Version : Ext.ux.MetaForm - A FormPanel configured by metadata received from server



Pages : [1] 2

jsakalos
6 Feb 2008, 1:46 PM
Hi all,

I've run into need of a FormPanel that would be auto-configured by metadata received from server. As usually, I've written it; here is the first version:

This is html file I've used for testing:


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css">
<script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext/ext-all-debug.js"></script>
<script type="text/javascript" src="Ext.ux.MetaForm.js"></script>

<!-- A Localization Script File comes here -->
<script type="text/javascript">
Ext.onReady(function() {

var win = new Ext.Window({
id:'metaform-win'
,layout:'fit'
,width:500
,height:300
,title:'Ext.ux.MetaForm'
,items:{
xtype:'metaform'
,url:'formconfig.php'
,buttons:[{
text:'Load'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().load();
}
},{
text:'Submit'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().submit();
}
}]
}
});

win.show();
});
</script>
<title>Ext.ux.MetaForm Example</title>
</head>
<body>
</body>
</html>

Ext.ux.MetaForm code:



// vim: ts=4:sw=4:nu:fdc=4:nospell
/*global Ext */
/**
* @class Ext.ux.form.MetaForm
* @extends Ext.form.FormPanel
*
* A FormPanel configured by metadata received from server
*
* @author Ing. Jozef Sakáloš
* @copyright (c) 2008, by Ing. Jozef Sakáloš
* @version 1.3
* @date <ul>
* <li>6. February 2007</li>
* <li>6. March 2009</li>
* </ul>
* @revision $Id: Ext.ux.form.MetaForm.js 625 2009-03-11 00:04:59Z jozo $
*
* @license Ext.ux.form.MetaForm is licensed under the terms of
* the Open Source LGPL 3.0 license. Commercial use is permitted to the extent
* that the code/component(s) do NOT become part of another Open Source or Commercially
* licensed development library or toolkit without explicit permission.
*
* <p>License details: <a href="http://www.gnu.org/licenses/lgpl.html"
* target="_blank">http://www.gnu.org/licenses/lgpl.html</a></p>
*
* @forum 25551
*
* @donate
* <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
* <input type="hidden" name="cmd" value="_s-xclick">
* <input type="hidden" name="hosted_button_id" value="3430419">
* <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif"
* border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
* <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
* </form>
*/

Ext.ns('Ext.ux.form');

/**
* Creates new MetaForm
* @constructor
* @param {Object} config A config object
*/
Ext.ux.form.MetaForm = Ext.extend(Ext.form.FormPanel, {

// {{{
// config options
/**
* @cfg {Boolean/Object} autoInit
* Load runs immediately after the form is rendered if autoInit is set. In the case of boolean true
* the load runs with {meta:true} and in the case of object the load takes autoInit as argument
* (defaults to true)
*/
autoInit:true

/**
* @cfg {Object} baseParams
* Params sent with each request (defaults to undefined)
*/

/**
* @cfg {Boolean} border
* True to display the borders of the panel's body element, false to hide them (defaults to false). By default,
* the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
*/
,border:false

/**
* @cfg {Boolean} focusFirstField
* True to try to focus the first form field on metachange (defaults to true)
*/
,focusFirstField:true

/**
* True to render the panel with custom rounded borders, false to render with plain 1px square borders (defaults to true).
*/
,frame:true

/**
* @cfg {String} loadingText
* Localizable text for "Loading..."
*/
,loadingText:'Loading...'

/**
* @cfg {String} savingText
* Localizable text for "Saving..."
*/
,savingText:'Saving...'

/**
* @cfg {Number} buttonMinWidth
* Minimum width of buttons (defaults to 90)
*/
,buttonMinWidth:90

/**
* @cfg {Number} columnCount
* MetaForm has a column layout insise with this number of columns (defaults to 1)
*/
,columnCount:1

/**
* @cfg {Array} createButtons Array of buttons to create.
* Valid values are ['meta', 'load', defaults', 'reset', 'save', 'ok', 'cancel'] or any subset of them
* (defaults to undefined)
*/

/**
* @cfg {Object} data
* Data object bound to this form. If both {@link #metaData} and data are set at config time
* the data is bound and loaded on form render after metaData processing. Read-only at run-time.
*/

/**
* True if meta data has been processed and fields have been created, false otherwise (read-only)
* @property hasMeta
* @type Boolean
*/
,hasMeta:false

/**
* @cfg {Array} ignoreFields Array of field names to ignore when received in metaData (defaults to undefined)
*/

/**
* @cfg {Object} metaData Meta data used to configure this form. If set it takes precedence over {@link #autoInit}
* and server is not accessed to get meta data.
*/

/**
* @cfg {String} method Sever access method. 'GET' or 'POST' (if undefined 'POST' is used)
*/

/**
* @cfg {String} url URL for loading an submitting the form (defaults to undefined)
*/
// }}}
// {{{
/**
* Runs after the meta data has been processed and the form fields have been created.
* Override it to add your own extra processing if you need (defaults to Ext.emptyFn)
* @method afterMetaChange
*/
,afterMetaChange:Ext.emptyFn
// }}}
// {{{
/**
* Runs after bound data is updated. Override to add any extra processing you may need
* after the bound data is updated (defaults to Ext.emptyFn)
* @param {Ext.ux.form.MetaForm} form This form
* @param {Object} data Updated bound data
*/
,afterUpdate:Ext.emptyFn
// }}}
// {{{
,applyDefaultValues:function(o) {
if('object' !== typeof o) {
return;
}
for(var name in o) {
if(o.hasOwnProperty(name)) {
var field = this.form.findField(name);
if(field) {
field.defaultValue = o[name];
}
}
}
} // eo function applyDefaultValues
// }}}
// {{{
/**
* @private
* Changes order of execution in Ext.form.Action.Load::success
* to allow reading of data in this server request (otherwise data would
* be loaded to the form before onMetaChange is run from actioncomplete event
*/
,beforeAction:function(form, action) {
action.success = function(response) {
var result = this.processResponse(response);
if(result === true || !result.success || !result.data){
this.failureType = Ext.form.Action.LOAD_FAILURE;
this.form.afterAction(this, false);
return;
}
// original
// this.form.clearInvalid();
// this.form.setValues(result.data);
// this.form.afterAction(this, true);

this.form.afterAction(this, true);
this.form.clearInvalid();
this.form.setValues(result.data);
};
} // eo function beforeAction
// }}}
// {{{
/**
* Backward compatibility function, calls {@link #bindData} function
* @param {Object} data
* A reference to an external data object. The idea is that form can display/change an external object
*/
,bind:function(data) {
this.bindData(data);
} // eo function bind
// }}}
// {{{
/**
* @param {Object} data
* A reference to an external data object. The idea is that form can display/change an external object
*/
,bindData:function(data) {
this.data = data;
this.form.setValues(this.data);
} // eo function bindData
// }}}
// {{{
/**
* Closes the parent if it is a window
* @private
*/
,closeParentWindow:function() {
if(this.ownerCt && this.ownerCt.isXType('window')) {
this.ownerCt[this.ownerCt.closeAction]();
}
} // eo function closeParentWindow
// }}}
// {{{
/**
* Returns button thet has the given name
* @param {String} name Button name
* @return {Ext.Button/Null} Button found or null if not found
*/
,findButton:function(name) {
var btn = null;
Ext.each(this.buttons, function(b) {
if(name === b.name) {
btn = b;
}
});
return btn;
} // eo function findButton
// }}}
// {{{
/**
* Returns the button. This funcion is undefined by default, supply it if you want an automated button creation.
* @method getButton
* @param {String} name A symbolic button name
* @param {Object} config The button config object
* @return {Ext.Button} The created button
*/
// getButton
// }}}
// {{{
/**
* override this if you want a special buttons config
*/
,getButtons:function() {
var buttons = [];
if(Ext.isArray(this.createButtons)) {
Ext.each(this.createButtons, function(name){
buttons.push(this.getButton(name, {
handler:this.onButtonClick
,scope:this
,minWidth:this.buttonMinWidth
,name:name
}));
}, this);
}
return buttons;
} // eo function getButtons
// }}}
// {{{
,getOptions:function(o) {
o = o || {};
var options = {
url:this.url
,method:this.method || 'POST'
};
Ext.apply(options, o);
var params = this.baseParams ? Ext.ux.util.clone(this.baseParams) : {};
options.params = Ext.apply(params, o.params);
return options;
} // eo function getOptions
// }}}
// {{{
/**
* Returns values calling the individual fields' getValue() methods
* @return {Object} object with name/value pairs
*/
,getValues:function() {
var values = {};
this.form.items.each(function(f) {
values[f.name] = f.getValue();
});
return values;
} // eo function getValues
// }}}
// {{{
,initComponent:function() {

var config = {
items:this.items || {}
};
if('function' === typeof this.getButton) {
config.buttons = this.getButtons();
}

// apply config
Ext.apply(this, Ext.apply(this.initialConfig, config));

// call parent
Ext.ux.form.MetaForm.superclass.initComponent.apply(this, arguments);

// add events
this.addEvents(
/**
* @event beforemetachange
* Fired before meta data is processed. Return false to cancel the event
* @param {Ext.ux.form.MetaForm} form This form
* @param {Object} metaData The meta data being processed
*/
'beforemetachange'
/**
* @event metachange
* Fired after meta data is processed and form fields are created.
* @param {Ext.ux.form.Metadata} form This form
* @param {Object} metaData The meta data processed
*/
,'metachange'
/**
* @event beforebuttonclick
* Fired before the button click is processed. Return false to cancel the event
* @param {Ext.ux.form.MetaForm} form This form
* @param {Ext.Button} btn The button clicked
*/
,'beforebuttonclick'
/**
* @event buttonclick
* Fired after the button click has been processed
* @param {Ext.ux.form.MetaForm} form This form
* @param {Ext.Button} btn The button clicked
*/
,'buttonclick'
);

// install event handlers on basic form
this.form.on({
beforeaction:{scope:this, fn:this.beforeAction}
,actioncomplete:{scope:this, fn:function(form, action) {
// (re) configure the form if we have (new) metaData
if('load' === action.type && action.result.metaData) {
this.onMetaChange(this, action.result.metaData);
}
// update bound data on successful submit
else if('submit' === action.type) {
this.updateBoundData();
}
}}
});
this.form.trackResetOnLoad = true;

} // eo function initComponent
// }}}
// {{{
,load:function(o) {
var options = this.getOptions(o);
if(this.loadingText) {
options.waitMsg = this.loadingText;
}
this.form.load(options);
} // eo function load
// }}}
// {{{
/**
* Called in the scope of this form when user clicks a button. Override it if you need a different
* functionality of the button handlers.
* <i>Note: Buttons created by MetaForm has name property that matches {@link #createButtons} names</i>
* @param {Ext.Button} btn The button clicked.
* @param {Ext.EventObject} e Click event
*/
,onButtonClick:function(btn, e) {
if(false === this.fireEvent('beforebuttonclick', this, btn)) {
return;
}
switch(btn.name) {
case 'meta':
this.load({params:{meta:true}});
break;

case 'load':
this.load({params:{meta:!this.hasMeta}});
break;

case 'defaults':
this.setDefaultValues();
break;

case 'reset':
this.form.reset();
break;

case 'save':
this.updateBoundData();
this.submit();
this.closeParentWindow();
break;

case 'ok':
this.updateBoundData();
this.closeParentWindow();
break;

case 'cancel':
this.closeParentWindow();
break;
}
this.fireEvent('buttonclick', this, btn);
} // eo function onButtonClick
// }}}
// {{{
/**
* Override this if you need a custom functionality
*
* @param {Ext.FormPanel} this
* @param {Object} meta Metadata
* @return void
*/
,onMetaChange:function(form, meta) {
if(false === this.fireEvent('beforemetachange', this, meta)) {
return;
}
this.removeAll();
this.hasMeta = false;

// declare varables
var columns, colIndex, tabIndex, ignore = {};

// add column layout
this.add(new Ext.Panel({
layout:'column'
,anchor:'100%'
,border:false
,defaults:(function(){
this.columnCount = meta.formConfig ? meta.formConfig.columnCount || this.columnCount : this.columnCount;
return Ext.apply({}, meta.formConfig || {}, {
columnWidth:1/this.columnCount
,autoHeight:true
,border:false
,hideLabel:true
,layout:'form'
});
}).createDelegate(this)()
,items:(function(){
var items = [];
for(var i = 0; i < this.columnCount; i++) {
items.push({
defaults:this.defaults
,listeners:{
// otherwise basic form findField does not work
add:{scope:this, fn:this.onAdd}
}
});
}
return items;
}).createDelegate(this)()
}));

columns = this.items.get(0).items;
colIndex = 0;
tabIndex = 1;

if(Ext.isArray(this.ignoreFields)) {
Ext.each(this.ignoreFields, function(f) {
ignore[f] = true;
});
}
// loop through metadata colums or fields
// format follows grid column model structure
Ext.each(meta.columns || meta.fields, function(item) {
if(true === ignore[item.name]) {
return;
}
var config = Ext.apply({}, item.editor, {
name:item.name || item.dataIndex
,fieldLabel:item.fieldLabel || item.header
,defaultValue:item.defaultValue
,xtype:item.editor && item.editor.xtype ? item.editor.xtype : 'textfield'
});

// handle regexps
if(config.editor && config.editor.regex) {
config.editor.regex = new RegExp(item.editor.regex);
}

// to avoid checkbox misalignment
if('checkbox' === config.xtype) {
Ext.apply(config, {
boxLabel:'&#160;'
,checked:item.defaultValue
});
}
if(meta.formConfig.msgTarget) {
config.msgTarget = meta.formConfig.msgTarget;
}

// add to columns on ltr principle
config.tabIndex = tabIndex++;
columns.get(colIndex++).add(config);
colIndex = colIndex === this.columnCount ? 0 : colIndex;

}, this);
if(this.rendered && 'string' !== typeof this.layout) {
this.el.setVisible(false);
this.doLayout();
this.el.setVisible(true);
}
this.hasMeta = true;
if(this.data) {
// give DOM some time to settle
(function() {
this.form.setValues(this.data);
}.defer(1, this))
}
this.afterMetaChange();
this.fireEvent('metachange', this, meta);

// try to focus the first field
if(this.focusFirstField) {
var firstField = this.form.items.itemAt(0);
if(firstField && firstField.focus) {
var delay = this.ownerCt && this.ownerCt.isXType('window') ? 1000 : 100;
firstField.focus(firstField.selectOnFocus, delay);
}
}
} // eo function onMetaChange
// }}}
// {{{
,onRender:function() {
// call parent
Ext.ux.form.MetaForm.superclass.onRender.apply(this, arguments);

this.form.waitMsgTarget = this.el;

if(this.metaData) {
this.onMetaChange(this, this.metaData);
if(this.data) {
this.bindData(this.data);
}
}
else if(true === this.autoInit) {
this.load(this.getOptions({params:{meta:true}}));
}
else if ('object' === typeof this.autoInit) {
this.load(this.autoInit);
}

} // eo function onRender
// }}}
// {{{
/**
* @private
* Removes all items from both formpanel and basic form
*/
,removeAll:function() {
// remove border from header
var hd = this.body.up('div.x-panel-bwrap').prev();
if(hd) {
hd.applyStyles({border:'none'});
}
// remove form panel items
this.items.each(this.remove, this);

// remove basic form items
this.form.items.clear();
} // eo function removeAllItems
// }}}
// {{{
,reset:function() {
this.form.reset();
} // eo function reset
// }}}
// {{{
,setDefaultValues:function() {
this.form.items.each(function(item) {
item.setValue(item.defaultValue);
});
} // eo function setDefaultValues
// }}}
// {{{
,submit:function(o) {
var options = this.getOptions(o);
if(this.savingText) {
options.waitMsg = this.savingText;
}
this.form.submit(options);
} // eo function submit
// }}}
// {{{
/**
* Updates bound data
*/
,updateBoundData:function() {
if(this.data) {
Ext.apply(this.data, this.getValues());
this.afterUpdate(this, this.data);
}
} // eo function updateBoundData
// }}}
// {{{
,beforeDestroy:function() {
if(this.data) {
this.data = null;
}
Ext.ux.form.MetaForm.superclass.beforeDestroy.apply(this, arguments);
} // eo function beforeDestroy
// }}}

});

// register xtype
Ext.reg('metaform', Ext.ux.form.MetaForm);

// eof
And for those using PHP, here is PHP script I've used for testing; hopefully it gives at least an idea for non-PHP users on how the returned json should look like:



<?php

$formConfig = array(
"labelAlign"=>"left"
,"columnCount"=>2
,"labelWidth"=>80
,"defaults"=>array(
"width"=>130
)
);
$fields = array(
// company name
array(
"name"=>"compName"
,"fieldLabel"=>"Company"
,"editor"=>array(
"allowBlank"=>false
)
)
,array(
"name"=>"compForm"
,"fieldLabel"=>"Legal Form"
,"editor"=>array(
"allowBlank"=>false
)
)
,array(
"name"=>"clientFrom"
,"fieldLabel"=>"Client Since"
,"editor"=>array(
"xtype"=>"datefield"
,"format"=>"j.n.y"
)
)
,array(
"name"=>"clientTill"
,"fieldLabel"=>"Client Till"
,"editor"=>array(
"xtype"=>"datefield"
,"format"=>"j.n.y"
)
)
,array(
"name"=>"compNote"
,"fieldLabel"=>"Note"
,"editor"=>array(
"xtype"=>"textarea"
)
)
);
$config = array(
"success"=>true
,"metaData"=>array(
"fields"=>$fields
,"formConfig"=>$formConfig
)
,"data"=>array(
"compName"=>"My Company"
,"compNote"=>"Company Note"
,"clientFrom"=>"1.2.08"
)
);
echo json_encode($config);

// end of file
?>
And finally, resulting json:



{"success":true,"metaData":{"fields":[{"name":"compName","fieldLabel":"Firma","editor":{"allowBlank":false}},{"name":"compForm","fieldLabel":"Legal Form","editor":{"allowBlank":false}},{"name":"clientFrom","fieldLabel":"Client Since","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"clientTill","fieldLabel":"Client Till","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"compNote","fieldLabel":"Note","editor":{"xtype":"textarea"}}],"formConfig":{"labelAlign":"left","columnCount":2,"labelWidth":80,"defaults":{"width":130}}},"data":{"compName":"My Company","compNote":"Company Note","clientFrom":"1.2.08"}}

Enjoy.

MeDavid
7 Feb 2008, 12:23 PM
Hi,

Maybe a good idea to use annotations / reflection, so that you can create froms and grids based on your php data classes?



class Person {
/**
* @GUI(label=>"First name", width=>200);
* @Validation(allowEmpty=>true, maxLength=>100)
*/
public $firstName;

}

jsakalos
7 Feb 2008, 2:26 PM
Sure. I'm not creating data for MetaForms with the PHP like above in real application. I've chosen the above example as it clearly illustrates the structure of JSON that is understood by the MetaForm.

Anyway, MetaForm as client side javascript class doesn't care how, or in which language, is created JSON it accepts the format of.

precariouspanther
11 Feb 2008, 8:23 PM
Thanks for the great plugin JSA. Just one small addition:




// loop through metadata colums or fields
// format follows grid column model structure
Ext.each(meta.columns || meta.fields, function(item) {
if(item.editor.regex){
//alert(item.editor.regex);
item.editor.regex= new RegExp(item.editor.regex);
}

var config = Ext.apply({}, item.editor, {
name:item.name || item.dataIndex
,fieldLabel:item.fieldLabel || item.header
,xtype:item.editor && item.editor.xtype ? item.editor.xtype : 'textfield'
});

This will allow regex validation to be passed from the server config as well as the json gets evaled as a string rather than a regex object.

jsakalos
11 Feb 2008, 8:30 PM
Right. I've incorporated it to the source. BTW, I've been working on improvement of MetaForm a lot recently so I'm posting new version in the first post.

Cheers.

precariouspanther
11 Feb 2008, 9:01 PM
Ooo very nice, thanks for the updates.

ikk0
12 Feb 2008, 10:35 AM
Hi,
this is not working correctly for me.
At first, you are using something like "Perseus" in your code.
I never heard of that. Had to comment that out to get the code working.
Then, in your PHP-Example you are using the _() function, with which you probably translate text in your application, but you should remove it in the example code.
But after loading the Metadata from the Server, I get an alert (Firebug):


POST get-content.php5?formconfig=true (235ms)ext-base.js (line 10)
c has no properties
[Break on this error] }else if(!c.events){

Any Idea?

jsakalos
12 Feb 2008, 10:56 AM
Ok, try it now, should work.

ikk0
12 Feb 2008, 11:35 AM
Ext.isArray is not a function
[Break on this error] if(Ext.isArray(this.ignoreFields)) {

Seems like this is not implemented in standard-Ext. Could you supply the code?

Greetings,

jsakalos
12 Feb 2008, 1:06 PM
What version of Ext are you running?

jsakalos
12 Feb 2008, 1:11 PM
Oh, I see, it's not even in 2.0.1, I'm running svn. Replace that line with




if(this.createButtons instanceof Array) {

ikk0
12 Feb 2008, 1:15 PM
Thanks, but it was about this line:


if(Ext.isArray(this.ignoreFields)) {

Working now. Thanks!

//Edit:
Ah, you have to replace this line too:

if(Ext.isArray(this.createButtons)) {

You should update your code for Ext 2.0.1 users.

jsakalos
12 Feb 2008, 1:34 PM
Yes, done.

ikk0
15 Feb 2008, 5:03 PM
Question:
I'm rendering the Metaform into a Ext.Window.
Is it possible to set the "height of the Window to auto"? I mean, i don't know how many fields are coming with the MetaForm, but i don't want to set a static height for the Window. Is it possible the Window resizes automatically?
Greetings,
ikk0.

jsakalos
16 Feb 2008, 3:47 AM
I'd say yes, I'm doing so with some image content, anyway, the best is to try. ;)

ikk0
16 Feb 2008, 4:25 AM
I can't seem to find a way to get the real height of the Meta-FormPanel. It has always got the height of it's container, i.e. the Window(Panel). How do you do it with images? Or have you got any idea how to realize this otherwise?

jsakalos
16 Feb 2008, 6:17 AM
Simple:



var win = new Ext.Window({
id:'stat-chart-zoom-win'
,width:400
,plain:true
,border:false
,shadow:false
,autoHeight:true
The image is in the window body element and I just don't care about its height (it's basically constant aspect ratio image created by server based on width). When the image is received window adjusts its height.

ikk0
16 Feb 2008, 8:16 AM
Great, thanks, autoHeight was what I was searching for. But it is a bit tricky, you have to set autoHeight of the FormPanel (MetaForm) AND the Window to true:



var win = new Ext.Window({
autoHeight: true,
items:{
xtype:'metaform',
autoHeight: true,
...
},
...
});

jsakalos
16 Feb 2008, 9:50 AM
Good to know. I'm glad you've got it working.

ikk0
18 Feb 2008, 6:14 AM
I have got another question. Could you extend your extension to also deliever the success and failure callback after a successful/failed submit of form data? Or how do I have to do it?

I tried, but didn't succeed:

var win = new Ext.Window({
autoHeight: true,
items:{
xtype:'metaform',
autoHeight: true,
success: function() {
Ext.MessageBox.alert('Status','Save done');
},
...
},
...
});

//or:
//even this won't work:
Ext.getCmp('metaform-win').items.get(0).getForm().on('actioncomplete', function(){alert('completed');});

jsakalos
18 Feb 2008, 6:43 AM
MetaForm, after configuration, behaves exactly as Ext.form.FormPanel so you can listen to same events as for standard Ext.form.

ikk0
18 Feb 2008, 8:34 AM
Even though I still couldn't find a solution for my problem, I think I found a really, really small bug in your code:


case 'save':
case 'submmit':
button = this.getButton(name, {
handler:this.submit.createDelegate(this, [{params:{cmd:'setPref'}}])
});
break;

"submmit". Think that was not intended? :)
Greetings

jsakalos
18 Feb 2008, 8:49 AM
Oh yes, thanks for finding typo. In fact, I've never thought that somebody will use that part of code... I use it to make life easier in my app.

george.antoniadis
28 Feb 2008, 12:54 AM
Saki for once again you've outdone your self! :)
Grats on yet another awesome ux ;)

Just a question. has anyone tried adding tabs on a metaform?

jsakalos
28 Feb 2008, 12:59 AM
There is no support for any visual structure in MetaForm. It just takes metaData and renders fields one after the other. I wouldn't use it for very complex crafted forms that are most likely unique in whole app anyway.

jamesfarrer
4 Mar 2008, 4:17 AM
Hi Jozef,

Thanks for all your excellent advice and extensions on here - I have also used your datetime field which is brilliant.

I'm having a problem using this one though....

To start with, I am just using your test form and test json data... however I get this problem...



var win = new Ext.Window({
id:'metaform-win'
,layout:'fit'
,width:500
,height:300
,title:'Ext.ux.MetaForm'
,renderTo:'dynamic-form'
,items:{
xtype:'metaform'
,url:'../profile/getprofileform.castle'
,buttons:[{
text:'Load'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().load();
}
},{
text:'Submit'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().submit();
}
}]
}
});


I then get this error....



fire : function(){
var ls = this.listeners, scope, len = ls.length;
if(len > 0){
this.firing = true;
var args = Array.prototype.slice.call(arguments, 0);
for(var i = 0; i < len; i++){
var l = ls[i];
if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
this.firing = false;
return false;
}
}
this.firing = false;
}
return true;
}


The specific issue is that l.fireFn is undefined. Do you think this is a problem because I am using renderTo?

Thanks

James

jsakalos
4 Mar 2008, 5:13 AM
Difficult to say... You should examine the call stack to see where is initiator of the error. In any case, I'd recommend against renderTo especially rendering to another container as body. You can also try to set autoInit:false to see what happens.

BTW, MetaForm has integrated an infrastructure for buttons you just need to provide function getButton and createButtons array.

chalu
15 Mar 2008, 12:32 PM
I am using Ext 2.0.2, I can't Ext.isArray in the docs, and the firebug javascript console in my ext application returns undefined with this code alert(Ext.isArray).

Though the demo / example I downloaded worked (after adding <?php instead of <? to the php code in formconfig.php which was causing an error), integrating it with my application now throws errors from within the Ext.ux.MetaForm.js file.

First, within the removeAll function, I had to make this change

// remove form panel items
//this.items.each(this.remove, this); // this line just won't work in my application
if(this.items && this.items.length > 0 && !Ext.isEmpty(this.items[0])){
this.items.each(this.remove, this);
}

Now I am stuck within the onMetaChange function, with firebug reporting that column has no
properties, from this line

columns.get(colIndex++).add(config);
seems that it is not been initialized from this line :

columns = this.items.get(0).items;

All I did to try to use it was
1. include the Ext.ux.MetaForm.js file
2. added this code to my application :

if(!Ext.get('metaform-win')){
var win = new Ext.Window({
id:'metaform-win'
,layout:'fit'
,width:370
,height:300
,title:'Configure User Column Action Settings'
,items:{
xtype:'metaform'
,url:'formconfig.php'
,buttons:[{
text:'Cancle'
,handler:function() {
Ext.getCmp('metaform-win').close();
}
},{
text:'Submit'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().submit();
}
}]
}
});

win.show();
}
}

Even using the same code in the html file from the source download still produces the same set of errors. Please what am I missing in it's usage. Note I am using the yui adapter includes, I can't find Ext.isArray. Thanks for this extension

jsakalos
15 Mar 2008, 3:01 PM
I am using Ext 2.0.2, I can't Ext.isArray in the docs, and the firebug javascript console in my ext application returns undefined with this code alert(Ext.isArray).

You can replace Ext.isArray(a) with 'function' === typeof a.pop. Ext.isArray is in SVN but not in distribution yet.


Though the demo / example I downloaded worked (after adding <?php instead of <? to the php code in formconfig.php which was causing an error)

This is just php.ini setting, short_open_tag = On

Other issues: You have to make it working at least once with the provided php backend to understand the structure of delivered JSON - it's quite deep and complex.

removeAll: I've just tested it and it works flawlessly. Strange...

columns: have you configured columnCount?

Just to be sure, I'm updating code in the first post but I doubt that it has changed. I haven't touched MetaForm for a couple of weeks....

chalu
17 Mar 2008, 7:05 AM
columnCount somewhere in the formconfig.php code has a value of 2 i.e "columnCount" => 2.
Do I need to change this to fix the errors, what I find strange is that your the example works on its own, but when put in my application, even without tampering with the original source ,it spits errors. Can't I just have it run in an application just by including the source and using your example block of code in the html file that shiped with the download.

This may not be the right place for this anyway but please, I am using some grid panel that accepts column model settings from meta data from the server, it has a toolbar that I also wish to adapt to some server meta, I need a way to remove the items in the toolbar and repopulate it, each time the grid recieves server meta.
tried

gridObject.remove( gridObject.getToolBar() );
and


Ext.each(gridObject.items, function(item){
this.remove(item);
}, gridObject.getToolBar());

all to no avail

Thanks Man

jsakalos
17 Mar 2008, 8:20 AM
Re MetaForm: If example works and application not, there must be some difference. Just to find and fix it...

Re Grid: Best would be to post it in Help forum - I don't know answer from the top of my head and there are another people that could...

rewind
18 Mar 2008, 5:32 AM
First of all my compliments!

With the following code i always get a failure even though firebug says the response =
{success:true}



var win;
if(!win) {
win = new Ext.Window({
id:'metaform-win'
,width:400
,autoHeight:true
,title:'Ext.ux.MetaForm'
,items:{
id: 'meta'
,xtype:'metaform'
,autoHeight: true
,url:'metatest.php?node='+node.id
,buttons:[{
text:'Load'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().load();
}
},{
text:'Submit'
,formBind: true
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().submit({
method:'POST',
waitTitle:'Connecting',
waitMsg:'Sending data...',
success:function(form, action){
Ext.MessageBox.alert('Succes!', 'Succes');
},
failure:function(form, action){
Ext.MessageBox.alert('Failed!', 'Failed');
}

});
}
}]
}
});
}
win.show();

jsakalos
18 Mar 2008, 6:00 AM
There is no apparent error in the code; it looks good. You need to track down the error with Firebug. Data coming from server is most likely wrong format. Should you need more help on this, prepare please functional example html+js+php that I can copy somewhere to ext tree and that would run so I can debug locally.

rewind
18 Mar 2008, 6:12 AM
i created a small testcase!

jsakalos
18 Mar 2008, 7:38 AM
Check you includes; you're trying to include ext-base.js and ext-all.js from resources directory. They have never been there. Also, you php returns only success. It has to return metadata, otherwise form stays empty.

rewind
18 Mar 2008, 7:47 AM
i use the forms in a new application i am writing, the js files are included correctly en in my original implementation i generate the json form with php. the form works perfectly e get the requested form with the right data and i can submit the changes. These changes are also correctly submitted to the mysql database. The only thing that is not working is the succes part. The form keeps giving me the failure message while it isn't failing!

I try'd all type of different json returns like:

echo '{success:true}';
echo '{"success":true}';
echo '{ success:true}';

etc..

Firebug also confirms the expected response from php

jsakalos
18 Mar 2008, 8:09 AM
echo '{"success":true}';

This one is correct. Anyway, if you post meta:true MetaForm expects it will receive metadata, not only success:true.

rewind
18 Mar 2008, 11:12 AM
ha thnx alot i didn't realize i needed to give the whole new object back to the form now it works :)

chalu
18 Mar 2008, 8:41 PM
Hello Saki, compliments for your good works, got an issue though.
I have re-downloaded the code from your first post and fixed the isArray errors, now I am stuck at l.fireFn is undefined, but I am not using renderTo as jamesfarrer did but I still get the stopper, any suggestions for my case while I still try to figure it out?
Here is my call :


if(!Ext.get('metaform-win')){
var win = new Ext.Window({
id:'metaform-win'
,layout:'fit'
,width:370
,autoHeight:true
,title:'Configure User Column Action Settings'
,items:{
xtype:'metaform'
,autoHeight:true
,url:'formconfig.php'
,buttons:[{
text:'Cancle'
,handler:function() {
Ext.getCmp('metaform-win').close();
}
},{
text:'Submit'
,handler:function() { Ext.getCmp('metaform-win').items.get(0).getForm().submit();
}
}]
}
});

win.show();
}


This seems to be the culprit line, it's in the removeAll() method call


// remove form panel items
this.items.each(this.remove, this);

hendra1
18 Mar 2008, 9:40 PM
i had try it to my app, but i still found error like this:

types[config.xtype || defaultType] is not a constructor
[Break on this error] return new types[config.xtype || defaultType](config)

NB: i had change the Ext.isArray into this.createButtons instanceof Array

does anyone could help me..?
Thanks in advance

jsakalos
19 Mar 2008, 2:13 AM
I have added this function to code:



if(!Ext.isArray) {
Ext.isArray = function(v) {
return v && 'function' == typeof v.pop;
}
}


Re xtype error: Is file really included - check path? Typo in xtype? Last line with Ext.reg('metaform', Ext.ux.MetaForm); missing?

ikk0
19 Mar 2008, 8:14 AM
Hi Saki,
it's me again. :-)
I have a question.
Is it possible to send a Combobox with a store with values through your UX? (Or generally, create a new class/object?)
I tried, but didn't succeed.



$fields = array(
array(
"name"=>"dial"
,"fieldLabel"=>"Dial"
,"editor"=>array(
"xtype"=>"combo",
"mode"=>"local",
"store"=>array("Ext.data.SimpleStore"=>array("fields"=>array('id', 'descr'), "data"=>array(array(0, 'zero'), array(1, 'one')))),
)
)
);


Help would be really appreciated!

Greetings
ikk0

jsakalos
19 Mar 2008, 12:05 PM
I have some pre-configured combos for this purpose in my application so all I need to send from server is xtype.

See Application Design Based On Pre-Configured Classes (http://extjs.com/forum/showthread.php?p=125476) for more details on how to create such components.

ikk0
19 Mar 2008, 12:29 PM
But i need to fill them with data from the server. What's the best way of doing this?
Greetings

jsakalos
19 Mar 2008, 12:33 PM
That's no problem. Have you read the above link? You can pre-configure your classes whatever way you like.

ikk0
19 Mar 2008, 12:35 PM
Ahh, after reading it the second time I understood it. Thanks!

chalu
19 Mar 2008, 1:43 PM
Saki, it's me again. Have prepared a testcase of my usage, please have a look.

jsakalos
19 Mar 2008, 2:05 PM
And what's problem? It works fine. Congrats!

chalu
19 Mar 2008, 3:39 PM
I can't place my finger on the problem, but this same testcase for me fails in firefox and IE7. Everything seems ok with the code, I thought my application had issues that made it not to work hence I made this simple test which now works for you but fails for me. I am confused.

jsakalos
19 Mar 2008, 3:44 PM
What's your PHP version? Do you receive metaData from server? How does received JSON look like?

jsakalos
19 Mar 2008, 3:53 PM
BTW, your problem is not browser dependent; I could run your testcase in FF@Linux, FF@Win, IE7@Win, Opera@Linux and Safari@Win w/o any problems.

chalu
19 Mar 2008, 4:13 PM
I am currently developing with WAMP 5 (PHP /MySQL 5 with Apache 2.x).
This is exactly what my server sends in the JSON response from formconfig.php :


{"success":true,"metaData":{"fields":[{"name":"compName","fieldLabel":"Company","editor":{"allowBlank"

:false}},{"name":"compForm","fieldLabel":"Legal Form","editor":{"allowBlank":false}},{"name":"clientFrom"

,"fieldLabel":"Client Since","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"clientTill","fieldLabel"

:"Client Till","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"compNote","fieldLabel":"Note"

,"editor":{"xtype":"textarea"}}],"formConfig":{"labelAlign":"left","columnCount":2,"labelWidth":80,"defaults"

:{"width":130}}},"data":{"compName":"My Company","compNote":"Company Note","clientFrom":"1.2.08"}}

jsakalos
19 Mar 2008, 4:16 PM
This is mine, working:


{"success":true,"metaData":{"fields":[{"name":"compName","fieldLabel":"Company","editor":{"allowBlank":false}},{"name":"compForm","fieldLabel":"Legal Form","editor":{"allowBlank":false}},{"name":"clientFrom","fieldLabel":"Client Since","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"clientTill","fieldLabel":"Client Till","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"compNote","fieldLabel":"Note","editor":{"xtype":"textarea"}}],"formConfig":{"labelAlign":"left","columnCount":2,"labelWidth":80,"defaults":{"width":130}}},"data":{"compName":"My Company","compNote":"Company Note","clientFrom":"1.2.08"}}

chalu
19 Mar 2008, 4:34 PM
Commenting this.removeAll(); in the onMetaChange function stops the 'l.fireFn has no properties' error but leads to another which complains that 'columns has no properties' at Line 305, this line columns.get(colIndex++).add(config), all in the Ext.ux.MetaForm.js file.
Some time ago you asked about configuring columnCount, what's that about? in the php config file or in the js extension file. Since my case is 'special' let me try debugging by elimination. :D

jsakalos
19 Mar 2008, 4:46 PM
There is a column layout created in the form. columnCount says how many columns this column layout has.

There is one another thing that doesn't make sense. Test case you provided runs here fine. That infers there must be sth different: I run lates svn version of Ext but I don't think this is the problem as MetaForm code is older than Ext 2.0.2.

Also, MetaForm code can be different, but I've never heard about the error Firebug spits out before so there is no "fix" for that error. Just to be absolutely sure, I've re-posted MetaForm code in the first post (svn rev. 80). Your testcase runs fine against that rev.

chalu
19 Mar 2008, 8:50 PM
Thanks Saki, downloaded the files again and now, at least, my test case now runs well BUT.
using the extension in the application gave some weired behavior. I use other extensions in the same project, and have observed that they cause code to fail except when included in a certain order. Firebug kept saying Ext.ux.MetaForm is not a constructor till I moved it's include up among the other extension files. Surprisingly, this error only goes away when the include is placed between a certain set of the extensions. I first noticed this behavior with the TabCloseMenu plugin. This is my include sequence



<script src="scripts/AC_RunActiveContent.js" type="text/javascript"></script> // flash script
<script src="src/lib/ext/adapter/ext/ext-base.js"></script>
<script src="src/lib/ext/ext-all-debug.js"></script>
<script src="src/lib/ext/ux/Autogrid.js"></script> // a meta grid extension
<script src="src/lib/ext/ux/Ext.ux.MetaForm.js"></script> // only 'works' here
<script src="src/lib/ext/ux/MetaToolbar.js"></script> // never mind
<script src="src/lib/ext/ux/TabCloseMenu.js"></script> // right click to close tabs
<script src="src/lib/ext/ux/pPageSize.js"></script> // paging toolbar plugin
<script src="src/console.js"></script> // my application script


Now it seems I've hit the lonely road (since it works off the box for everyone else) and I'll have to find the 'thing' in my code still causing the 'l.fireFn has no properties' error. I have a feeling it's a scope thing. I'll keep you posted.

ikk0
20 Mar 2008, 12:34 PM
When configuring the Metaform, is it possible to send a "selected" property for a Combobox/DatePicker? (Or setValue)

jsakalos
20 Mar 2008, 1:03 PM
You cannot send functions like setValue(), they won't get executed. But you can send the whole initial data for the form. I guess the example does so.

chalu
20 Mar 2008, 5:06 PM
The strange issues causing the code to fail in my application came from the Ext source project files I was working with, as provided by Aptana Studio, I changed the Ext source include lines to point to source I downloaded from the Ext site (containing examples, docs etc) and it fixed the error. Apparently, there is something wrong with the Ext 2.0 Aptana plugin (http://orsox.mocis.at/download.php?view.1) we are been asked to download from http://jackslocum.com/blog (http://http://jackslocum.com/blog/2008/02/07/ides-plugins-and-tools-for-extjs-20/)
which is what (I suppose) Aptana builds it's Ext projects with. It says its Ext 2.0 on that site, maybe there are version differences between that plugin download and the Ext site source download. Thanks for all the time.

jsakalos
20 Mar 2008, 6:20 PM
My 2 cents... Switch to vim (http://www.vim.org) ;)

mdissel
21 Mar 2008, 2:06 AM
Why are you overriding the getValues() function? this override doesn't return all the fieldvalues if for example fieldsets are used inside the formpanel..

jsakalos
21 Mar 2008, 2:48 AM
It is not overrinden method it is added method. FormPanel, the MetaForm is the extension of, doesn't have its own getValues method. getValues method is defined in the underlying BasicForm that uses Ajax.serializeForm that was not good for my purposes.

It is well known fact that if you add a component that is not formField to a FormPanel it is not added as item to underlying BasicForm (see FormPanel onAdd method). This is fiexed in MetaForm by lines:


,listeners:{
// otherwise basic form findField does not work
add:{scope:this, fn:this.onAdd}
}
Deeper nested structures, as fields in fieldsets, are not handled by the above fix, though.

The conclusion is: you can either use MetaForm::getValues() if it suits you or you can use MetaForm::getForm()::getValues() that is untouched.

mdissel
21 Mar 2008, 2:52 AM
The conclusion is: you can either use MetaForm::getValues() if it suits you or you can use MetaForm::getForm()::getValues() that is untouched.

Thanks for the explantion. Why didn't the serializeForm fit into your purpose?

jsakalos
21 Mar 2008, 2:58 AM
I guess it was because it didn't return unchecked checkboxes or something of the sort.

chalu
24 Mar 2008, 7:14 PM
Hi Saki, I was wondering if one can apply your advice of configured classes, using xtype, to make a plugin that can now be passed in json to a form widget say a combo. A hard coded example can be this :


var combo1 = new Ext.form.ComboBox({
mode:'local',
typeAhead: true,
triggerAction:'all',
transform:'test-combo',
plugins: new Ext.ux.AsyncComboLoader()
});


Is there any way to populate the plugins property with object literal(s), specifying the xtype of the a plugin (as with some extensions) and also passing parameters.
This has not worked :


var combo1 = new Ext.form.ComboBox({
mode:'local',
typeAhead: true,
triggerAction:'all',
transform:'test-combo',
plugins: [
{
xtype: 'comboloader',
el: combo2
}
]
});

mjlecomte
24 Mar 2008, 7:33 PM
If you're not aware Saki has published some great tutorials on extending classes (using xtypes, etc.) and also on plugins (http://extjs.com/learn/Tutorial:Writing_Ext_2_Plugins). After a quick read of those tutorials maybe you'll understand a little better.

chalu
24 Mar 2008, 10:15 PM
Just as you can get a combo to be instantiated with this :


....
items: [
xtype:'combo'
......
]
....

can a plugin object be stated in this manner. I needed a functionality to allow a combo1 populate other combo(s) when items in combo1 are selected. After some thought, I decided that an extension would not resolve the challenge since we can only inherit / extend one type at a time. A plugin fits because any combo will be able to use it at will. Thus we can have a Countries IconCombo (with this plugin) that will populate a States IconCombo when a particular country is selected, and with same plugin, have the States combo populate a Province / District / Local Government combo for the users state.
With
plugins:new Ext.ux.plugins.IconCombo(), this is hard coded, and the parameters (if any) for the plugin may be passed right there and then. What if it's a Ext.ux.MetaForm scenario where field configs are comming from the server, we will be able to make a combo just stating its type and including other config in the server, can we do the same with this loader plugin, E.g we have to tell it which combo to load data into, where to get the data from, what node in the response has the data, how to handle request failures etc. These may vary for each combo. We may not need as much as these params, they may be defined in the target combo's store, and have our loader just pass the value of it's selected field but what happens if combo1 has several target combos. If we can pass config to the client and make a plugin with its xtype value, passing the other behavior also as part of this config, then we may have risen up to the challenge.

I am persuaded to use this, as it abstracts the 'loading' functionality away, and to a single location (can really ease upgrade and maintenance) and make it re-useable. Or perhaps I should just listen for the 'select' event of combo1 and do whatever I please ? Certainly not possible in a Ext.ux.MetaForm scenario where I have no handle of the combo.

jsakalos
25 Mar 2008, 12:33 AM
Try to add the following code after handling regex and let me know if it works please:


if(config.editor && config.editor.plugins) {
var plugins = config.editor.plugins;
delete(config.editor.plugins);
if(plugins instanceof Array) {
config.editor.plugins = [];
Ext.each(plugins, function(plugin) {
config.editor.plugins.push(Ext.ComponentMgr.create(plugin));
});
}
}
You may need to tweak the code - I've written it off-hand - haven't tested it.

chalu
25 Mar 2008, 4:33 AM
I'll do it and get back to you, thanks again.

chalu
25 Mar 2008, 7:08 PM
With your suggested code, I kept having firebug say something like 'plugins[i].init is not a function'. Apparently, our new block of code was not even reached before this error fires up, it seems to be caused from the block from which we assign values to the config variable (just before we handle regex). So I came up with this (inspired by yours though) :


var editorPlugins = null;
if(item.editor && item.editor.plugins){
var plugins = item.editor.plugins;
delete item.editor.plugins;
if(plugins instanceof Array){
editorPlugins = [];
Ext.each(plugins, function(plugin){
editorPlugins.push( Ext.ComponentMgr.create(plugin) );
});
}else{
editorPlugins = Ext.ComponentMgr.create(plugin);
}
}

var config = Ext.apply({}, item.editor, {
name:item.name || item.dataIndex,
fieldLabel:item.fieldLabel || item.header,
defaultValue:item.defaultValue,
xtype:item.editor && item.editor.xtype ? item.editor.xtype : 'textfield',
plugins: editorPlugins
});

And this did it. Besides, I observed that the shadow of the formpanel is not resized accordingly (I am using autoHeight:true) after the form gets populated with fields and changes its height, until you move it, any remedy for this. I have a little demo of a plugin usage with Ext.ux.MetaForm thread (http://extjs.com/forum/showthread.php?p=143061#post143061).Thanks

ray007
28 Mar 2008, 3:14 AM
Is there a way to pass the metaData object in the initial configuration when creating the form?
I'd like the create the form with all the fields it's supposed to have and not wait for the first load ...

jsakalos
28 Mar 2008, 3:17 AM
If you know fields the form should have then MetaForm is not for you. Use standard Ext.form.FormPanel. MetaForm, by design, needs metaData to be received from server.

Richie1985
28 Mar 2008, 4:53 AM
What i have to do, when i want to use this in a tabpanel, not in a window?

I hope you can help me!

thanks!

jsakalos
28 Mar 2008, 4:57 AM
MetaForm extends FormPanel so there is no difference in adding it to tabpanel. Just specify it as one of tabs.

goldledoigt
28 Mar 2008, 6:50 AM
Hi Saki,
first of all thanks for this marvelous ux (as usual).

My question:
I know you've said that ...


There is no support for any visual structure in MetaForm. It just takes metaData and renders fields one after the other. I wouldn't use it for very complex crafted forms that are most likely unique in whole app anyway.

But do you have an idee about how to add Ext.form.FieldSet to your metaForm ?
(FieldSet defined by server json of course)

The expected result could look like exemple 2 in the dynamic.html
http://extjs.com/deploy/dev/examples/form/dynamic.html

Thanks

jsakalos
28 Mar 2008, 7:12 AM
The design principle of MetaForm was to keep it simple, therefore, there is no fieldset support built in. You can check RemoteComponent extension if you need more visually structured form.

ray007
31 Mar 2008, 1:14 AM
If you know fields the form should have then MetaForm is not for you. Use standard Ext.form.FormPanel. MetaForm, by design, needs metaData to be received from server.

But I'd like to use the same metaData-object to construct the form no matter whether I already have the definition already locally available or need to wait for the result of the ajax call.
And in the former case waiting for the remote result just to be able to show the form is unwanted waiting time for the user.

jsakalos
31 Mar 2008, 1:51 AM
There are 2 distinct and different situations:

- You know fields => FormPanel
- You don't know fields => MetaForm

Combination of them doesn't make sense.

mdissel
31 Mar 2008, 4:01 AM
There are 2 distinct and different situations:

- You know fields => FormPanel
- You don't know fields => MetaForm

Combination of them doesn't make sense.

There's a third combination that makes it useful to support to loading metaData without an extra request to the server...
- You don't know the fields and the MetaForm is nested inside another dynamic loaded component..

Maybe something you this works: (not tested)

,onRender:function() {
if (this.metaData){
this.autInit = false;
this.onMetaChange(this, this.metaData);
// not sure if this works ok
this.form.clearInvalid();
if (this.data){
this.form.setValues(this.data);
this.form.trackResetOnLoad = true;
}
}

// call parent
Ext.ux.MetaForm.superclass.onRender.apply(this, arguments);
this.form.waitMsgTarget = this.el;

if(true === this.autoInit) {
this.load({params:{meta:true}});
}
else if ('object' == typeof this.autoInit) {
this.load(this.autoInit);
}
} // eo function onRender



ps. What's the reason of item.editor.xtype? why not item.xtype inside the onMetaChange?

Thanks
Marco

jsakalos
31 Mar 2008, 7:55 AM
I avoid loading of components so I have no experiences on that.

item.editor.xtype - I use same backend for MetaGrid and MetaForm.

chalu
31 Mar 2008, 12:42 PM
I am building an extension for wizards with MetaForm, to allow for remotely configured wizards if needed. I am using the card layout thus my server script has 'pages' instead of 'fields' that the metaform example php script has. A page (actually an array) in the 'pages' array now contains one or more 'fields' (array specifying configs for a particular field), more like a paginated form for the card layout. The default onMetachange method will not accommodate this change, which is why I needed to override it in my extension. Here is a sample block from my extension :


Ext.ux.Wizard = Ext.extend(Ext.ux.MetaForm, {
...

initComponent: function(){
....
Ext.apply(this, {
layout:'card',
activeItem: this.activeItem || 0
});
...
Ext.ux.Wizard.superclass.initComponent.apply(this, arguments);
....
},

onMetaChange(form, meta){
console.log('Called');
}
...
});

Ext.reg('wizard', Ext.ux.Wizard);


This is supposed to be simple, by just declaring the function in the extension and doing my stuff, just like onRender is overriden in most extensions to do customization at render time.
The problem is that my onMetachange method is just never ever called when the JSON response reaches the client. Any suggestions please

jsakalos
31 Mar 2008, 3:36 PM
You do not need anything special with MetaForm as it supports basePrams. Just put your page number or page name there and respond from server with correct (meta)data. onMetaChange gets called only if response contains member metaData.

chalu
31 Mar 2008, 4:55 PM
The server response contains metadata, it's actually the same mateform sample php script, I just modified it a bit by putting field configuration into 'pages'


<?php

$formConfig = array(
"labelAlign"=>"right",
"columnCount"=>2,
"labelWidth"=>80,
"defaults"=>array(
"width"=>180,
"msgTarget"=>"side",
"labelSeparator"=>""
)
);
// this is our collection of pages for the wizard
$pages = array(
// this is the start page, aside form the index property, everything else will be for fileds configuration in this page
// if I can get this (panel) to render as it is then putting form fields should work also
array(
'index' => 0,
'html' => '<h1>Welcome to the Wizard!</h1><p>Step 1 of 5</p>'
),
array(
'index' => 1,
'html' => '<p>Step 2 of 3</p>'
),
array(
'index' => 2,
'html' => '<p>Step 3 of 3</p>'
)
);

$config = array(
"success"=>true,
"metaData"=>array(
// now we need to modify onMetaChange to loop through these panels, adding each
// to the card layout, and then loop through each panel's fields adding them to the
// panel, quite straight forward
"pages"=>$pages,
"formConfig"=>$formConfig
)
);
echo json_encode($config);

// end of file
?>

jsakalos
31 Mar 2008, 5:01 PM
The structure of metaData is mandatory and if you change it you cannot expect that MetaForm will work w/o changing onMetaChange function. I wouldn't go this direction. A wizard is sequence of forms so you can get config of each of them in separate requests changing only:

baseParams:{page:'page1'}
baseParams:{page:'page2'}

etc. Server-side has to recognize and process the page variable of course.

chalu
31 Mar 2008, 5:16 PM
I think I like this idea, I try it out and let you know the out come. Thank you very much.

chalu
31 Mar 2008, 5:44 PM
On a second thought, this looks like each page will be gotten from the server an created as it is navigated to, this is a wizard, the user may go back and forth in the navigation .. extra XHR. With this structure, what happens to page 1 when the response for the request for page 2 arrives, will page 1 get cleared up since onMetaChange calls removeAll as it's first action, if this is the case what happens in situations where we need wizard where all input are submmited to the server at the final page. Just thinking. Thanks

jsakalos
31 Mar 2008, 6:20 PM
Well, it depends on your design premises. MetaForm was not meant to be a part of wizard. Anyway, you can use the "standard" wizard technology and that is card layout, each card containing MetaForm that would request metaData only first time.

ray007
31 Mar 2008, 11:54 PM
There are 2 distinct and different situations:

- You know fields => FormPanel
- You don't know fields => MetaForm

Combination of them doesn't make sense.

The first time I'm showing a form, I probably need to load it all from the server, the second time I still might have cached metaData around from the first time.

Calling 'onMetaChange()' in initComponent() doesn't work, but starting initComponent with
if (this.metaData && this.metaData.fields) {
this.items = this.metaData.fields;
} else if (!this.items) {
this.items = {};
}
has at least partly solved my problems (I've added some more code to provide a default formConfig) ... now I only need to weld the forms to our COMET-implementation instead of standard extjs ajax calls - which seems to be more involved than I had initially thought ... :-?

jsakalos
1 Apr 2008, 4:36 AM
I use meta:true/false param that tells server to send/not-send metadata. If metadata is received the form is re-created but you can tell server in advance if you want to do so w/o any changes in MetaForm code.

chalu
8 Apr 2008, 9:29 PM
Hello Saki and all, did a little work on my wizard recently and wanted your comments on it so far (not near completion). I decided to implement my wizard, using composition in the cardlayout such that the collection of cards 'IS A' Metaform, this way the metaData is collected, for all the cards, once, the first time the wizard loads. The user can go back and forth anyhow and the implementation can do any logic in-between the navigation (I used some custom events). The only difference is that I am using a 'pages' array (though Saki warned against it =;) thus:



<?php

$formConfig = array(
"labelAlign"=>"left",
"columnCount"=>2,
"labelWidth"=>80,
"defaults"=>array(
"width"=>130
)
);

$fields = array(

);

$pages = array(
array(
'index' => 0,
'html' => '<h1>Page 1</h1>'
),
array(
'index' => 1,
'layout' => 'form',
'items' => array(
array(
'xtype' => 'textfield',
'fieldLabel' => "Company",
"name" => "compName",
"editor" => array(
"allowBlank"=>false
)
),
array(
'xtype' => 'textfield',
'fieldLabel' => 'Legal Form',
"name" => "compForm",
"editor" => array(
"allowBlank"=>false
)
),
array(
'xtype' => 'textarea',
'fieldLabel' => 'Description',
'name' => 'desc',
'width' => 250,
"editor" => array(
"allowBlank"=>false
)
)
)
),
array(
'index' => 2,
'items' => array(
'xtype' => 'fieldset',
'title' => 'Phone Number',
'collapsible' => true,
'autoHeight' => true,
'defaults' => array(
'width' => 220
),
'defaultType' => 'textfield',
'items' => array(
array(
'fieldLabel' => 'Home',
'name' => 'home',
'value' => '(888) 555-1212'
),
array(
'fieldLabel' => 'Business',
'name' => 'business'
),
array(
'fieldLabel' => 'Fax',
'name' => 'fax'
)
)
)
),
array(
'index' => 3,
'html' => '<h1>Page 4</h1>'
)
);

$config = array(
"success"=>true,
"metaData"=>array(
"pages"=>$pages,
'fields' => $fields,
"formConfig"=>$formConfig
),
"data"=>array(
"compName"=>"My Company",
"compNote"=>"Company Note",
"clientFrom"=>"1.2.08"
)
);

echo json_encode($config);

// end of file
?>

You can View Demo Here (http://www.petterson-clor.com/labs/ext_labs/wizard/)
and download my Tests Here (http://www.petterson-clor.com/labs/ext_labs/wizard/test.zip), Please take some time to look at what I have done.
This is not definitive, I am still developing and evaluating my choices which is why this post is here, (need useful criticism). Notice that with a simple structure we are able to create the fields (w/o complicated loops), though our editor, validation rules ( and maybe other things like regex, plugins etc ) seem not to be working yet ??

amic
13 Apr 2008, 11:43 AM
Hi there,

since I found metadata I found, what I was seeking for - providing form details to the client from the PHP script. But from time to time I receive the following error. It's strange because sometimes it works fine and then, suddenly, the error occurs:



uncaught exception: [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMNSHTMLDocument.designMode]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://localhost/client/desktop/extjs/ext-all.js :: anonymous :: line 136" data: no]


Do you have any idea why this occurs?

The response is generated with the following code:



$formConfig = array(
"labelAlign"=>"left"
,"columnCount"=>2
,"labelWidth"=>80
);
$fields = array(
// company name
array(
"name"=>"compName2"
,"fieldLabel"=>"Company - Test"
,"editor"=>array(
"allowBlank"=>false
)
)
,array(
"name"=>"compName"
,"fieldLabel"=>"Company"
,"editor"=>array(
"allowBlank"=>false
)
)
,array(
"name"=>"compForm"
,"fieldLabel"=>"Legal Form"
,"editor"=>array(
"allowBlank"=>false
)
)
,array(
"name"=>"clientFrom"
,"fieldLabel"=>"Client Since"
,"editor"=>array(
"xtype"=>"datefield"
,"format"=>"j.n.y"
)
)
,array(
"name"=>"clientTill"
,"fieldLabel"=>"Client Till"
,"editor"=>array(
"xtype"=>"datefield"
,"format"=>"j.n.y"
)
)
,array(
"name"=>"compNote"
,"fieldLabel"=>"Note"
,"editor"=>array(
"xtype"=>"htmleditor"
)
)
);
$config = array(
"success"=>true
,"metaData"=>array(
"fields"=>$fields
,"formConfig"=>$formConfig
)
,"data"=>array(
"compName"=>$this->Server->GetAttributeValue($objId, "Firstname")
,"compName2"=>$this->Server->GetAttributeValue($objId, "Lastname")
,"compNote"=>"Company Note"
,"clientFrom"=>"02/02/2008"
)
);
return json_encode($config);


Could it be a timing problem? The exception is fired when opening a window on the desktop takes longer then normal. As soon this IS the case once, the exception is fired every time I reopen the form.

Would be great if you could help me with this issue.

Thanks
Mike

jsakalos
13 Apr 2008, 11:47 AM
Look like code is accessing an element that is not (yet?) in the DOM...

BTW, you should send metaData only once for form to configure; all subsequent request should contain data only unless you need to re-configure the form.

chalu
17 Apr 2008, 6:04 AM
Please take a look at this :
Use of Metaform (http://extjs.com/forum/showthread.php?p=154512#post154512)

amic
27 Apr 2008, 9:02 AM
Is there anything I can do about this error?

I was looking for a way of how to pass form and data to the client from a PHP script. MetForm seemed to be the solution - but right now it's not possible to use it.

jsakalos
27 Apr 2008, 12:48 PM
You would need to find out which element is accessed too early and why.

chalu
27 Apr 2008, 7:34 PM
uncaught exception: [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMNSHTMLDocument.designMode]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://localhost/client/desktop/extjs/ext-all.js :: anonymous :: line 136" data: no]

I usually have this error when I make an XHR / Ajax call and forget to provide a URL for the request object, I experienced it once with metaform and never had it again after fixing the URL

craigharmonic
27 Apr 2008, 9:02 PM
I found your MetaForm extension and had it up and going in no time, thank you very much.

I was wondering how I handle a failure coming back from the server. So some JSON like:

{"success":false}

I'd like to display some sort of error message to the user telling them what has happened. Could you suggest a way to do this? Basically I want to do something like:

{"success":false,"errorMessage:":"Could not retrieve form data."}

Then display errorMessage to the user rather than the form.

Thanks!

jsakalos
28 Apr 2008, 2:10 AM
It is not exactly same but I hope will help you: http://examples.extjs.eu/?ex=formloadsubmit

craigharmonic
28 Apr 2008, 7:13 PM
I had a look at your example (thanks) but this seems to be for processing failure on form submit. I want to handle the error if (for whatever reason) the retrieval of the form metadata does not get received from the server correctly (I send back a "success":false in this case).

Your submit function seems to set a failure function, which I tried to imitate for the metaForm with the following config lines:



failure:function() {
alert('error');
},


Then i returned {"success":false} but the function did not fire.

jsakalos
29 Apr 2008, 3:21 AM
Process {success:false} in success function. Does it get called?

thewebguy
29 Apr 2008, 2:13 PM
I have some pre-configured combos for this purpose in my application so all I need to send from server is xtype.

See Application Design Based On Pre-Configured Classes (http://extjs.com/forum/showthread.php?p=125476) for more details on how to create such components.

Maybe I'm just being dense, but...

I'm confused as to how preconfigured classes buys you anything in using a MetaForm. My whole purpose of the MetaForm was to extract the 'business layer' from the JavaScript and configure it from the PHP-end. The comboboxes I intend to use have values that really have no business in a .js file.

If I am reading this right, you're saying I have to predefine the classes in Javascript and then all PHP's job is at that point is to provide xtypes to a form. How is that much different from just defining a FormPanel with the fields defined in there?

jsakalos
29 Apr 2008, 2:19 PM
Well, it's up to you if you use MetaForm or not...

chalu
30 Apr 2008, 1:48 AM
I have some issues with the Ext 2.1 combo store creation using arrays, I am trying to make combo's, by providing a store for it's editor with json response. This test case has not worked for me, please have a look at it Here (http://www.extjs.com/forum/showthread.php?p=161738#post161738)

thewebguy
30 Apr 2008, 5:14 AM
Well, it's up to you if you use MetaForm or not...

Umm... right, but in your initial post, you said the purpose of the MetaForm is to define the form's properties on the PHP side... then later on you say the way to use it is to define the form elements on the javascript side. I'm just pointing out a contradiction in what this class is supposed to do. Surely there's a way to define a set of form fields in JSON format that a form will implement.

EDIT: Ah, I figured out my problem, at least... just needed to upgrade to Ext2.1 in order to take advantage of passing combos via JSON. :)

jsakalos
30 Apr 2008, 9:10 AM
I'm saying that you can use PHP to tell Ext which building blocks to use and you are calling for PHP to create building blocks. That's the difference.

boonkerz
30 Apr 2008, 12:36 PM
Hello,

Thanks for the nice plugin.
is it possible to user an tabpanel with metaform?

Thx

jsakalos
30 Apr 2008, 3:25 PM
No, it was designed to be K.I.S.S. You can configure only number of columns.

Duxer
1 May 2008, 9:29 PM
Hello, Jozef!
I have trouble - columnCount in formConfig is not applying. I've try add to formconfig.php this:


$formConfig2 = array(
"columnCount"=>2
);

$config = array(
"success"=>true
,"metaData"=>array(
"fields"=>$fields
,"formConfig"=>$formConfig
,"formConfig2"=>$formConfig2 // <- add
)
,"data"=>array(
"compName"=>"My Company"
,"compNote"=>"Company Note"
,"clientFrom"=>"1.2.08"
)
);

and in MetaForm.js in onMetaChange (before adding Panel) this:


Ext.apply(this, meta.formConfig2, {});

as a result - fields are in 2 columns.
(Tested on v2.02 and v2.1)

Why it may not work?

jsakalos
2 May 2008, 1:02 AM
It was bug in fact; I've fixed it right now. Grab the code from the first post.

chalu
2 May 2008, 7:56 AM
MetaForm forces one to always use a 'data' property in the response from the server, even in the response to a submit where we just want to indicate success or failure, else it assumes it's a load failure :


beforeAction:function(form, action) {
action.success = function(response) {
var result = this.processResponse(response);
if(result === true || !result.success || !result.data){
this.failureType = Ext.form.Action.LOAD_FAILURE;
this.form.afterAction(this, false);
return;
}

this.form.afterAction(this, true);
this.form.clearInvalid();
this.form.setValues(result.data);
}

Take A Look At This (http://www.extjs.com/forum/showthread.php?p=163159#post163159).

amic
2 May 2008, 8:14 AM
Hi,

I tracked down the issue and found out that the error occurs in the call


"this.doLayout();"
(approx. line 331)

It's interesting, cause if I place an alert('Text'); right before the call, the alert box pops up and the error never occurs. If I remove the allert() call, the exception comes up.

Does this help you?

chalu
2 May 2008, 8:22 AM
I have tried to make metaform accept fieldsets, it works so far but breaks other things :
1. Loading message sometimes shows under the window's title bar
2. Saving message never shows up
3. Client side validation is no longer respected.

I am still, working on it, you can assist with the test case:

jsakalos
3 May 2008, 2:28 AM
MetaForm forces one to always use a 'data' property in the response from the server, even in the response to a submit where we just want to indicate success or failure, else it assumes it's a load failure :


beforeAction:function(form, action) {
action.success = function(response) {
var result = this.processResponse(response);
if(result === true || !result.success || !result.data){
this.failureType = Ext.form.Action.LOAD_FAILURE;
this.form.afterAction(this, false);
return;
}

this.form.afterAction(this, true);
this.form.clearInvalid();
this.form.setValues(result.data);
}
Take A Look At This (http://www.extjs.com/forum/showthread.php?p=163159#post163159).
It is explained in the comment of beforeAction function. Hardcoded data property comes from underlying Action class.

craigharmonic
4 May 2008, 9:48 PM
Process {success:false} in success function. Does it get called?

I just added:


success:function() {
alert('success');
},

Into the metaform config and it does not fire at all. Can I do this here or do I have to do it in the metaform javascript itself?

jsakalos
5 May 2008, 1:26 AM
I've meant sth like:



form.load({
success:function(...){...}
,failure:function(...){...}
, // ....
});

treqx
5 May 2008, 12:19 PM
Hi,

Would it be possible to use DWR to retrieve the metadata with this extension?

Thanks,
Michel

jsakalos
5 May 2008, 3:33 PM
If I knew what is DWR....;) I expect it is a server side framework. If so, then answer is yes as far as it can deliver JSON in correct format.

craigharmonic
5 May 2008, 10:41 PM
I've meant sth like:



form.load({
success:function(...){...}
,failure:function(...){...}
, // ....
});


Thank you so much, that worked. I am also now trying to configure the look of the form. can this be done in the config? I tried the following in the meta form config object:



bodyStyle:'background-color:#ffffff'


But this results in the background of the area inside the metaform "window" being white, and I want to remove/hide the whole window/panel the form comes in. I have attached an image to explain what I mean. In the attachment I would like no border around the form and the light blue area to be white. Am I puttng the style info in the wrong place?

Thanks again for all your help and your great metaform!

jsakalos
6 May 2008, 1:19 AM
MetaForm extends FormPanel so surrounding Window is not necessary. You can place it wherever you want.

treqx
7 May 2008, 8:06 AM
Hi Jozef,

Thank you for yet another great extension.

I have a question, the ordering within objects seems to matter in the JSON response, shoud it be so?

I use the java library from json.org to generate the output (I put DWR on the backburner for now) and since the JSON spec stipulates that a JSON object is unordered, the code does not always generate your sample in the same order (keys in each object can be in a different order).

I tried with the hardcoded JSON output in your sample and everything works fine but I use the generated one (where the order is different), the window remains empty and there are no errors in Firebug.

Thanks,
Michel

jsakalos
7 May 2008, 11:29 AM
Yes, fields are generated in the order they are received. I know nothing about DWR but PHP's json_encode always honors the order in which the object/array being encoded has been defined.

pokerking400
8 May 2008, 7:15 AM
Fantastic. This is what i am looking for. I was going nowhere with your recordform plugin as that is not usable for me.

This little example is the one i am looking for. Basically i wanted to use same data sore info i am sending grid to use it for forms as well.

Even editing grid will send a request to server and return with one record.

I do not want to put any UI elements in server. That is aefully bad design. I am only sending generic data , may be one type of editor based on the format. That is because database has that info , i am just propagating it to UI.

I need to redesign your example to create a render object to render the fields. Single colum , double colum or form with tabs.

1. Basic form rendering is with single , dual and ..
2. One one Forms Kind of person with office address and home address ( kind of drop down to save space.
3. One to many if the result set has Object inside then grid will be created and reloaded with child data.

That is the idea. I have to do it by this week. That is my own goal. We will see.

Thanks again for the example. I wasted two days searching ..you hav eto put this in your example website as well. It is simple but for nebies like me any thing simple is good.

pokerking400
8 May 2008, 1:32 PM
hi saki ,

what meta data i have to send to create this form?.

bd.createChild({tag: 'h2', html: 'Form 5 - ... and forms can contain TabPanel(s)'});


var tab2 = new Ext.FormPanel({
labelAlign: 'top',
title: 'Inner Tabs',
bodyStyle:'padding:5px',
width: 600,
items: [{
layout:'column',
border:false,
items:[{
columnWidth:.5,
layout: 'form',
border:false,
items: [{
xtype:'textfield',
fieldLabel: 'First Name',
name: 'first',
anchor:'95%'
}, {
xtype:'textfield',
fieldLabel: 'Company',
name: 'company',
anchor:'95%'
}]
},{
columnWidth:.5,
layout: 'form',
border:false,
items: [{
xtype:'textfield',
fieldLabel: 'Last Name',
name: 'last',
anchor:'95%'
},{
xtype:'textfield',
fieldLabel: 'Email',
name: 'email',
vtype:'email',
anchor:'95%'
}]
}]
},{
xtype:'tabpanel',
plain:true,
activeTab: 0,
height:235,
defaults:{bodyStyle:'padding:10px'},
items:[{
title:'Personal Details',
layout:'form',
defaults: {width: 230},
defaultType: 'textfield',

items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank:false,
value: 'Jack'
},{
fieldLabel: 'Last Name',
name: 'last',
value: 'Slocum'
},{
fieldLabel: 'Company',
name: 'company',
value: 'Ext JS'
}, {
fieldLabel: 'Email',
name: 'email',
vtype:'email'
}]
},{
title:'Phone Numbers',
layout:'form',
defaults: {width: 230},
defaultType: 'textfield',

items: [{
fieldLabel: 'Home',
name: 'home',
value: '(888) 555-1212'
},{
fieldLabel: 'Business',
name: 'business'
},{
fieldLabel: 'Mobile',
name: 'mobile'
},{
fieldLabel: 'Fax',
name: 'fax'
}]
},{
cls:'x-plain',
title:'Biography',
layout:'fit',
items: {
xtype:'htmleditor',
id:'bio2',
fieldLabel:'Biography'
}
}]
}],

buttons: [{
text: 'Save'
},{
text: 'Cancel'
}]
});

tab2.render(document.body);
});


This is the dynamic form with tabpanels. Once i able to create this , that will be the first step , then i have to create content for the tabs later.

I want to use your sample meta data to create this , how do i do it?

Big Thanks!

jsakalos
8 May 2008, 1:35 PM
Just follow the example written in PHP from the first post.

pokerking400
8 May 2008, 9:25 PM
That is a plain form. I want to add tab panel to existing form. How do i do that through metadata

jsakalos
9 May 2008, 1:25 AM
Then you are on your own. MetaForm doesn't support tabs at present.

pokerking400
9 May 2008, 2:29 AM
Not a problem. I am just checking whether someone has done the thing i am looking for, then i can build upon it.

Thanks for the reply anyway.

Duxer
9 May 2008, 5:13 AM
Hello Jozef!

I define small xtype - this is label + radio button 'yes' and radio button 'no' based on panel. And I try to set value in this field from JSON as for other, but it is not working... Can you give me some advice what should there present to set value?


/**
*
* @class Ext.ux.YesNoRadio
* @extends Ext.Panel
*/

Ext.ux.YesNoRadio = Ext.extend(Ext.Panel, {

fieldLabel:'',
labelWidth:80,
value:true,

initComponent:function() {
Ext.apply(this, {
border:false
,layout:'absolute'
,height:20
,width:this.labelWidth + 100
,style:'font-size:12px;'
,items:[
{
x:0
,y:0
,xtype:'label'
,text: this.fieldLabel
},
{
x: this.labelWidth + 5
,y:0
,xtype:'radio'
,boxLabel:'Yes'
,checked: (this.value == true)
,name:this.name
,inputValue:1
},
{
x: this.labelWidth + 50
,y:0
,xtype:'radio'
,boxLabel:'No'
,checked: (this.value == false)
,name:this.name
,inputValue:0
}]
});

// call parent initComponent
Ext.ux.YesNoRadio.superclass.initComponent.call(this);

} // end of function initComponent

});

// register xtype
Ext.reg('yesnoradio', Ext.ux.YesNoRadio);

// end of file

jsakalos
9 May 2008, 5:18 AM
Off the top of my head: You should set value instead of inputValue. All form controls understand value - if it is present in config then it is set as value of field.

pokerking400
9 May 2008, 9:33 AM
OnMetaChange ...

i need something like this when it sees fieldset...i don't know exact stuff i have to do to get new fields



if('fieldset' === config.xtype) {
Ext.apply(config, {
xtype:'fieldset',
checkboxToggle:true,
title: 'User Information2',
width:400,
height:300,
defaults: {width: 210},
collapsed: true,
items :{
xtype:'metaform'
,title:'Ext.ux.MetaForm1'
,url:'/recordform/formconfig1.php'
}
});
}


or


if('fieldset' === config.xtype) {
Ext.apply(config, {
xtype:'fieldset',
checkboxToggle:true,
title: 'User Information2',
width:400,
height:300,
defaults: {width: 210},
collapsed: true,
items :{
url:'/recordform/formconfig1.php'
}
});
}

pokerking400
9 May 2008, 3:17 PM
I want to add another set of tabs (tabpanel) to metaform. Any idea how i add ?.

I did add Fieldset successfully. But adding any panel throws me this error.

types[config.xtype || defaultType] is not a constructor


if('formPanel' === config.xtype) {
Ext.apply(config, {
xtype: "FormPanel",
labelWidth: 75,
url:'save-form.php',
frame:true,
title: 'Simple Form',
bodyStyle:'padding:5px 5px 0',
width: 350,
defaults: {width: 230},
defaultType: 'textfield',

items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank:false
},{
fieldLabel: 'Last Name',
name: 'last'
},{
fieldLabel: 'Company',
name: 'company'
}, {
fieldLabel: 'Email',
name: 'email',
vtype:'email'
}, new Ext.form.TimeField({
fieldLabel: 'Time',
name: 'time',
minValue: '8:00am',
maxValue: '6:00pm'
})
]
});

}

Any advise is welcome. My methods are probably wrong but i would like to have tab panel Form like in dynamic.html examples.
:)

pokerking400
9 May 2008, 3:36 PM
oh i got it..i have to use smaller case letters like panel , tabpanel in xtype..

How do i add hidden elements in extjs?. My child tabs need hidden master primary key for submission.

Thanks...

I am moving forward inch by inch...:)

jsakalos
10 May 2008, 2:51 AM
You don't need hidden fields; you can post values back to server in params object.

pokerking400
10 May 2008, 5:51 AM
hidden fields are coming from server , all automatic. So can't write that into params. Planning on keeping few form templates for all types of forms.

There will be always specialized forms here and there . But mosly i want to keep two or three formtemplates to manage generic objects management.

thanks.

pokerking400
13 May 2008, 6:23 AM
It is funny newbie like me asks most stupidest questions again and again....hahaha...going back to my old questions make me laugh...

People need patience to answer all the questions...

Anyway i am using same Metadata fields as autogrid. Basically i am using autogrid and metaform and take the best out of both...

I am stuck in one place...i am trying to load a combo box...in metaform...i hav eto figure it out how i do it. At present xtype:'combo' shows plain combo and i have to load its contents through ajax.

Anyway i will figure it out.

Saki's examples gives me ideas...of how extjs works...he should write a book even though i think his examples are over designed....

I really think all widgets need new architecture to allow plugins for doing different actions.
Instead of extending things...have a core Widget and add plugins to it.

ok ok..i have to figure out how i am going to fix my combobox issue...

laters...

jsakalos
13 May 2008, 8:13 AM
Do it as described here: Writing a Big Application in Ext (http://extjs.com/forum/../learn/Tutorial:Writing_a_Big_Application_in_Ext)

pokerking400
13 May 2008, 8:18 AM
hi saki,

why my combobox head is not showing up?. it shows up when i press down arrow on the filed..

The code...

config = Ext.apply({}, item.editorcfg, {
name:item.name || item.dataIndex
,fieldLabel:item.fieldLabel || item.header
,defaultValue:item.defaultValue
,layout:'fit'
,xtype:'combo'
,displayField:'name'
,valueField: "id"
,triggerAction:'all'
,typeAhead:true
,mode:'remote'
,hiddenName : 'country_id1'
,listClass:'x-combo-list-small'
,emptyText:'Select Country...'
,store: new Ext.data.JsonStore({
autoLoad: true,
root:'records',
totalProperty:'totalCount',
fields:["id","name"],
url:'/reference/boards',
id:"id"
})
,hideTrigger:true
});

Advance thanks for your reply.

I went through your link ..i am not there yet .. i am in learning mode..cut and paste and make it work first and then think about clean it up....hahahaha....if i don't know full ability of extjs , i can't really do architect things...so another month of trial and error...also i do things my own way and use every one ideas and morph into my own concept. At present i am in EXTJS learning mode ...so far some part of Autogrid , some part of metaform...basically concept behind those two and making things my own...at presnet i am stuck at the combobox display thingy..it shows like textfield in the grid and form...why?.

pokerking400
13 May 2008, 8:33 AM
SOLVED!. This is what happen when you cut and paste stuff...hhahahaha... it happened because hidetrigger:true.... commented it and combobox back in action...

Next is field set ...

laters,

EShy
14 May 2008, 2:12 PM
really nice saki

I've been working on upgrading an old form creation javascript to use with extjs, and this code might do it or at least be a great base for what I need.

thanks for all your work

tmartinez
19 May 2008, 9:08 AM
Hello,
i'm trying to make a form based on a database table.
The creation of the form work quite well but the problem is when i want to load some datas (from a database via JSON) into my fields. I don't know exactly where i must put the Reader ??
This is my example code:
index.html


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="../resources/css/ext-all.css">
<script type="text/javascript" src="../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext-all-debug.js"></script>
<script type="text/javascript" src="Ext.ux.MetaForm.js"></script>
<script type="text/javascript" src="ComboBox.js"></script>

<!-- A Localization Script File comes here -->
<script type="text/javascript">
Ext.onReady(function() {
var myReader; //reader
var myRecordObj;
var primaryKey='companyID';
myRecordObj = Ext.data.Record.create([
{name: primaryKey},//this corresponds to 'companyID', I assigned a
{name: 'societe_id'},
{name: 'raison'},
{name: 'stype'},
{name: 'sigle'},
{name: 'adresse1'},
{name: 'adresse2'},
{name: 'adresse3'},
{name: 'copost'},
{name: 'ville'},

]);
myReader = new Ext.data.JsonReader( //creates array from JSON response
/**
* The 1st parameer for the reader constructor is to specify the
* reader's config options:
*/
{

root: 'results', //delimiter tag for each record (row of data)
totalProperty: 'total',//element containing total dataset size (opt
id: primaryKey //used several times so a Private Variable is used
},
myRecordObj//pass a reference to the object
);
var win = new Ext.Window({
id:'metaform-win'
,layout:'fit'
,width:500
,height:300
,title:'Ext.ux.MetaForm'
,items:{

xtype:'metaform'
,url:'formconfig.php'
,buttons:[{
text:'Load'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().load({url: '../retrieve-php.php?task=readEU&societe_id=17128',
method: 'POST'});
}
},{
text:'Submit'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().submit();
}
}]
}
});

win.show();
});
</script>
<title>Ext.ux.MetaForm Example</title>
</head>
<body>
</body>
</html>
my formconfig.php
[php]
<?php
$mysql_id = mysql_connect('localhost', 'root', '');
mysql_select_db('test');
$res = mysql_query("select * from fields" );

$fields_total=array();
while ($res1 = mysql_fetch_row($res)) {
$id_champs=$res1[0];
$nom=$res1[1];
$nom_affichage=$res1[2];
$type=$res1[3];
$store=$res1[4];
$validation=$res1[5];
if($res1[6]=1){
$hidden=false;
}else{
$hidden=true;
}
if($res1[7]=1){
$modifiable="true";
}else{
$modifiable="false";
}
if($res1[8]=1){
$obligatoire="false";
}else{
$obligatoire="true";
}
$ctrl_cdl=$res1[9];

//mysql_free_result($res2);
switch($type){
case "combo":
$store_total=array(array("id","valeur"));
$res2 = mysql_query("select * from ".$store );
$store_head=array("id"=>"id","valeur"=>"valeur");
$i=0;
$j=0;
while ($res3 = mysql_fetch_row($res2)) {
$id=$res3[0];
$nom_val=$res3[1];
$store3=array(array($id,$nom_val));
$store_total=array_merge($store_total,$store3);
$i++;
$fields2=array(array(
'id' => $id_champs,
'hiddenName' => $nom,
'name' => $nom,
'hidden' => false,
'disable' =>true,
'fieldLabel' => $nom_affichage,
'width' => 140,
'allowBlank' => $obligatoire,
'editable' => $modifiable,
'xtype' => $type,
'typeAhead' => false,
'triggerAction'=>'all',
'disableKeyFilter' => true,
'store' => $store_total
));

}
break;
case "textfield":
$fields2=array(array(
'id' => $id,
'hiddenName' => $name,
'name' => $name,
'hidden' => $hidden,
'fieldLabel' => $nom_affichage,
'width' => 140,
'allowBlank' => $obligatoire,
'editable' => $modifiable,
'xtype' => $type

));
break;
}
$fields_total=array_merge($fields_total,$fields2);

}
mysql_free_result($res);


$formConfig = array(
"reader" => "MyReader",
"labelAlign" => "right",
"columnCount" => 2,
"labelWidth" => 120,
"defaults" => array(
"width"=> 180 ,
"msgTarget" => "side",
"labelSeparator" => '',
'labelStyle' => 'padding-top:5px'
)
);
$fields = array(
array(
'xtype' => 'fieldset',
'autoHeight' => true,
'width' => 400,
'collapsible' => false,
'title' => 'Bloc Soci

jsakalos
19 May 2008, 9:16 AM
Form data has to have format:


{"success":true,"data":{"name":"value","name2":"value2",...}}


and you don't need any reader.

tmartinez
19 May 2008, 9:34 AM
Thanks you for you very fast reply.
I'v tried but that doesn't work anyway.
Now when i load data i have this firebug message:


{"success":true,"data":{"raison":"azerty"}}

but into the textfield called 'raison' nothing appear...

jsakalos
19 May 2008, 10:12 AM
Take a look at this example to see how it is done for normal form: http://examples.extjs.eu/?ex=formloadsubmit

boonkerz
21 May 2008, 3:03 PM
Hi

I have implemented Tabpanel but how i can load data in this tabs?

i add an tabpanel and then an panel for each tab. submit works but i can not load data into this.



// vim: ts=4:sw=4:nu:fdc=4:nospell
/**
* Ext.ux.MetaForm
*
* @author Ing. Jozef Sakalos
* @copyright (c) 2008, by Ing. Jozef Sakalos
* @date 6. February 2007
* @version $Id: Ext.ux.MetaForm.js 80 2008-03-20 00:44:36Z jozo $
*
* @license Ext.ux.MetaForm is licensed under the terms of
* the Open Source LGPL 3.0 license. Commercial use is permitted to the extent
* that the code/component(s) do NOT become part of another Open Source or Commercially
* licensed development library or toolkit without explicit permission.
*
* License details: http://www.gnu.org/licenses/lgpl.html
*/

// isArray is in SVN only
if(!Ext.isArray) {
Ext.isArray = function(v) {
return v && 'function' == typeof v.pop;
}
}

/**
*
* @class Ext.ux.MetaForm
* @extends Ext.FormPanel
*/
Ext.ux.MetaForm = Ext.extend(Ext.FormPanel, {
// configurables
autoInit:true
,border:false
,frame:true
,loadingText:'Loading...'
,savingText:'Saving...'
,buttonMinWidth:90
,columnCount:1
,layout: 'column'
/**
* createButtons {Array} array of buttons to create
* valid values are ['meta', 'load', defaults', 'reset', 'save', 'ok', 'cancel']
*/
/**
* ignoreFields: {Array} of field names to ignore when received in metaData
*/

// {{{
,initComponent:function() {

// create one item to avoid error
Ext.apply(this, {
items:this.items || {}
}); // eo apply

// get buttons if we have button creation routines
if('function' == typeof this.getButton) {
this.buttons = this.getButtons();
}

// call parent
Ext.ux.MetaForm.superclass.initComponent.apply(this, arguments);

this.addEvents('cancel', 'ok');

// install event handlers on basic form
this.form.on({
beforeaction:{scope:this, fn:function(form, action) {
this.beforeAction(this, action);
}}

,actioncomplete:{scope:this, fn:function(form, action) {
// (re) configure the form if we have (new) metaData
if('load' === action.type && action.result.metaData) {
this.onMetaChange(this, action.result.metaData);
}
// update bound data on successful submit
else if('submit' == action.type) {
this.updateBoundData();
}
}}
});
this.form.trackResetOnLoad = true;

} // eo function initComponent
// }}}
// {{{
/**
* private, changes order of execution in Ext.form.Action.Load::success
* to allow reading of data in this server request (otherwise data would
* be loaded to the form before onMetaChange is run from actioncomplete event
*/
,beforeAction:function(form, action) {
action.success = function(response) {
var result = this.processResponse(response);
if(result === true || !result.success || !result.data){
this.failureType = Ext.form.Action.LOAD_FAILURE;
this.form.afterAction(this, false);
return;
}
// original
// this.form.clearInvalid();
// this.form.setValues(result.data);
// this.form.afterAction(this, true);

this.form.afterAction(this, true);
this.form.clearInvalid();
this.form.setValues(this.data);
};
} // eo function beforeAction
// }}}
// {{{
/**
* @param {Object} data A reference to on external data object. The idea is that form can display/change an external object
*/
,bind:function(data) {
this.data = data;
this.form.setValues(this.data);
} // eo function bind
// }}}
// {{{
/**
* override this if you want a special buttons config
*/
,getButtons:function() {
var buttons = [];
if(Ext.isArray(this.createButtons)) {
Ext.each(this.createButtons, function(name) {
var button;
switch(name) {
case 'meta':
button = this.getButton(name, {
handler:this.load.createDelegate(this, [{params:{meta:true}}])
});
break;

case 'load':
button = this.getButton(name, {
scope:this
,handler:this.load
});
break;

case 'defaults':
button = this.getButton(name, {
scope:this
,handler:this.setDefaultValues
});
break;

case 'reset':
button = this.getButton(name, {
scope:this
,handler:this.reset
});
break;

case 'save':
case 'submit':
button = this.getButton(name, {
handler:this.submit.createDelegate(this, [{params:{cmd:'setPref'}}])
});
break;

case 'ok':
button = this.getButton(name, {
scope:this
,handler:this.onOk
});
break;

case 'cancel':
button = this.getButton(name, {
scope:this
,handler:this.onCancel
});
break;
}
if(button) {
Ext.apply(button, {
minWidth:this.buttonMinWidth
});
buttons.push(button);
}
}, this);
};
return buttons;
} // eo function getButtons
// }}}
// {{{
,getOptions:function(o) {
var options = {
url:this.url
,method:this.method || 'post'
};
Ext.apply(options, o);
options.params = Ext.apply(this.baseParams || {}, o.params);
return options;
} // eo function getOptions
// }}}
// {{{
/**
* @return {Object} object with name/value pairs using fields.getValue() methods
*/
,getValues:function() {
var values = {};
this.form.items.each(function(f) {
values[f.name] = f.getValue();
});
return values;
} // eo function getValues
// }}}
// {{{
,load:function(o) {
var options = this.getOptions(o);
if(this.loadingText) {
options.waitMsg = this.loadingText;
}
this.form.load(options);
} // eo function load
// }}}
// {{{
/**
* cancel button handler - fires cancel event only
*/
,onCancel:function() {
this.fireEvent('cancel', this);
} // eo function onCancel
// }}}
// {{{
/**
* Override this if you need a custom functionality
*
* @param {Ext.FormPanel} this
* @param {Object} meta Metadata
* @return void
*/
,onMetaChange:function(form, meta) {
this.removeAll();

// declare varables
var columns, colIndex, tabIndex, ignore = {};

// add column layout
this.add(new Ext.TabPanel({
activeTab: 0,
frame: true,
autoWidth: true,
layoutOnTabChange: true
}));

tabIndex = 0;

if(Ext.isArray(this.ignoreFields)) {
Ext.each(this.ignoreFields, function(f) {
ignore[f] = true;
});
}
// loop through metadata colums or fields
// format follows grid column model structure
Ext.each(meta.columns || meta.fields, function(item) {
if(true === ignore[item.name]) {
return;
}

this.items.get(0).add(new Ext.Panel({
title: item.general.title,
layout:'form',
defaults: {width: 230},
defaultType: 'textfield'
}));

colIndex = 0;

columns = this.items.get(0).items.get(tabIndex);

Ext.each(item.fields, function(field) {



if(field.editor.regex){
//alert(item.editor.regex);
field.editor.regex= new RegExp(field.editor.regex);
}
var config = Ext.apply({}, field.editor, {
name:field.name || field.dataIndex
,fieldLabel:field.fieldLabel || field.header
,defaultValue:field.defaultValue
,xtype:field.editor && field.editor.xtype ? field.editor.xtype : 'textfield'
});

// handle regexps
if(config.editor && config.editor.regex) {
config.editor.regex = new RegExp(field.editor.regex);
}

// to avoid checkbox misalignment
if('checkbox' === config.xtype) {
Ext.apply(config, {
boxLabel:' '
,checked:field.defaultValue
});
}

if('combo' === config.xtype) {
Ext.apply(config, {
store: new Ext.data.JsonStore({
url: '/service/?mode=' + config.service,
root: 'items',
fields: ['name', 'label']
}),
mode: 'remote',
triggerAction: 'all',
selectOnFocus:true,
valueField:'name',
displayField:'label'

});
}
if(meta.formConfig.msgTarget) {
config.msgTarget = meta.formConfig.msgTarget;
}

// add to columns on ltr principle
columns.add(config);
colIndex = colIndex == this.columnCount ? 0 : colIndex;

}, this);
tabIndex = tabIndex+1;
}, this);

this.doLayout();
} // eo function onMetaChange
// }}}
// {{{
,onOk:function() {
this.updateBoundData();
this.fireEvent('ok', this);
}
// }}}
// {{{
,onRender:function() {
// call parent
Ext.ux.MetaForm.superclass.onRender.apply(this, arguments);

this.form.waitMsgTarget = this.el;

if(true === this.autoInit) {
this.load({params:{meta:true}});
}
else if ('object' == typeof this.autoInit) {
this.load(this.autoInit);
}
} // eo function onRender
// }}}
// {{{
/**
* private, removes all items from both formpanel and basic form
*/
,removeAll:function() {
// remove border from header
var hd = this.body.up('div.x-panel-bwrap').prev();
if(hd) {
hd.applyStyles({border:'none'});
}
// remove form panel items
this.items.each(this.remove, this);

// remove basic form items
this.form.items.clear();
} // eo function removeAllItems
// }}}
// {{{
,reset:function() {
this.form.reset();
} // eo function reset
// }}}
// {{{
,setDefaultValues:function() {
this.form.items.each(function(item) {
item.setValue(item.defaultValue);
});
} // eo function setDefaultValues
// }}}
// {{{
,submit:function(o) {
var options = this.getOptions(o);
if(this.savingText) {
options.waitMsg = this.savingText;
}
this.form.submit(options);
} // eo function submit
// }}}
// {{{
,updateBoundData:function() {
if(this.data) {
Ext.apply(this.data, this.getValues());
}
} // eo function updateBoundData
// }}}

});

// register xtype
Ext.reg('metaform', Ext.ux.MetaForm);

// eof

jsakalos
21 May 2008, 4:16 PM
No idea, I've never looked in the direction of tabs in MetaForm.

boonkerz
21 May 2008, 4:21 PM
Ok

Have you an idea where i can search?

Formpanel
-- Tabpanel
---- Panel
---- Panel

jsakalos
21 May 2008, 4:25 PM
Docs or Forums. I personally don't use tabbed forms so I have no experiences.

dante
4 Jun 2008, 4:31 AM
Hello Saki,

did you ever check if there is any kind of memory leak after having supplied new metadata for an existing metaform? I am a little afraid that onMetaChange() does not really free up all memory having been used for the former form fields.. that wouldn't be a problem caused by your wonderful metaform, but rather by the browser (or maybe even ext itself).

I would like to use metaform in an application and it can happen that the form gets meta-changed fairly often so that would be a crucial issue.

jsakalos
4 Jun 2008, 5:22 AM
onMetaChange calls method removeAll, which calls Form's remove in turn, that should take care about cleanup. I've not tested mem leaks though.

ismell
9 Jun 2008, 8:07 AM
Here is a getButton for the lazy people. I just added it as part of the MetaForms plugin. Then if you need specific functions you can overwrite this one.

,getButton: function(name, config) {
var button = {
'text': Ext.util.Format.capitalize(name)
}
Ext.apply(button, config);
return button;
}
Great plugin!

mystix
9 Jun 2008, 8:24 AM
@ismell, there's a built-in Ext.util.Format.capitalize() method btw... B)

ismell
9 Jun 2008, 8:52 AM
Oh nice!
Source changed.

Also, I just realized how to make a local auto complete combo box. Very useful if you have a small predefined set of values. Thought it would be useful for all of us that are still learning :)

"fields":[{
"name":"empID",
"fieldLabel":"Employee",
"editor":{
"xtype": "combo"
,"mode": "local"
,"store": [
[314, "1356-Robert Golden"]
,[645, "1482-Gary Smith"]
,[586, "1937-Test User"]
]
,"allowBlank":false
}
}]


Ext Rocks!

sintax.era
25 Jun 2008, 8:48 PM
Hey guys, I just tried running the example and I get this error in firebug :)



types[config.xtype || defaultType] is not a constructor

return new types[config.xtype || defaultType](config);



I searched for a solution, and made sure the MetaForm.js was loaded and spelled correctly, But I just cannot seem to get it to work!
Damn! :P

Its throwing upon trying to register the type in ext-all-debug.js and when I hover over all the values they seem to be right...

sintax.era
25 Jun 2008, 8:53 PM
ok, I just copied the text from the metaform javascript file into the html file above the on ready function, and its working...
any ideas why its not processing the javascript?

jsakalos
26 Jun 2008, 5:23 AM
Looks like you have forgotten to copy Ext.reg(....) line.

scottpenrose
8 Jul 2008, 3:17 AM
Thanks great tool. I have a small problem on updating from metadata after a save.

I have the save handler like this:


form.getForm().submit({
waitMsg:'Saving Data...',
params: {
task: 'update'
}
});
form.getForm().load({
waitMsg:'Loading new data...'
});


Which works almost perfectly but suffers from two problems.


It is loading the data twice. After the save I already return a new metaData, which does not get used. So I am calling load which loads it again, which means two requests instead of one.
If the save fails (e.g. success: false with error list) the form updates and shows the errors but then reloads anyway (this one is more obvious. If I force a load then of course it will reload, so I suspect this one may go away with the solution for 1).
My question is. How can I do an update of the metaData after a save. It is an easy one line addition to the class, but I would rather leave it as the original and do it here.

Thanks

Scott

jsakalos
8 Jul 2008, 6:44 AM
submit and load start asynchronous process so execution of the code immediately continues after submit with load.

scottpenrose
8 Jul 2008, 1:25 PM
submit and load start asynchronous process so execution of the code immediately continues after submit with load.

I thought that might be the case. Thanks.

So how do I get submit to do a metaData refresh?

Thanks

SCott

jsakalos
8 Jul 2008, 9:45 PM
You don't need to refresh metaData unless you want to reconfigure the form, to change fields. If you really need to change fields then the form is reconfigured on load not on submit. Then way would be to trigger the load from submit success callback.

scottpenrose
8 Jul 2008, 9:54 PM
You don't need to refresh metaData unless you want to reconfigure the form, to change fields. If you really need to change fields then the form is reconfigured on load not on submit. Then way would be to trigger the load from submit success callback.

Thanks that worked perfectly.

Yes I did want to change the metaData on a successful save. Basically the code shows the user some out of date fields in their profile. Once they update those fields, different fields may be out of date.

Scott

mirage
18 Jul 2008, 1:37 PM
Hello Saki,

I hope you'll get to read this. I'm a bit of trouble. I've modified your extension a bit since I had the need to add the form items to specific tabpanels. So the whole Form is a tabpanel.

Adding the items to the panel works fine. They render and submit fine. However, they fail to initialize. What I mean by 'they submit fine' is that if I fill out the fields or check the checkboxes, it actually submits the values.

So I went into firebug and did something like this:

frm=Ext.getCmp('myForm').getForm();
fld=frm.findField('event_10');

Turns out fld is undefined. In other words it appears as if the form object has no reference to it. If I add the items to the Form instead of the tabpanel, then it finds the fields ok, but of course they don't render.

What's really puzzling me is that if the findField() doesn't work and thus setValues() fails, then how come the values actually do make it into the POST data upon submit().

Got any wisdom to share on what might be going on or whether I need to do something special when adding these fields to the tabpanel?

thanks
-m

mirage
18 Jul 2008, 1:54 PM
Never mind!




,listeners:{
// otherwise basic form findField does not work
add:{scope:this, fn:this.onAdd}
}


Note to self: Read Saki's code comments before asking redundant questions



I needed to add the 'add' listener to the tabpanel...

GokhanNL
25 Jul 2008, 4:16 AM
I know MetaForm is not created for complex elements, but wondering is there a way to implement grid in MetaForm? I just need empty grids for my users to enter values, I have to create the forms on the fly because there are hundreds of forms.

if possible any example?

jsakalos
25 Jul 2008, 11:39 PM
MetaForm has been designed with form fields in the mind so there is no direct support for grids. However, you can try to throw a grid xtype to it to see what happens.

pokerking400
3 Sep 2008, 4:25 PM
How do i add hiddenfield? without showing it?. Label shows up or it creates space for it.

jsakalos
3 Sep 2008, 11:05 PM
I have never needed it as I've always posted additional data in params:{..} object.

pokerking400
5 Sep 2008, 1:14 AM
do you have any tips to achieve it?. i can't send it through params because it it give me lots of work to handle param stuff different and post stuff different.

Too much complexity.

I only send "Action" in param not data.

I add hidden field..it hides but layout still uses the field for layout but just do not show. It creates empty space at top.

I need to hide it from layout as well. How do i do that?.

At present i make the field disable..do not want to many disable field to show to user. I need to hide it completely but data has to go through post data.

Thanks

mask_hot
5 Sep 2008, 5:13 AM
Hello Saki,

I want to try your MetaForm ux like your RecordForm ux :

I have a form describing an Event in which some people can answer if they will be present at the event.

I would like to Edit the Event through an Edit button. Once clicked, a MetaForm will be displayed.

My questions :
- Is it a true use of this ux?
- when do I have to load the MetaForm data? Do I have, for example, to create the metaForm with the formName and the Id of the Event I'd like to Edit? (I will have several different forms configured on the serevr) So, the server will send back the metaForm (fields) and the data to fill it?
- How could I tell my metaForm to refresh the original form with the submitted data?

thanks

jsakalos
6 Sep 2008, 5:24 AM
@pokerking400,
hmmm, it's much less work to add params:{"aHiddenField":123} then to create and maintain a <field type="hidden">, isn't it?

Otherwise you could set this field as ignored field and create it manually for example from MetaForm::afterMetaChange implementation.

pokerking400
6 Sep 2008, 8:32 PM
I basically create a routine to re populate $_POST from all url data.

So now i can attach to param what ever field i do not intend to display. I basically use disable as a flag indicator.

I need user flag (kind of user variable to attach to element so i can use that instead of disable.

I just go through form elements and see if there is any field is disables , i just add to param list in submit options.

we need user variable in element.

Thanks.

jsakalos
6 Sep 2008, 11:22 PM
I basically create a routine to re populate $_POST from all url data.

I have no idea what this could be. POST doesn't put data in url, GET does it. What would be use of taking GET data and put it to $_POST variable? Or I get it wrong?


So now i can attach to param what ever field i do not intend to display. I basically use disable as a flag indicator.
Do you mean form submit params?


I need user flag (kind of user variable to attach to element so i can use that instead of disable.

I just go through form elements and see if there is any field is disables , i just add to param list in submit options.

we need user variable in element.

Thanks.I'd consider run through the application design cycle again...

pokerking400
7 Sep 2008, 1:11 PM
Thanks saki.

My architecture is rugged. Haha.

I basically decode data from $_POST , $_GET...combine all parameters and sent to further processing downstream.

I avoid GET as much in my design.

If there is a GET request i just move to $_POST or another combined array which does fruther processing.

I use URL only for actions. Not for data.

In some cases data may come through URL , in that cases i just combines them.

My problem solved.
:)

jsakalos
7 Sep 2008, 3:00 PM
FYI, http://sk.php.net/manual/en/reserved.variables.request.php

pokerking400
7 Sep 2008, 8:32 PM
I know it is global and available everywhere. I just need processing at one place so it is easy to maintain.

huling
3 Nov 2008, 6:07 AM
how can i get this plugin?

jsakalos
4 Nov 2008, 12:52 AM
1) It is extension, not plugin.
2) The code is in the first post of this thread.

OutpostMM
5 Nov 2008, 10:02 PM
This is a very useful extension Saki, well done.

I'm getting an error that seems to be related to the JSON coming back, when I use your example PHP code in the first post I don't get the error, but I can't find the problem.

Firebug says the error is on line 9 of ext-base.js and the error message is "array has no properties". Here's an example of the JSON response I'm sending back:


{"success":true,"metaData":{"formConfig":{"columnCount":1,"msgTarget":"under","labelWidth":80},"fields":[{"name":"id","editor":{"xtype":"hidden"}},{"name":"page_mode","editor":{"xtype":"hidden"}},{"name":"data","fieldLabel":"Replace Text","editor":{"xtype":"textfield","anchor":"100%","allowBlank":false}}]},"data":{"id":"home_head2","data":"Ranch Real Estate","page_mode":"save"}}

{"success":true,"metaData":{"formConfig":{"columnCount":1,"msgTarget":"under","labelWidth":80},"fields":[{"name":"id","editor":{"xtype":"hidden"}},{"name":"page_mode","editor":{"xtype":"hidden"}},{"name":"data","editor":{"xtype":"htmleditor","height":200,"anchor":"100%","createLinkText":"Enter URL","enableColors":false,"enableFont":true,"fontFamilies":["","Verdana","Arial","Helvetica","serif","sans-serif"],"hideLabel":true}}]},"data":{"id":"home_box3","data":"Coming Soon!","page_mode":"save"}}

Do you see what would cause an error like that?

jsakalos
6 Nov 2008, 12:49 AM
I can say nothing just from staring at the json you posted. It looks correct on reading. Try to set some breakpoints in your code just before the error occurs and then step into to trace it down.

OutpostMM
12 Nov 2008, 8:54 PM
It looks like the error was caused by the server response not including the "fields" and "formConfig" properties in the metaData property of the response object. The server response was not including these properties when the form was sending an initial request with the parameter meta=true. I see that request being sent in onRender but I'm not sure what it is expecting to receive as a response. It doesn't send the extra parameters I use when I load the form so I'm not sure if I'll be able to tell which form it wants metadata for, I have several meta forms per page where it uses the ID to determine which fieldset to show and what data to save and load. I was getting the error when I sent this as a response:

{"success":true,"metaData":[],"data":{"id":""}}

but not with this:

{"success":true,"metaData":{"fields":[],"formConfig":[]},"data":{"id":""}}

The JSON I posted above was from the call to load, it was the request sent during onRender that was causing the error.

I'm putting together a small CMS where they can just click things on the page to edit them, and this is the Javascript code for it so far:


Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif';

Ext.namespace('app');

app.admin = function() {

return {

init: function() {
Ext.QuickTips.init();

var links = Ext.select('a.admin_edit_link');
links.addListener(
'click',
function (evt, t, o)
{
this.show_edit(t.getAttribute('id'));
},
this
);
},

show_edit: function(id) {
var win = new Ext.Window({
id: 'edit-win',
modal: true,
title: 'Edit Content',
layout: 'fit',
width: 500,
height: 400,
items: [
{
xtype:'metaform',
id: 'edit-form',
url:'io.php',
method: 'post',
buttons: [
{
text:'Save',
handler: this.do_edit,
scope: this
}
]
}
]
});
win.show();
Ext.getCmp('edit-form').getForm().load({params: {page_mode: 'load-form', id: id}});
},

do_edit: function() {
Ext.getCmp('edit-form').getForm().submit(
{
method: 'post',
success: function(f, a)
{
window.location.reload(true);
},
failure: function(f, a)
{
Ext.Msg.alert('Error', 'The update was not successful. Please refresh the page and try again. You may copy your text before refreshing.');
}
}
);
}
};
}();

The links just need the right class on them and a database ID for what to edit, e.g.:

<a href="javascript:void(0);" id="home_text1" class="admin_edit_link"></a>

The PHP script checks the database for the data and determines if it needs to use a single line, HTML editor, etc. When the initial request with meta=true came in, the PHP script initialized the response array but didn't fall through the switch to fill things out because it didn't send the other data.

jsakalos
13 Nov 2008, 12:40 AM
Empty response from the server just doesn't make sense as should the form be empty we don't need it at all, we don't even need to send any requests. The server must response with valid metadata.

radustefan
13 Nov 2008, 5:20 PM
Hello Saki,
I hope you'll get to read this. I'm a bit of trouble. I've modified your extension a bit since I had the need to add the form items to specific tabpanels. So the whole Form is a tabpanel.


I also need the functionality to load the form fields in specific tab panels. Would you please post your code?

jsakalos
14 Nov 2008, 12:15 AM
I've written MetaTabsForm for somebody but I'm not quite sure if it is universal enough for a general use. Nevertheless, you can try it:
[php]
// vim: ts=4:sw=4:nu:fdc=4:nospell
/**
* Ext.ux.MetaTabsForm
*
* @author Ing. Jozef Sak

radustefan
14 Nov 2008, 8:00 AM
Saki, please help me with the JSON format

Later edit: I send this, it displays the two tab pages, but it doesn't display contents.




{"success":true,"metaData":{"formConfig":{"labelAlign":"left","columnCount":1,"labelWidth":120,"defaults":{"width":300}},"tabPanelConfig":{"items":[{"name":"A","title":"A","height":200,"fields":[{"name":"compName","fieldLabel":"Company"},{"name":"compForm","fieldLabel":"Legal Form"}]},{"name":"B","title":"B","height":200,"fields":[{"name":"compName","fieldLabel":"Company"},{"name":"compForm","fieldLabel":"Legal Form"}]}]},"fields":[{"name":"compName","fieldLabel":"Company"},{"name":"compForm","fieldLabel":"Legal Form"}]},"data":{"compName":"AAA","compForm":"BBB"}}

jsakalos
14 Nov 2008, 1:05 PM
http://extjs.eu/metatabsform/metatabsform.html

radustefan
14 Nov 2008, 2:07 PM
Thank you, I just studied metaform.js line by line in the last 2-3 hours.
I really appreciate the sample, really solved a big problem. Have a nice weekend!

jsakalos
14 Nov 2008, 2:15 PM
You're welcome. Nice weekend for you too... :)

radustefan
16 Nov 2008, 8:59 AM
I am using triggerfields in my MetaTabsForm sent by PHP like this:



array("xtype"=>"trigger", "fieldLabel"=>"$prm->Caption", "name"=>"$prm->FieldName", "triggerClass"=>"x-form-search-trigger", "width"=>200, "lookupmodel"=>"catalog/item" )


How can I assign a handler function for ontriggerclick event to those fields?

jsakalos
16 Nov 2008, 5:00 PM
No chance w/o some coding, evaling. Json only contains strings but you need a function name.

radustefan
17 Nov 2008, 1:24 AM
I can define the function in myown.js, and I can asign it in metaform.js but how?

jsakalos
17 Nov 2008, 2:41 AM
I'm not sure if it is best but this should work:



function fn() {....};

// now you receive from JSON
{"handler":"fn"};

// and then
form.handler = eval(o.handler);
// where o would be decoded json object

radustefan
17 Nov 2008, 3:18 AM
I want to set the handler for each trigger field maybe in metaform.js in onMetaUpdate



if('trigger' == typeof item) {
item.onTriggerClick = eval( 'OnSelectButton' )
}
But function OnSelectButton is declared in client js, is that correct?

jsakalos
17 Nov 2008, 3:21 AM
I have no clue what is client.js. Generally, try it yourself and you'll see it immediately. I have no bandwidth to develop/debug an application for you.

radustefan
17 Nov 2008, 12:32 PM
I assigned the handler function to all my trigger fields inside onMetaChange handler like this:



if( field.xtype == 'trigger' ) {
field.onTriggerClick = eval( 'myFunction');
}


Thank you Saki for your tip, and I apologize if you understand that I asked you to build/debug my application. It's not my style.

jgarrison
18 Dec 2008, 3:21 PM
I'm incredibly green when it comes to Ext and JS in general, I'm somewhat more familiar with PHP but hardly an expert. I have a small app that I've been working on and was excited to find this extension and believe that it will work perfectly for part of my project.

I've been able to build the forms relatively easily and have no problem with that. I don't understand however how to pass the form back to the to the server. I borrowed someones code from their submit function but I don't really understand how it works or what form the data is returned to the server in. Could someone please explain or give me an example of how to return the data and how to handle it server side?

The code i currently have is attached below. Thank you in advance.



new Ext.Window({
id:'metaform-win'
,layout:'fit'
,width:200
,height:300
,title:'Ext.ux.MetaForm'
,items:{
xtype:'metaform'
,url:'database.php'
,baseParams:{task: "STATS"} // this parameter is passed for any HTTP request
,buttons:[{
text:'Submit'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().submit({
method:'POST',
waitTitle:'Connecting',
waitMsg:'Sending data...',
success:function(form, action){
Ext.MessageBox.alert('Succes!', 'Succes');
},
failure:function(form, action){
Ext.MessageBox.alert('Failed!', 'Failed');
}
});

}
},{
text:'Reset'
,handler:function() {
Ext.getCmp('metaform-win').items.get(0).getForm().reset();
}
}]
}
})

mjlecomte
18 Dec 2008, 5:10 PM
There are some examples in the wiki, Saki has some on his site, there are examples in the demos I believe, there's a recently released book, and talk about another site offering tutorials, screencasts, example code etc. There's several resources to tap, suggest you poke around a little bit more.

jsakalos
19 Dec 2008, 3:10 AM
There is one example at http://examples.extjs.eu/?ex=formloadsubmit

henryivy
27 Feb 2009, 7:56 AM
Hi,

I am using Metaform for one of my UI. In that I have a datefield. I am using JsonReader and my Json data returns date as '/Date(1216120082410)/'. When I am binding this to UI it shows as it is. How to change this format?

Thanks,

mystix
27 Feb 2009, 8:26 AM
Hi,

I am using Metaform for one of my UI. In that I have a datefield. I am using JsonReader and my Json data returns date as '/Date(1216120082410)/'. When I am binding this to UI it shows as it is. How to change this format?

Thanks,

find a way to send the following datefield config down the wire using the metaform ux:


{
xtype: 'datefield',

// other datefield configs

setValue : function(date) {
date = Ext.isDate(date)? date : new Date(parseInt(date.replace(/\/Date\((\d+)\)\//, '$1')));

Ext.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
}
}


or use the following JsonReader field config:


{name: 'myDateField', type: 'date', convert: function(v) {
return v? new Date(parseInt(v.replace(/\/Date\((\d+)\)\//, '$1'))) : v;
}}

henryivy
1 Mar 2009, 10:45 PM
It works well. But can you tell me how to show the time along with date?. also If i want to show the date in text field how can I implement it?

Thanks for your quick reply

Regards,
Jay

mystix
2 Mar 2009, 12:28 AM
It works well. But can you tell me how to show the time along with date?. also If i want to show the date in text field how can I implement it?

Thanks for your quick reply

Regards,
Jay



{name: 'myDateField', type: 'date', dateFormat: 'Y-m-d H:i:s', convert: function(v) {
return v? new Date(parseInt(v.replace(/\/Date\((\d+)\)\//, '$1'))) : v;
}}

henryivy
4 Mar 2009, 9:53 AM
Thanks for quick reply.

One more doubt. I am not able to right align the form labels.
I have set labelAlign property to right. still it is not working. Am I missing anything here?


{"success":true,"metaData":{"fields":[{"name":"compName","fieldLabel":"Firma","editor":{"allowBlank":false}},{"name":"compForm","fieldLabel":"Legal Form","editor":{"allowBlank":false}},{"name":"clientFrom","fieldLabel":"Client Since","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"clientTill","fieldLabel":"Client Till","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"compNote","fieldLabel":"Note","editor":{"xtype":"textarea"}}],"formConfig":{"labelAlign":"right","columnCount":2,"labelWidth":80,"defaults":{"width":130}}},"data":{"compName":"My Company","compNote":"Company Note","clientFrom":"1.2.08"}}


Thanks

mystix
4 Mar 2009, 6:15 PM
labelAlign is set at the container level, not field level.

henryivy
4 Mar 2009, 10:20 PM
Yes, it is for container level. If i set that labelAlign property, the labels of all fields in the form should get right aligned right?

mystix
4 Mar 2009, 10:38 PM
Yes, it is for container level. If i set that labelAlign property, the labels of all fields in the form should get right aligned right?

yes, they should.
check the final generated xtype config and make sure that's the case.

DoS
10 Mar 2009, 3:00 AM
It seems like MetaForm doesn't display server side validation error messages. Does it support that?
For example if server response is {'success':false,'errors':{'id':'SOME_FIELD_NAME','msg':'SOME ERROR'}}, nothing is displayed.

jsakalos
10 Mar 2009, 3:12 AM
It depends on how it is configured. I use it many times in my app with no problems. You see, MetaForm is very much like standard form with only one difference: it is configured from server.

DoS
10 Mar 2009, 3:34 AM
On Ext side:

var config = {
autoInit: {params:{'group':this.settingskey}},
url: '/ext_admin/ajax/settings/form/',
tbar: [{text:'Save', iconCls:'save-icon', scope: this, handler:function(){
//var formdata = this.getForm().getValues();
this.getForm().submit({
params:{cmd:'save',group:this.settingskey},
success: function(form, action) {
//console.log(action);
},
failure: function(form, action) {
//console.log(action);
}
});
}}]

};Gets json object:
{'success':true,'meta':true,'metaData':{'fields':{'fieldLabel':'SOMETHING','name':'SOME_NAME'},'formConfig':{'labelWidth':200,'labelAlign':'left'}},'data':{'SOME_NAME':5}}The form is displayed correctly, submits correctly.

Let's say SOME_NAME can be only integer. If I enter an integer, everything works. If I enter some text, response is
{'success':false,'errors':{'id':'SOME_NAME','msg':'This field has to contain an integer'}} "failure" callback function works and I can display errors there with an alert or Ext.Msg, but no errors are displayed inside the form like when validating on client side. What am I missing here?

henryivy
10 Mar 2009, 3:40 AM
Hi mystix,

Below said code is working fine. I am able to right align all labels if i mention labelAlign property in script. But when I send the labelAlign property as part of Metadata, it is not right align the labels. As you said i have verified my meta data.



metaForm = new Ext.ux.MetaForm({
applyTo: 'frmDataset',
autoHeight: true,
labelAlign: 'right',
waitMsgTarget: true,
frame: true,
url: '/System/GetDataSetDetails'
});

Please let me know, how to resolve this.

Thanks,

mystix
10 Mar 2009, 5:08 AM
Hi mystix,

Below said code is working fine. I am able to right align all labels if i mention labelAlign property in script. But when I send the labelAlign property as part of Metadata, it is not right align the labels. As you said i have verified my meta data.



metaForm = new Ext.ux.MetaForm({
applyTo: 'frmDataset',
autoHeight: true,
labelAlign: 'right',
waitMsgTarget: true,
frame: true,
url: '/System/GetDataSetDetails'
});

Please let me know, how to resolve this.

Thanks,

check if the ux.MetaForm even checks for labelAlign configs from the server.
you'll need to dig into the source to find out exactly what the MetaForm looks for in the server response. i've never used this plugin, so that's about all the advice i can give.

you'll either need to check with @saki, or better yet, dive into the source code.

jsakalos
10 Mar 2009, 6:36 AM
Yes mystix, you're right.

@henryivy: There is formConfig property expected from the server that should contain form configuration (not fields). Also, if you want some validation on fields, you must supply it from the server. Like allowBlank:false in the field config. Further, see how your MetaForm differs from http://examples.extjs.eu/?ex=formerrors

DoS
10 Mar 2009, 7:13 AM
Can't seem to find a difference.
If I call

this.getForm().markInvalid(action.result.errors) in submit failure callback, then errors are displayed, so I'll stick to that right now and if I get some time then try to find out why these errors don't get shown automatically.

jsakalos
10 Mar 2009, 7:35 AM
AFAIK, you don't need to call anything. All is handled by Ext infrastructure.

DoS
10 Mar 2009, 7:53 AM
Yes, but somewhy and somehow these errors get lost somewhere.

jsakalos
10 Mar 2009, 7:58 AM
Hmmm, there is changed order of actions in beforeAction:


/**
* @private
* Changes order of execution in Ext.form.Action.Load::success
* to allow reading of data in this server request (otherwise data would
* be loaded to the form before onMetaChange is run from actioncomplete event
*/
,beforeAction:function(form, action) {
action.success = function(response) {
var result = this.processResponse(response);
if(result === true || !result.success || !result.data){
this.failureType = Ext.form.Action.LOAD_FAILURE;
this.form.afterAction(this, false);
return;
}
// original
// this.form.clearInvalid();
// this.form.setValues(result.data);
// this.form.afterAction(this, true);

this.form.afterAction(this, true);
this.form.clearInvalid();
this.form.setValues(result.data);
};
} // eo function beforeAction

Could you test if that could be reason, though I doubt...?

DoS
10 Mar 2009, 8:37 AM
No, it gets lost in that first if block (result.success == false, so !result.success == true, so failure type is set to LOAD_FAILURE and form errors are never displayed)

I changed it to something like that and now errors are displayed:



,beforeAction:function(form, action) {
action.success = function(response) {
var result = this.processResponse(response);

if(result === true || !result.success || !result.data){
if(result.success === false && result.errors){
this.form.markInvalid(result.errors);
this.failureType = Ext.form.Action.SERVER_INVALID;
} else {
this.failureType = Ext.form.Action.LOAD_FAILURE;
}
this.form.afterAction(this, false);
return;
}
// original
// this.form.clearInvalid();
// this.form.setValues(result.data);
// this.form.afterAction(this, true);

this.form.afterAction(this, true);
this.form.clearInvalid();
this.form.setValues(result.data);
};
} // eo function beforeAction
Took it from Ext.form.Action.Submit.success:


success : function(response){
var result = this.processResponse(response);
if(result === true || result.success){
this.form.afterAction(this, true);
return;
}
if(result.errors){
this.form.markInvalid(result.errors);
this.failureType = Ext.form.Action.SERVER_INVALID;
}
this.form.afterAction(this, false);
},

jsakalos
10 Mar 2009, 8:46 AM
I've tried to remove all that beforeAction logic, including the listener and it seems to work. Could you please test it once again? if it works w/o beforeAction, that came from some older versions of Ext, then I'll remove it altogether and that would be event better. The simpler, the better.

DoS
10 Mar 2009, 8:55 AM
If I remove beforeAction and the listener, the forms will be displayed correctly, but there's no data in them.

jsakalos
10 Mar 2009, 9:06 AM
I see. OK, I'll take another look maybe during weekend.

DoS
10 Mar 2009, 9:10 AM
Maybe just adding checking action type is enough. Seems to work fine. For load action order of function calls are changed and for submit nothing gets overriden and hence works normally.



,beforeAction:function(form, action) {
if ('load' == action.type) { // JUST ADD THAT
action.success = function(response) {
var result = this.processResponse(response);
console.log(result);
if(result === true || !result.success || !result.data){
this.failureType = Ext.form.Action.LOAD_FAILURE;
this.form.afterAction(this, false);
return;
}
// original
// this.form.clearInvalid();
// this.form.setValues(result.data);
// this.form.afterAction(this, true);

this.form.afterAction(this, true);
this.form.clearInvalid();
this.form.setValues(result.data);
};
}
} // eo function beforeAction

jsakalos
10 Mar 2009, 9:15 AM
Yeah, sounds sensible. I'll check it anyway a bit more. Then I'll let you know.

henryivy
11 Mar 2009, 3:40 AM
Hi,

I am using metaform in web apllication. It was woking fine. And I want to include the multiple fieldset in that form.

Please any one help me how to implement that.

Thanks

jsakalos
11 Mar 2009, 4:37 AM
It should accept fieldsets if delivered from server in field config, doesn't it?

henryivy
12 Mar 2009, 2:28 AM
{"success":true,"metaData":{"fields":[{"name":"compName","fieldLabel":"Firma","editor":{"allowBlank":false}},{"name":"compForm","fieldLabel":"Legal Form","editor":{"allowBlank":false}},{"name":"clientFrom","fieldLabel":"Client Since","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"clientTill","fieldLabel":"Client Till","editor":{"xtype":"datefield","format":"j.n.y"}},{"name":"compNote","fieldLabel":"Note","editor":{"xtype":"textarea"}}],"formConfig":{"labelAlign":"right","columnCount":2,"labelWidth":80,"defaults":{"width":130}}},"data":{"compName":"My Company","compNote":"Company Note","clientFrom":"1.2.08"}}

Here compName and compForm in a fieldset, I am not sure how to add fieldset for this.

Please help.

jsakalos
12 Mar 2009, 3:24 AM
I think that you could send xtype:fieldset,items:[...] from the server and it should work. I don't have time to prepare an example of that before weekend...

henryivy
12 Mar 2009, 6:38 AM
Thanks for your replay.

I modified the metadata below format.


{"success":true,"metaData":{
"fields":[{
"editor":{"xtype": "fieldset","columnCount":2,"title": "Company Information","defaultType": "textfield", "height": 200, "width":500
, items: [{fieldLabel: "Comp Name","name": "compName"},{fieldLabel: "Address1","name": "Address1"}]
}},
{
"editor":{"xtype": "fieldset","title": "Company Information","defaultType": "textfield", "autoHeight": "true", "width":300
, items: [{fieldLabel: "Address2","name": "Address2"}]}
}],
"formConfig":{"labelAlign":"right","columnCount":1,"labelWidth":80,"defaults":{"width":130}}},
"data":{"compName":"My Company","Address1":"First Street","Address2":"London"}}


Fieldset was working fine but data is not display.
I attached the screen shot.

Please advice to me how to rectify that issue.

jsakalos
12 Mar 2009, 6:48 AM
Yeah, there could be a bug, I've never used it with fieldsets. I have not time to look at it before (hopefully this) weekend.

Radziu
27 Mar 2009, 12:37 PM
hi i try to use metaform in tab panel but it doesnt works i tried set this as a tab and as an item of the tab but still i have error:


onRender()(Object dom=div#ext-gen307.x-panel-body id=ext-gen307, "asd")ext-all-debug.js (wiersz 15972)
onRender()(Object dom=div#ext-gen307.x-panel-body id=ext-gen307, "asd")ext-all-debug.js (wiersz 28809)
onRender()()ext.ux.m...taform.js (wiersz 339)
render()(Object dom=div#ext-gen307.x-panel-body id=ext-gen307, "asd")ext-all-debug.js (wiersz 12454)
render()()ext-all-debug.js (wiersz 14062)
renderItem()(Object initialConfig=Object url=asasd.php events=Object, 0, Object dom=div#ext-gen307.x-panel-body id=ext-gen307)ext-all-debug.js (wiersz 14351)
renderItem()(Object initialConfig=Object url=asasd.php events=Object, 0, Object dom=div#ext-gen307.x-panel-body id=ext-gen307)ext-all-debug.js (wiersz 15469)
renderAll()(Object initialConfig=Object title=Uprawnienia, Object dom=div#ext-gen307.x-panel-body id=ext-gen307)ext-all-debug.js (wiersz 14344)
onLayout()(Object initialConfig=Object title=Uprawnienia, Object dom=div#ext-gen307.x-panel-body id=ext-gen307)ext-all-debug.js (wiersz 14331)
onLayout()(Object initialConfig=Object title=Uprawnienia, Object dom=div#ext-gen307.x-panel-body id=ext-gen307)ext-all-debug.js (wiersz 14489)
layout()()ext-all-debug.js (wiersz 14326)
onResize()()ext-all-debug.js (wiersz 14385)
fire()()ext-all-debug.js (wiersz 1488)
fireEvent()()ext-all-debug.js (wiersz 1184)
setSize()(674, 154)ext-all-debug.js (wiersz 13546)
setItemSize()(Object initialConfig=Object title=Uprawnienia, Object width=674 height=154)ext-all-debug.js (wiersz 14440)
onLayout()(Object initialConfig=Object xtype=tabpanel, Object dom=div#ext-gen285.x-tab-panel-body id=ext-gen285)ext-all-debug.js (wiersz 14433)
layout()()ext-all-debug.js (wiersz 14326)
setActiveItem()(Object initialConfig=Object title=Uprawnienia)ext-all-debug.js (wiersz 14462)
setActiveTab()(Object initialConfig=Object title=Uprawnienia)ext-all-debug.js (wiersz 19151)
render()()ext-all-debug.js (wiersz 18821)
renderItem()(Object initialConfig=Object xtype=tabpanel, 2, Object dom=form#ext-gen240.x-panel-body id=ext-gen240)ext-all-debug.js (wiersz 14351)
renderItem()(Object initialConfig=Object xtype=tabpanel, 2, Object dom=form#ext-gen240.x-panel-body id=ext-gen240)ext-all-debug.js (wiersz 15469)
renderAll()(Object initialConfig=Object xtype=ClientForm gStore=Object, Object dom=form#ext-gen240.x-panel-body id=ext-gen240)ext-all-debug.js (wiersz 14344)
onLayout()(Object initialConfig=Object xtype=ClientForm gStore=Object, Object dom=form#ext-gen240.x-panel-body id=ext-gen240)ext-all-debug.js (wiersz 14331)
onLayout()(Object initialConfig=Object xtype=ClientForm gStore=Object, Object dom=form#ext-gen240.x-panel-body id=ext-gen240)ext-all-debug.js (wiersz 14489)
layout()()ext-all-debug.js (wiersz 14326)
doLayout()(undefined)ext-all-debug.js (wiersz 14204)
doLayout()(undefined)ext-all-debug.js (wiersz 14211)
render()()ext-all-debug.js (wiersz 14077)
show()(undefined, undefined, undefined)ext-all-debug.js (wiersz 16814)
handler()()Client.Grid.js (wiersz 88)
onClick()(Object browserEvent=Event mouseout button=0 type=mouseout)ext-all-debug.js (wiersz 19687)
h()()ext-all-debug.js (wiersz 1694)
getViewWidth()()ext-base.js (wiersz 10)

chrome://firebug/content/blank.gif this.body.addClass(this.bodyCls + '-noborder');

jsakalos
27 Mar 2009, 12:58 PM
Do you think you've found a bug in MetaForm?

Radziu
27 Mar 2009, 1:02 PM
i think that sth isnt render i sth like this i dont know with what might be a problem that i have an error: 'this.body is null" i suppose thet isnt a bug

jsakalos
27 Mar 2009, 1:05 PM
Are you sure that it is MetaForm related? What if you use standard Ext form?

Radziu
27 Mar 2009, 2:39 PM
i found my bug :) i had a window with formPanel with items and tab panel where was metaform in fact formPanel when i change my main item in window to ext.panel everytging works great

Radziu
27 Mar 2009, 2:47 PM
how to add params to the request?

jsakalos
27 Mar 2009, 3:08 PM
Do not hijack this thread to ask basic questions please. Use help forum for that purpose.

Radziu
1 Apr 2009, 11:19 AM
i've read all posts from the thread and i didnt find answer for my problem:
"columns.get(colIndex++) is undefined" - firebug error.
and my json: {"success":"true","metaData":{"fields":[{"name":"compName","fieldLabel":"Company","editor":{"allowBlank"
:"false","xtype":"checkbox"}},{"name":"compName","fieldLabel":"Company","editor":{"allowBlank":"false"
,"xtype":"checkbox"}},{"name":"compName","fieldLabel":"Company","editor":{"allowBlank":"false","xtype"
:"checkbox"}},{"name":"compName","fieldLabel":"Company","editor":{"allowBlank":"false","xtype":"checkbox"
}}],"formConfig":{"labelAlign":"left","columnCount":"1","labelWidth":"80","defaults":{"width":"230"}
}},"data":[]}

and what is fanny in fact? when i write an array with the meta objects everything works great and the json is thesame like this above. When i try to iterate this by foreach PHP the error is arrear. Any ideas?

jsakalos
1 Apr 2009, 12:25 PM
Post a complete workable showcase as per: http://extjs.com/learn/Ext_Forum_Help#Posting_a_working_showcase

Jangla
2 Apr 2009, 7:38 AM
A theoretical question on this extension - could/should it be possible to use the php file to declare a card that in turn calls another php file to populate a control on a card?

The reason I ask is this - I'm trying to just that :D I want the second card to have a CheckTree extension on it which needs to be populated from JSON. I had a crack at just continuing with the same theory of the metaform but without much luck (as you'll see below). I then tried adding a listener to the wizard but couldn't get that to fire either.

Tips greatly appreciated.



win = new Ext.Window({
id: Ext.id(),
layout:'fit',
height: 500,
width: 280,
modal: true,
shadow: 'frame',
shadowOffset: 4,
constrain: true,
center: true,
title: 'Availability search',
items: {
id: 'availabilility-search-wizard',
xtype: 'wizard',
animate: true,
height: 350,
helpBtn: null,
reviewEntries: false,
headerConfig: {
titleText: 'Search for availabile properties',
titleImg: 'fileadmin/templates/scripts/extJS/resources/images/default/s.gif'
},
autoInit: {
url: 'fileadmin/templates/scripts/wizardconfig.php',
params: {
query: 'get',
mode: 'userprofile'
}
}
,
listeners: {
'afterrender': function(){
alert("rendered"); // placeholder - can't get this to fire at all

}
}
});
win.show();

tree = new Ext.ux.tree.CheckTreePanel({
title:'Countries/regions',
id:'tree',
width:300,
height:250,
autoScroll:true,
rootVisible:false,
root:{
nodeType:'async',
id:'root',
text:'root',
expanded:true,
uiProvider:false
},
loader:{
url:'get-regions.php'
}]
});


and this was my initial attempt at using the metaform idea to load a further php file:



..............
array(
'index' => 1,
'layout' => 'form',
'trailText' => 'Country/region',
"defaults"=>array(
"width"=>130
),
'items' => array(
'title' => 'Countries/regions',
'id' => 't2',
'width' => 245,
'height' => 300,
'autoScroll' => true,
'rootVisible' => false,
'root' => array(
array(
'nodeType' => 'async',
'id' => 'root',
'text' => 'root',
'expanded' => true,
'uiProvider' => false
)
),
'loader' => array(
array(
'url' => 'process-request.php',
'baseParams' => array(
array(
'cmd' => 'getTree',
'treeTable' => 'tree',
'treeID' => 1
)
)
)
),
'tools' => array(
array(
'id' => 'refresh',
'qtip' => 'Reload Tree',
'handler' => 'function() {t2.getRootNode().reload();' // this is where I started to realise that this probably wasn't going to work!
)
)
)
)
............



BTW, while I'm here - can these php calls be cross domain?

jsakalos
2 Apr 2009, 8:39 AM
I think it is possible. There are couple of extensions that load components from server, for example this one: http://extjs.com/forum/showthread.php?t=13894

Ajax requests cannot be cross-domain.

Jangla
2 Apr 2009, 11:22 AM
Ajax requests cannot be cross-domain.

I thought Ext had a proxy to get round that?

jsakalos
2 Apr 2009, 11:23 AM
Yes, ScriptTagProxy.

Radziu
7 Apr 2009, 11:43 PM
how to add listeners to the components generated in metaform?

jsakalos
7 Apr 2009, 11:52 PM
afterMetaChange function (empty by default) is called when form is ready and configured. You can install listeners from there.

Radziu
8 Apr 2009, 12:08 AM
in your code isnt afterMetaChange function so i implement this to initCOmponent this.form...etc ane it works thanks

jsakalos
8 Apr 2009, 12:16 AM
I've updated the code in the first post - use that.

Radziu
8 Apr 2009, 12:21 AM
great! thanks!

Radziu
8 Apr 2009, 12:27 AM
why did tou chage Ext.FormPanel to Ext.form.FormPanel?

and what is: Ext.ux.util.clone(this.baseParams) on line 281?

jsakalos
8 Apr 2009, 12:51 AM
Yes, I've put all my form related extensions to Ext.ux.form.

Clone: http://extjs.eu/docs/?class=Ext.ux.util&member=clone

Radziu
9 Apr 2009, 10:29 PM
is it possible to use Ext.data.Store component with json reader in eg. combobox
actually i user simpleStore as an array but i think the json store od data store with json reader will be moge comfortable.

jsakalos
10 Apr 2009, 12:58 AM
It would need a considerable change because you get only strings via JSON so you would need to check if you have string "new Ext.data.Store..." in the config and eval it.

I solve it from other end. I create Combo extension that contains all configuration data, register is as xtype and then deliver only the xtype string from server.

deka49
12 Apr 2009, 8:46 AM
hi

thanks for this add
I can't use "maskRe", is it possible ?



array(
"name"=>"AddQuantite"
,"fieldLabel"=>"Quantite"
,"editor"=>array(
"allowBlank"=>false
,"maskRe"=>"/([0-9\s]+)$/")

)



I have this : "this.maskRe.test is not a function" in firebug.

thanks

jsakalos
12 Apr 2009, 4:48 PM
The problem is that json delivers string but you need a RegExp. A solution could be to extend a field, include the required RegExp in the extension and to deliver the new xtype.