PDA

View Full Version : new Ext.form field type - MiscField



Nullity
29 May 2007, 12:00 PM
I wanted a way to display just simple text, with or without a label, in my form layout. Second, I wanted a way to display a label, but with no associated form field. This extension solved all of my needs, and more.

In addition to being able to accomplish the above, you can now also easily add images, buttons, etc, to your form layout.

Examples:


// regular MiscField field with plain text
new Ext.form.MiscField({
fieldLabel: 'MiscField',
id: 'miscfield',
width: 160,
value: 'blah blah blah'
});

// label with a blank field - just don't set the 'value' option
new Ext.form.MiscField({
fieldLabel: 'MiscField',
id: 'miscfield_novalue',
width: 160
})

// MiscField with image and bold text
new Ext.form.MiscField({
fieldLabel: 'MiscField',
id: 'miscfield_image',
width: 160,
value: '<img src="/path/drop-yes.gif"> image and <b>bold text</b>'
});

... this produces what you see in the attached image (along with a couple TextFields for comparison).

Any methods/functions/events/etc that are related to a form input field have been stripped out (i.e. validation, focus/blur, etc) as they are no longer necessary. Some things may work a little differently. For example, you can use HTML tags in the 'value' option. Calling 'miscfield.getRawValue()' will return the MiscField value, exactly as it is, HTML and all. However, calling 'miscfield.getValue()' returns the text only and strips out all HTML tags. Same deal for 'setValue()' and 'setRawValue()'.

This should be obvious, but I'll mention it anyway just in case; using a MiscField is only for visual purposes - as in adding more functionality to the form layout. MiscFields do not post any data when submitting a form.

Here is the code:

/**
* @class Ext.form.MiscField
* @extends Ext.BoxComponent
* Base class to easily display simple text in the form layout.
* @constructor
* Creates a new MiscField Field
* @param {Object} config Configuration options
*/
Ext.form.MiscField = function(config){
Ext.form.MiscField.superclass.constructor.call(this, config);
};

Ext.extend(Ext.form.MiscField, Ext.BoxComponent, {
/**
* @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
* {tag: "div"})
*/
defaultAutoCreate : {tag: "div"},

/**
* @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
*/
fieldClass : "x-form-field",

// private
isFormField : true,

/**
* @cfg {Mixed} value A value to initialize this field with.
*/
value : undefined,

/**
* @cfg {Boolean} disableReset True to prevent this field from being reset when calling Ext.form.Form.reset()
*/
disableReset: false,

/**
* @cfg {String} name The field's HTML name attribute.
*/
/**
* @cfg {String} cls A CSS class to apply to the field's underlying element.
*/

// private ??
initComponent : function(){
Ext.form.MiscField.superclass.initComponent.call(this);
},

/**
* Returns the name attribute of the field if available
* @return {String} name The field name
*/
getName: function(){
return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
},

// private
onRender : function(ct, position){
Ext.form.MiscField.superclass.onRender.call(this, ct, position);
if(!this.el){
var cfg = this.getAutoCreate();
if(!cfg.name){
cfg.name = this.name || this.id;
}
this.el = ct.createChild(cfg, position);
}

this.el.addClass([this.fieldClass, this.cls]);
this.initValue();
},

/**
* Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
* @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
* @return {Ext.form.MiscField} this
*/
applyTo : function(target){
this.allowDomMove = false;
this.el = Ext.get(target);
this.render(this.el.dom.parentNode);
return this;
},

// private
initValue : function(){
if(this.value !== undefined){
this.setRawValue(this.value);
}else if(this.el.dom.innerHTML.length > 0){
this.setRawValue(this.el.dom.innerHTML);
}
},

/**
* Returns true if this field has been changed since it was originally loaded.
*/
isDirty : function() {
return String(this.getRawValue()) !== String(this.originalValue);
},

// private
afterRender : function(){
Ext.form.MiscField.superclass.afterRender.call(this);
this.initEvents();
},

/**
* Resets the current field value to the originally-loaded value
* @param {Boolean} force Force a reset even if the option disableReset is true
*/
reset : function(force){
if(!this.disableReset || force === true){
this.setRawValue(this.originalValue);
}
},

// private
initEvents : function(){
// reference to original value for reset
this.originalValue = this.getRawValue();
},

/**
* Returns whether or not the field value is currently valid
* Always returns true, not used in MiscField.
* @return {Boolean} True
*/
isValid : function(){
return true;
},

/**
* Validates the field value
* Always returns true, not used in MiscField. Required for Ext.form.Form.isValid()
* @return {Boolean} True
*/
validate : function(){
return true;
},

processValue : function(value){
return value;
},

// private
// Subclasses should provide the validation implementation by overriding this
validateValue : function(value){
return true;
},

/**
* Mark this field as invalid
* Not used in MiscField. Required for Ext.form.Form.markInvalid()
*/
markInvalid : function(){
return;
},

/**
* Clear any invalid styles/messages for this field
* Not used in MiscField. Required for Ext.form.Form.clearInvalid()
*/
clearInvalid : function(){
return;
},

/**
* Returns the raw field value.
* @return {Mixed} value The field value
*/
getRawValue : function(){
return this.el.dom.innerHTML;
},

/**
* Returns the clean field value - plain text only, strips out HTML tags.
* @return {Mixed} value The field value
*/
getValue : function(){
var f = Ext.util.Format;
var v = f.trim(f.stripTags(this.getRawValue()));
return v;
},

/**
* Sets the raw field value.
* @param {Mixed} value The value to set
*/
setRawValue : function(v){
this.value = v;
if(this.rendered){
this.el.dom.innerHTML = v;
}
},

/**
* Sets the clean field value - plain text only, strips out HTML tags.
* @param {Mixed} value The value to set
*/
setValue : function(v){
var f = Ext.util.Format;
this.setRawValue(f.trim(f.stripTags(v)));
}
});
... and here is the associated CSS (this might be able to be improved on a little):

.x-form-miscfield {
height: 22px;
line-height: 18px;
vertical-align: middle;
overflow: hidden;
}
.ext-ie .x-form-miscfield {
height: 22px; /* ie quirks */
line-height: 18px;
}
.ext-strict .x-form-miscfield {
height: 18px;
}
.ext-safari .x-form-miscfield {
height: 20px; /* safari always same size */
}
.ext-gecko .x-form-miscfield {
padding-top: 2px; /* FF won't center the text vertically */
padding-bottom: 0;
}


UPDATE 1: Added new 'disableReset' option as proposed by devnull (http://extjs.com/forum/showthread.php?p=57040#post57040). When true, this field is untouched when the reset() method is called (i.e. from a form reset). Also, if 'disableReset' is true, but you would like to force a reset manually, you can do so by passing 'true' to the reset method (i.e. miscfield.reset(true);)

UPDATE 2 (9/21/07): Refactored code to be more compatible with Ext 1.1.x (was previously based off of Ext 1.0).

Nullity
13 Jun 2007, 5:57 AM
I updated the code in the first post to fix a couple bugs.

See discussion here:
http://extjs.com/forum/showthread.php?t=7293

cgoss
14 Jun 2007, 5:59 AM
Hey, this worked great, thanks for posting it. I added a few modifications for my application and to make it easier to change existing TextFields to MiscFields:

In the Extend function:

/**
* Returns the name attribute of the field if available
* @return {String} name The field name
*/
getName: function(){
return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
},

And in the Constructer:

Ext.form.MiscField = function(config){
config.id = config.name;
Ext.form.MiscField.superclass.constructor.call(this, config);
};

These may seem like hacks, but I wanted to fill the fields dynamically, after they are already rendered like normal TextFields.

My form fill code is now:

frm.add( new Ext.form.MiscField({fieldLabel: 'Author', name: 'author' }));

And I later fill the data with frm.setValues(...);

Thanks again!

mrogers
20 Jun 2007, 10:09 PM
One more addition to the js:


getName : function(){
return this.Name;
},

Nullity
27 Jun 2007, 11:17 AM
Oops...

I updated the code in the first post to add the 'getName' method back in (sorry about that), and also fixed an IE bug with the CSS.

dantheman
2 Aug 2007, 2:09 PM
I must have grabbed the source before getName() was added back.
Beware: findField will bomb for the whole form without it.

MiscField is very useful. Thanks for posting it.
--dan

ZooKeeper
5 Aug 2007, 2:42 PM
Thanks for an outstanding piece of code u shared with us.
One improvement that'd be really handy is autoheight, based on the text. Something like multiline. Will be just awesome!

gnosis
14 Aug 2007, 9:41 AM
And I later fill the data with frm.setValues(...);

Note that when using this technique, any HTML tags will be stripped out of your value. If you want to do any HTML, you can set the MiscField separately via setRawValue();

Useful extension!

-G

hendersf
20 Aug 2007, 9:07 AM
When I load this JavaScript extension, I'm getting a javascript error from ext-base.


Error: sp has no properties
Source File: http://localhost/francois/ext-1.1/adapter/ext/ext-base.js
Line: 10


Also as soon as I'm trying to use it, I have a second error that shows up


Error: Ext.form.MiscField.superclass has no properties
Source File: http://localhost/francois/scripts/MiscField.js
Line: 11

Any idea?

Thanks in advance for any input

Francois

Nullity
20 Aug 2007, 9:21 AM
When I load this JavaScript extension, I'm getting a javascript error from ext-base.


Error: sp has no properties
Source File: http://localhost/francois/ext-1.1/adapter/ext/ext-base.js
Line: 10


Also as soon as I'm trying to use it, I have a second error that shows up


Error: Ext.form.MiscField.superclass has no properties
Source File: http://localhost/francois/scripts/MiscField.js
Line: 11

Any idea?

Thanks in advance for any input

Francois

Hmm, I'm not really sure. I am also using ext-base.js and I haven't had any issues. Make sure the javascript files are being included in the correct order and the paths to each file are correct.

Correct order:

<script type="text/javascript" src="/ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="/ext/ext-all.js"></script>
<script type="text/javascript" src="MiscField.js"></script>

If that's not it, you may need to post some of your code.

hendersf
21 Aug 2007, 3:28 AM
Nice,

Thank you Nullity, it was the inclusion order of the Javascript libraries.

Is there a place where these directive are available in the documentation or on the web? I didn't saw that anywhere.

Thanks again,
Francois

Nullity
21 Aug 2007, 5:30 AM
There is a text file included in the Ext package you download from this site called 'INCLUDE_ORDER.txt'.

hendersf
21 Aug 2007, 7:00 AM
Thanks,

Francois

devnull
22 Aug 2007, 4:46 PM
I am a bit confused here as to how to add something other than text or html markup (in this case i want to add a Ext.Toolbar.MenuButton). Can you provide an example of this, or am i just not understanding how this works and this isnt supported?

Nullity
23 Aug 2007, 6:41 AM
Well, I mainly created this for text and simple HTML, so that isn't supported directly. However, you can do something like this which works just fine:


var form = new Ext.form.Form({
labelWidth: 85
});

form.add(
new Ext.form.MiscField({
fieldLabel: 'MiscField',
id: 'miscfield_button',
width: 160,
value: '<div id="test_button"></div>'
})
);

form.render('myForm');

var myButton = new Ext.Button('test_button', {
text: 'Button'
});

As in, use the MiscField to create an empty DIV, then after the form is rendered, create your Ext element and render it to that empty DIV.

devnull
23 Aug 2007, 8:14 AM
Ok, I was just completely wrong on that one then, thanks.
Now a Button renders fine, but a Toolbar.Button's constructor doesn't take a "renderTo" option. But thats my problem and not yours :)

Nullity
23 Aug 2007, 8:24 AM
Just FYI - if all you are after is a menu, the Ext.Button constructor supports a 'menu' option.

devnull
23 Aug 2007, 8:43 AM
Yeah, I did explore that option and it does work, but I dont like the behavior. The problem is that the button's main handler is called even when clicking on the menu expander portion of the button. What I really am after is the toolbar's SplitButton.

dantheman
23 Aug 2007, 9:00 AM
I have been doing just this [adding a div I render a button to afterward], and it works well.

I know it's a topic beat to death, but the fine-grained control
over placement of form controls is the one thing I miss in Ext.

I still not going back, tho. :D

--dan

devnull
23 Aug 2007, 10:43 AM
Well dont I feel like a tool, theres a Ext.SplitButton right there waiting for me to use it :)
I did have to make a small modification though, to prevent the button from being wiped out with a form.reset():


/**
* Resets the current field value to the originally-loaded value
*/
reset : function(){
if (!this.disableReset){
this.setRawValue(this.originalValue);
}
},

(new config option disableReset)
Perhaps there is a better way to do this but for now this works for me.

Nullity
23 Aug 2007, 12:14 PM
I did have to make a small modification though, to prevent the button from being wiped out with a form.reset():
...
(new config option disableReset)

Ah, good idea, I didn't even consider that. If you don't mind, I think I'll add that in.

devnull
23 Aug 2007, 12:25 PM
Have at it :)
If you can think of a better way to implement it than my quick hack, more power to ya!

Nullity
23 Aug 2007, 12:33 PM
Here is what I added:


/**
* Resets the current field value to the originally-loaded value
* @param {Boolean} force Force a reset even if the option disableReset is true
*/
reset : function(force){
if(!this.disableReset || force === true){
this.setRawValue(this.originalValue);
}
},

This way, it allows you to still force a reset manually (as opposed to a form reset) by passing 'true', if the 'disableReset' option is set.

Like so:


miscfield.reset(true);

MaxT
21 Sep 2007, 3:21 AM
Hello Nullity, just taking a look at your extension and have a question about the setSize method.




/**
* Sets the height and width of the field
* @param {Number} width The new field width in pixels
* @param {Number} height The new field height in pixels
*/
setSize : function(w, h){
if(!this.rendered || !this.el){
this.width = w;
this.height = h;
return;
}
if(w){
this.el.setWidth(w);
}
if(h){
this.el.setHeight(h);
}
var h = this.el.dom.offsetHeight; // force browser recalc
},


In this there is a minor error (gives a Javascript warning) in that the input parameter "h" is redeclared as "variable h" at the end. I assume that either the "var" part could be removed, or it could be changed to "var h2" and still have the same effect.

Can you expand a bit on what the comment for this line means? I assume that just having the line causes the browser (all of them, or is this browser specific?) to recalculate the height?

Thanks,

Max

Nullity
21 Sep 2007, 7:50 AM
That 'setSize' method was actually ripped straight from Field.js from Ext 1.0. I just updated the first post with totally refactored code based off of Ext 1.1.1, so this should no longer be a problem.

MaxT
25 Sep 2007, 2:50 AM
I've tried out the new version, seems to work fine for me.


In one case, I have labels aligned at the top and I'm using this code to create a MiscField:



f.column(
{width: 54, labelSeparator: ""},

new Ext.form.MiscField(
{
fieldLabel: "&nbsp;",
value: "From:",
id: "t-date-from-title",
cls: "x-form-miscfield-text",
width: 50
}
)
);


The additional CSS is:


.x-form-miscfield-text {
padding: 3px 0;
}


This column is followed by another column that contains a standard ComboBox.

With the simple CSS I've given above the "From:" text lines up vertically with the ComboBox text in Fx2, but is 1px too high in IE.

Has anyone got their head round making the alignment perfect in both IE and Fx?

Admittedly, the difference is very hard to spot (jpg attached of IE7 screen capture) and I'm happy to let it stay as it is, but if anyone has a better solution that would be even better.

Thanks,

Max

Roger BORDEAUX
4 Jan 2008, 1:52 AM
Hi Nullity,

Does your extension be compatible with Ext 2.0 ?

I have the following source that give me the error :

this.el has no properties
http://localhost/conference/js/ext/ext-all.js
Line 58



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<!-- GC -->
<!-- LIBS -->
<link rel="stylesheet" type="text/css" href="../js/ext/resources/css/ext-all.css"/>
<script type="text/javascript" src="../js/ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../js/ext/ext-all.js"></script>

<script type="text/javascript" src="../js/ext-extension/MiscField.js"></script>
<link rel="stylesheet" type="text/css" href="../js/ext-extension/MiscField.css"/>

<!-- ENDLIBS -->


<script type="text/javascript">

Ext.onReady(init);

function init() {

var myForm = new Ext.FormPanel({
url:'save-form.php',
frame:true,
title: 'Simple Form',
bodyStyle:'padding:5px 5px 0; ',
width: 600,
height : 500,
defaultType: 'textfield',
collapsible : true,
waitMsgTarget: true

});

myForm.add(new Ext.form.TextField({
name : 'first'
,fieldLabel : 'Firstname'
,labelSeparator : ''
,id : 'first'
,width : 150
}));

myForm.add(new Ext.form.MiscField({
fieldLabel: 'MiscField',
id : 'fieldLabel',
value: 'Test value'
}));

myForm.render(Ext.get('myElem'));

}
</script>
</head>
<body>
<div id="myElem"></div>
</body>
</html>



Best regards

Roger

MaxT
14 Jan 2008, 7:34 AM
I don't think it is compatible with Ext 2.0.

A similar extension is Ext.ux.StaticTextField:
http://extjs.com/forum/showthread.php?t=20992

Has the advantage that you can choose to add a hidden field to submit the field. However, it does some things differently, like automatically encoding the value when you call setValue. Not so sure this is a good idea.

I found a bug with MiscField in that getName doesn't work. Here is my workaround.



/**
* Returns the name attribute of the field if available, otherwise the hiddenName if
* available. Returns a null string if neither are available.
*
* @return {String} name The field name or hiddenName.
*/
getName: function(){
//return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
// NB: "name" is applied to a div, hence you must use hasAttribute and getAttribute.
// Can't access it as el.dom.name as you would for an input element.
var n = '';
if ( this.rendered && this.el.dom.hasAttribute("name") ) {
n = this.el.dom.getAttribute("name");
} else if (this.hiddenName) {
n = this.hiddenName;
}
return n;
},

amoghadam
18 Sep 2008, 9:48 PM
I have gotten a JS error saying C is NULL. I have added both the css file and the js file in the order specified.

Please help.
Thanks

Mjollnir26
17 Dec 2008, 12:22 AM
Removing the "applyTo" - Method from Nullity (http://extjs.com/forum/member.php?u=1268)'s SourceCode made this cool little thing work for me on Ext 2.2

Not totally sure if that won't break anything though.

talshadar
14 Apr 2009, 9:18 AM
But I'm having a problem getting the spacing in IE working properly.

I'm using the miscelField to hold some info fed from the selection of a combo box. Unless they select a certain value, the miscel field needs to be hidden. Only shown(and filled) if they select the value I specify.

I have tried several different things and the following is the only thing I can get working 1/2 right. otherwise it shows the info in the top corner instead of below the combo box.



interfaceInfoPlaceholder = new Ext.form.MiscField("interfaceSelection",{
fieldLabel:"&nbsp;",
labelSeparator: "",
id: "interfaceInfo",
width:350,
hideMode: "visibility"
});

frmActionItem.add(interfaceInfoPlaceholder);


txtInterfaceInfoPlaceholder = Ext.get("interfaceSelection");
txtInterfaceInfoPlaceholder.hide();
txtInterfaceInfoPlaceholder.setStyle("display","none");

//these give an error - container is null
//txtInterfaceInfoPlaceholder.container.up("div.x-form-item").hide();
//txtInterfaceInfoPlaceholder.container.up("div.x-form-item").setStyle("display","none");




any suggestions would be helpful.

willf1976
16 Sep 2009, 5:25 PM
Hi All

This is a very nice and very useful extension. Thanks for building it :).

I had a few problems with it though that I thought I would report --

First of all the applyTo function seems to be overwriting a property that ext is expecting to use. In order for make the class work I had to pass in an applyTo value of null in its config.

Also I couldn't get the class to work with out lazily instantiating it.

So I added this line of code to the end of the class:



Ext.reg('form-miscfield', Ext.form.MiscField);



Here is an example of what did and didn't work for me:


Ext.onReady(function(){
//Works:
var testMiscField = {
xtype : 'form-miscfield',
fieldLabel: 'MiscField',
id: 'miscfield',
width: 160,
value: 'blah blah blah',
applyTo : null
},
form = new Ext.FormPanel({
items : [testMiscField],
renderTo: document.body
});

//Doesn't work:
var testMiscField = new Ext.form.MiscField({
xtype : 'form-miscfield',
fieldLabel: 'MiscField2',
id: 'miscfield2',
width: 160,
value: 'blah blah blah'
}),
form = new Ext.FormPanel({
items : [testMiscField],
renderTo: document.body
});
});


I should also note that I am using version 3.0.1 of ext

Keep up the good work.

Best Regards

Will Ferrer

tenBoxelulley
29 Mar 2011, 7:59 AM
very nice map-tried doing something like this a few times, but never worked, so thanks

bclinton
11 Apr 2011, 1:46 AM
Yes, I know this post is very, very old. But seeing tenBoxelulley's post I'm not the only one who has found it while looking for a way to add a form item with text rather than an input field. There is no need for an extension to do this in ExtJS 3. You can use Ext.form.DisplayField