PDA

View Full Version : [CLOSED] Left and right buttons in the text field



NewLink
Apr 17, 2020, 7:27 PM
Hello support team,
I intend to create my own picker with buttons inside the input field:

View


@using Ext.Net;
@using Ext.Net.MVC;

@{
Layout = null;
var X = Html.X();
}

<!DOCTYPE html>

<html>
<head>
<script type="text/javascript" src="~/IconFieldTest/widget/IconField.js?@DateTime.Now"></script>

<script type="text/javascript">
function show() {
new Ext.window.Window({
xtype: "window",
closeAction: "destroy",
hidden: true,
items: [{
xtype: "iconfield",
padding: 10
}]
}).show();
}
</script>
</head>

<body>
@(X.ResourceManager())

@(X.Container()
.Items(
X.Button().Text("Show Window").Width(100).Margin(10).AutoFocus(true).Handler("show()")
)
)
</body>
</html>


Component


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

Ext.define("Ext.ux.form.IconField", {
extend: "Ext.form.field.Picker",
alias: "widget.iconfield",

leftButtons: [{
iconCls: "#Shading",
}],

rightButtons: [{
iconCls: "#ArrowNsew",
}],

createPicker: function () {
var me = this,
picker = new Ext.panel.Panel({
pickerField: me,
floating: true,
hidden: true,
ownerCt: this.ownerCt,
renderTo: document.body,
bodyPadding: 5,
height: 300
});

return picker;
}
});


Ext JS 7.1.0.46 / Ext.NET 5.1.0

Everything is OK the first time the window is displayed. However, when I close it and try to open for a second time, I get a "Cannot read property 'apply' of null" error message. I found that the left and right buttons are causing the problem. When they are removed from the component, no error occurs and the window can be opened and closed as many times as you want.

I tried to play with different destroy methods, but it did not lead to any satisfactory outcome. Can you help me, please?

Thank you for your effort.

Kind regards
Dan

fabricio.murta
Apr 17, 2020, 9:49 PM
Hello Dan!

This one was tricky! The way you extended the component is the problem.

Don't:



leftButtons: [{
iconCls: "#Shading",
}],

rightButtons: [{
iconCls: "#ArrowNsew",
}]


But rather:



initComponent: function () {
this.leftButtons = [{
iconCls: "#Shading",
}];

this.rightButtons = [{
iconCls: "#ArrowNsew",
}];

return this.callParent(arguments);
}


Why? Because in your original approach, you are binding an array to the extended component's prototype. When the left/right buttons are built and their entry updated, the array gets changed and, although the prototype still points to the same array, the first array element is updated to that entry.

Then, when destroy() wipes away the component (when the window is closed), it cleans up the reference to the destroyed component within the instance, yet the reference will be left in the array that you bound to the extended component's "prototype".

Transferring it to the initComponent function ensures the components' default sub-elements are like you specified. In the example above it will -always- have the left and right buttons (and discard anything you might specify during creation); you could improve it in case you want to support specifying left/right buttons on a per-instance level by adjusting how it binds the variables (checking if it has some value before and merging the arrays if so).

This happens and may be seen as a limitation of javascript that always handles objects as reference and side effects like that can occur all the time.

Hope this helps!

NewLink
Apr 17, 2020, 10:20 PM
Hi Fabrício, of course it helps ...

Thank you for your super fast response. Moving the button configuration to initComponent really solved the trouble.

However, when I slightly extend the code by LoadMask (I can't use the mask() method because I need more control over the mask), I get a "Cannot read property 'viewModel' of null" error after closing window:



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

Ext.define("Ext.ux.form.IconField", {
extend: "Ext.form.field.Picker",
alias: "widget.iconfield",

fieldMask: null,

initComponent: function () {
this.leftButtons = [{
iconCls: "#Shading",
}];

this.rightButtons = [{
iconCls: "#ArrowNsew",
}];

this.fieldMask = new Ext.LoadMask({
msg: "Loading icons ...",
target: this
});

//this.fieldMask.msgWrapEl.addCls("nelis-iconfield-mask-msg");
//this.fieldMask.msgEl.addCls("nelis-iconfield-mask-msg-inner");
// ...

return this.callParent(arguments);
},

createPicker: function () {
var me = this,
picker = new Ext.panel.Panel({
pickerField: me,
floating: true,
hidden: true,
ownerCt: this.ownerCt,
renderTo: document.body,
bodyPadding: 5,
height: 300
});

return picker;
},

onDestroy: function () {
this.fieldMask = null;
}
});


Please can you help me to resolve this problem as well? Because this might be related to the previous issue, I continue in the same thread. Otherwise, please let me know, and I'll open a new ticket.

Thank you for your assistance.

Kind regards
Dan

NewLink
Apr 20, 2020, 6:13 PM
Hi Fabrício,
if I use this.fieldMask.destroy() instead of this.fieldMask = null in the onDestroy method, everything works fine.

I also created a new Ext.panel.Panel() for the picker each time a different set of icons was loaded, which is not the correct approach and caused the same error that I resolved with this.fieldMask.destroy(). When using removeAll and add instead of recreating the picker from scratch whenever the content is changed, this error is also fixed.

Thank you again for your assistance, the ticket can be closed.

Kind regards
Dan

fabricio.murta
Apr 21, 2020, 4:55 PM
Hello Dan!

Glad you could make it work the way you needed, thanks for the feedback!

On a side note, I would not get notified that your previous answer became a question because you edited it -- and last time I saw it, it was just about the solution we provided, preliminarily, working. So when you have something substantial to add to your last post, it is better to make a new post instead of appending to the last post you did, so we get notified of the new question.

Hope this helps, and closing.