Feb 05, 2013, 9:33 AM
[CLOSED] JavaScript error when a component is a property of another component that is generated during a DirectMethod request
Hi,
I am finding that I get JavaScript errors when I generated a component during a DirectMethod request. The nature of the component is significant though.
It is only if my custom component itself has its own custom component that is also generated during the DirectMethod request and added as a property of a containing component.
In the example below, I have a custom button. What is custom about it is that it has a property to hold a custom window (the idea being you press the button and the window is shown).
When the button is used via markup (or code-behind), there is no problem. However, when the button (and its custom window) is generated via a DirectMethod request, then I get JavaScript errors noted further below.
Here is an example.
First, example of a custom window:
Hence, I always get a JavaScript error.
Note, functionally the button still works and the Window gets its declared properties, because they are also through the config as well as these method calls; but it just has the error as well.
The error also prevents the success and complete handlers from running.
I am sure I have missed something obvious, as I am sure this has worked in the past... If it helps, for a long time I've been running an october 16 build, and only recently updated to latest 1.x branch, and still seeing the issue.
I am finding that I get JavaScript errors when I generated a component during a DirectMethod request. The nature of the component is significant though.
It is only if my custom component itself has its own custom component that is also generated during the DirectMethod request and added as a property of a containing component.
In the example below, I have a custom button. What is custom about it is that it has a property to hold a custom window (the idea being you press the button and the window is shown).
When the button is used via markup (or code-behind), there is no problem. However, when the button (and its custom window) is generated via a DirectMethod request, then I get JavaScript errors noted further below.
Here is an example.
First, example of a custom window:
public class CustomWindow : Window
{
private Panel _panel;
public override string InstanceOf
{
get { return "MyApp.CustomWindow"; }
}
public override string XType
{
get { return "customwindow"; }
}
protected override void OnLoad(EventArgs e)
{
Title = "Custom window";
Cls += " custom-window";
Layout = "Fit";
Listeners.Show.Handler = "this.customFn();";
BottomBar.Add(new Toolbar
{
Items =
{
new Button
{
Text = "Button",
Listeners =
{
Click =
{
Handler = "this.findParentByType('customwindow').onButtonClicked();"
}
}
}
}
});
Items.Add(GetNewPanel());
CustomConfig.Add(new ConfigItem("panel", _panel.ClientID, ParameterMode.Value));
base.OnLoad(e);
}
private Component GetNewPanel()
{
_panel = new Panel { Html = "Panel html", Border = false };
return _panel;
}
}
Next, an example of a custom button using that windowpublic class ButtonWithCustomWindow : Button
{
private ItemsCollection<CustomWindow> _customWindows;
public override string InstanceOf { get { return "MyApp.ButtonWithCustomWindow"; } }
public override string XType { get { return "buttonwithcustomwindow"; } }
[Meta]
[ConfigOption]
[NotifyParentProperty(true)]
[PersistenceMode(PersistenceMode.InnerProperty)]
public virtual ItemsCollection<CustomWindow> CustomWindow
{
get { return _customWindows ?? (_customWindows = new ItemsCollection<CustomWindow>(true)); }
}
[XmlIgnore]
[JsonIgnore]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override ConfigOptionsCollection ConfigOptions
{
get
{
ConfigOptionsCollection list = base.ConfigOptions;
list.Add("customWindow", new ConfigOption("customWindow", new SerializationOptions("customWindow", typeof(ItemCollectionJsonConverter)), null, CustomWindow));
return list;
}
}
protected override void OnLoad(System.EventArgs e)
{
Cls += " custom-button";
if (CustomWindow.Count > 0)
{
CustomWindow[0].Hidden = true;
Controls.Add(CustomWindow[0]);
LazyItems.Add(CustomWindow[0]);
}
base.OnLoad(e);
}
}
JavaScript for the two components (embedded into a sample HTML)<%@ Page Language="C#" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Example</title>
<ext:ResourcePlaceHolder runat="server" />
<style>
body { padding:10px; }
</style>
<script type="text/javascript">
Ext.ns("MyApp");
MyApp.CustomWindow = Ext.extend(Ext.Window, {
constructor: function(config) {
config = config || {};
MyApp.CustomWindow.superclass.constructor.call(this, config);
if (this.panel) {
this.panel = Ext.getCmp(this.panel);
}
},
customFn: function() {
console.log('customFn called', this.id, this);
},
onButtonClicked: function() {
console.log('onButtonClicked called', this.id, this);
}
});
Ext.reg("customwindow", MyApp.CustomWindow);
MyApp.ButtonWithCustomWindow = Ext.extend(Ext.Button, {
constructor: function (config) {
config = config || {};
MyApp.ButtonWithCustomWindow.superclass.constructor.call(this, config);
this.on('click', function () {
this.customWindowInstance.show();
}, this);
},
initComponent: function () {
MyApp.ButtonWithCustomWindow.superclass.initComponent.call(this);
this.customWindowInstance = Ext.create(Ext.apply({ ownerCt: this, animateTarget: this.el }, this.customWindow));
delete this.customWindow;
}
});
Ext.reg("buttonwithcustomwindow", MyApp.ButtonWithCustomWindow);
</script>
</head>
<body>
<ext:ResourceManager runat="server" />
<p>Button With Custom Window via markup</p>
<ext:ButtonWithCustomWindow runat="server" Text="Show custom window">
<CustomWindow>
<ext:CustomWindow runat="server" />
</CustomWindow>
</ext:ButtonWithCustomWindow>
<p>Button With Custom Window component generated via ASHX</p>
<ext:Button runat="server" Text="Generate button">
<Listeners>
<Click Handler="
Ext.net.DirectMethod.request({
url: 'BuildButtonWithCustomWindow.ashx',
cleanRequest: true,
params: { container: '#{Panel1}' },
complete: function() { console.log('done'); }
});
" />
</Listeners>
</ext:Button>
<ext:Panel ID="Panel1" runat="server" Title="Dynamic button" />
</body>
</html>
The ASHX that is invoked to dynamically create an instance of the ButtonWithCustomWindow:public class BuildButtonWithCustomWindow : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string buttonScript = BuildButton().ToScript(RenderMode.RenderTo, context.Request["container"]);
new DirectResponse(buttonScript).Return();
}
private XControl BuildButton()
{
return new ButtonWithCustomWindow
{
ID = "id" + Guid.NewGuid().ToString("N"),
Text = "Created from server",
CustomWindow =
{
new CustomWindow
{
Width = 400,
Height = 400
}
}
};
}
public bool IsReusable
{
get { return false; }
}
}
When I press the button for the ButtonWithCustomWindow that has been added via markup to the page, this is part of the initialization script that I get:new MyApp.ButtonWithCustomWindow({
id : "ctl02",
cls : " custom-button",
renderTo : "ctl02_Container",
text : "Show custom window",
customWindow : {
id : "ctl09",
panel : "ctl15",
xtype : "customwindow",
cls : " custom-window",
hidden : true,
height : 100,
width : 200,
items : {
id : "ctl15",
html : "Panel html",
border : false
},
layout : "fit",
bbar : {
id : "ctl11",
xtype : "toolbar",
items : [{
id : "ctl12",
text : "Button",
listeners : {
click : {
fn : function (item, e) {
this.findParentByType('customwindow').onButtonClicked();
}
}
}
}, {
id : "ctl18",
xtype : "nettbspacer"
}
]
},
title : "Custom window",
listeners : {
show : {
fn : function (item) {
this.customFn();
}
}
}
}
});
When I look at the initialization script created by the ASHX, it is very similar, but has some crucial differences:Ext.net.ResourceMgr.destroyCmp("idd5f79582b75945cd8e6ed53ed45cafb3");
new MyApp.ButtonWithCustomWindow({
id : "idd5f79582b75945cd8e6ed53ed45cafb3",
cls : " custom-button",
renderTo : "Panel1",
text : "Created from server",
customWindow : {
panel : "ctl08",
xtype : "customwindow",
cls : " custom-window",
hidden : true,
height : 400,
width : 400,
items : {
html : "Panel html",
border : false
},
layout : "fit",
bbar : {
xtype : "toolbar",
items : [{
id : "id748da190ac874f56a6e8c4f65e83ff4f",
text : "Button",
listeners : {
click : {
fn : function (item, e) {
this.findParentByType('customwindow').onButtonClicked();
}
}
}
}, {
xtype : "nettbspacer"
}
]
},
title : "Custom window",
listeners : {
show : {
fn : function (item) {
this.customFn();
}
}
}
}
});
ctl02.setTitle("Custom window");
ctl02.addClass(" custom-window");
Notice the last two lines: ctl02.setTitle("Custom window");
ctl02.addClass(" custom-window");
Also note that it doesn't even match the ID that I set explicitly (to a new Guid). Whether I set or don't set the ID, I get these two lines that do not match any id (if any) for the button.Hence, I always get a JavaScript error.
Note, functionally the button still works and the Window gets its declared properties, because they are also through the config as well as these method calls; but it just has the error as well.
The error also prevents the success and complete handlers from running.
I am sure I have missed something obvious, as I am sure this has worked in the past... If it helps, for a long time I've been running an october 16 build, and only recently updated to latest 1.x branch, and still seeing the issue.
Last edited by Daniil; Feb 07, 2013 at 4:05 AM.
Reason: [CLOSED]