This code is working in Extjs 4.0.2a
but when converted to 4.1 it no longer works and gives an error
Uncaught TypeError: Cannot call method 'query' of undefined
Ext.onReady(function() {
var panel = new Ext.Panel({
renderTo: divtag,
draggable: {
insertProxy: false,
onDrag: function(e) {
var el = this.proxy.getEl();
this.x = el.getLeft(true);
this.y = el.getTop(true);
},
endDrag: function(e) {
this.panel.setPosition(this.x, this.y);
}
},
title: 'Panel',
width: 200,
height: 100,
x: 20,
y: 20
});
});
Apparently there is a bug in this version of Ext. It wont work even if you try default D'n'D for panel like this:
Ext.onReady(function() {
var panel = new Ext.Panel({
renderTo: 'divtag',
draggable: true,
title: 'Panel',
width: 200,
height:100,
x: 20,
y: 20
}); //panel.show(); });
});
I menage to patch the code to work the way you want it, this code should work:
Ext.onReady(function() {
var panel = new Ext.Panel({
renderTo: 'divtag',
draggable: {
insertProxy: false,
onDrag: function(e) {
var el = this.proxy.getEl();
this.x = el.getX();
this.y = el.getY();
},
endDrag: function(e) {
panel.setPosition(this.x,this.y);
},
alignElWithMouse: function() {
panel.dd.superclass.superclass.alignElWithMouse.apply(panel.dd, arguments);
this.proxy.sync();
}
},
title: 'Panel',
width: 200,
height:100,
x: 20,
y: 20
}); //panel.show(); });
});
As a side note I should probably advice you not to do this anyway, because you can define your own DD for panel that you can use, and even better Ext already have one defined, so you can just override Ext panel to use default Ext.util.ComponentDragger, or in code, I advice you to do this:
Ext.override(Ext.panel.Panel, {
initDraggable: function() {
var me = this,
ddConfig;
if (!me.header) {
me.updateHeader(true);
}
if (me.header) {
ddConfig = Ext.applyIf({
el: me.el,
delegate: '#' + me.header.id
}, me.draggable);
// Add extra configs if Window is specified to be constrained
if (me.constrain || me.constrainHeader) {
ddConfig.constrain = me.constrain;
ddConfig.constrainDelegate = me.constrainHeader;
ddConfig.constrainTo = me.constrainTo || me.container;
}
me.dd = Ext.create('Ext.util.ComponentDragger', this, ddConfig);
me.relayEvents(me.dd, ['dragstart', 'drag', 'dragend']);
}
}
});
var panel = Ext.create('Ext.panel.Panel', {
id: 'test',
renderTo: 'divtag',
draggable: true,
floating: true,
title: 'Panel',
width: 200,
height:100,
x: 20,
y: 20
});
Code for a initDraggable function in panel override is taken from current stable version of Ext.window.Window.initDraggable method.
I was able to get it working in 4.1: you have to add quotes around the id of the renderTo element, like:
renderTo : 'divtag',
Without quotes it was looking for an undefined variable named divtag.
Once I ran that I got no errors, and then I just did panel.show() to render it.
Just a suggestion: a Window component is a specialized Panel that has a floating mixin - might be all you need.
Related
Using ExtJS Classic 7.3.0
Trying to animate the window while it is showing, but the title of the window is not ending up at the specifications in 'TO' config. Fiddle is here: Sencha Fiddle
If you try to drag the window by clicking on the "blue title", you will see the entire title how it should be, but thats it.
Anyone know if I need to specify something else here?
I tinkered with it a bit and found that it worked if you set the width property on the window:
width: Ext.getBody().getViewSize().width / 2,
Full code:
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.create('Ext.Window', {
id: 'win',
title: "Window",
width: Ext.getBody().getViewSize().width / 2,
html: "<h1>Hello</h1> ",
listeners: {
show: function (win) {
var el = win.getEl();
var size = Ext.getBody().getViewSize();
el.animate({
from: {
opacity: 0,
width: 0,
height: 0,
x: size.width/2,
y: size.height/2
},
to: {
opacity: 100,
width: size.width/2,
height: size.height/2,
x: size.width/4,
y: size.height/4
},
});
},
beforeclose: function (win) {
if (!win.shouldClose) {
win.getEl().fadeOut({
duration: 2000,
callback: function () {
win.shouldClose = true;
win.close();
}
});
}
return win.shouldClose ? true : false;
}
}
}).show();
}
});
width: '50%'
also seems to work.
I am using the below code -
afterListeners: function(thisEl, eOpts) {
sliderSprite = Ext.create('Ext.draw.sprite.Rect', {
width: spriteWidth, // half year width height : 20, x : 16, y : 0, draggable : true, floatable : true, 'stroke-width' : 2, fill : '#FCE5C5', stroke : '#C6B395' });
sliderSprite.show(true);
thisEl.getSurface().add(sliderSprite);
alert("before source");
new Ext.drag.Source({
element: sliderSprite,
constrain: {
// Drag only horizontal in 30px increments
horizontal: true, // snap: { // y: 30 // }
},
onDragMove: function() {
alert("inside source");
spriteHighlighter.remove();
me.onDragSprite(e, this, chartWidth, spriteWidth);
},
onDragEnd: function() {
me.refreshCharts(xPlots, bigChart, sliderSprite, firstYear, lastYear, chartWidth);
}
});
alert("outside source");
},
}
}
Now, the issue is, control doesn't go inside the Ext.drag.Source(). I get 2 alert messages ,before source and outside source. and because it doesn't go inside Ext.drag.Source().
The drag-able functionality of the element is not working. What should I do ?
First you need to be clear on which component you want to use. After that you need to put afterrender event on that component and inside of that event you can use Ext.drag.Source.
In this FIDDLE, I have created a demo using button and Ext.drag.Source.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
var buttons = [],
rendomColor = () => {
return "#" + ((1 << 24) * Math.random() | 0).toString(16);
};
for (var i = 0; i < 10; i++) {
buttons.push({
text: `Button ${i+1}`,
margin: 10,
style: `background:${rendomColor()}`
});
}
Ext.create({
xtype: 'panel',
height: window.innerHeight,
title: 'Ext.drag.Source Example',
defaults: {
xtype: 'button'
},
items: buttons,
renderTo: Ext.getBody(),
listeners: {
afterrender: function (panel) {
panel.items.items.forEach(item => {
new Ext.drag.Source({
element: item.el,
constrain: {
// Drag only vertically in 30px increments
//vertical: true,
snap: {
y: 1,
x: 1
}
}
})
})
}
}
});
}
});
I've got an application that is heavy on field usage. I noticed that adding new fields can be fairly expensive, even when using suspend/resumelayouts. Observing the timeline in Chrome, I can see quite a lot of recalculation of styles and forced layouts (seems like one per fields) for the panel div.
The code below is a simple representation of what I'm doing.
util = {
createTextField: function(myItemId) {
return Ext.create('Ext.form.field.Text', {
fieldLabel: 'Field' + myItemId + ':',
name: 'field',
itemId: myItemId,
autofocus: true,
enableKeyEvents: true,
labelAlign: 'left',
labelWidth: 50,
labelStyle: 'font-size: 16px;',
width: 500
});
}
}
Ext.onReady(function() {
Ext.create('Ext.Button', {
text: 'Click me',
renderTo: Ext.getBody(),
handler: function() {
for(i=0; i<100; i++)
{
Ext.suspendLayouts();
formPanel.add(util.createTextField(i));
Ext.resumeLayouts(true);
}
}
});
var formPanel = Ext.create('Ext.form.Panel', {
frame: true,
title: 'Form Fields',
width: 340,
height: 600,
bodyPadding: 5,
autoScroll: true,
fieldDefaults: {
labelAlign: 'left',
labelWidth: 90
}});
formPanel.render('form-ct');
});
The page itself is fairly straightforward:
<body>
<div id="form-ct"></div>
</body>
Right now pressing the button takes roughly ~2 seconds in Chrome and almost 4 in IE11. My question is whether this can be somehow optimized. Note that the fields must be rendered dynamically. I'm using ExtJS 4.1.
Start with moving suspendLayout/resumeLayout pair outside of the loop:
Ext.suspendLayouts();
for(i=0; i<100; i++)
{
formPanel.add(util.createTextField(i));
}
Ext.resumeLayouts(true);
Calling these inside the loop basically defeats the whole purpose of suspending layouts because you are forcing a relayout no less than 100 times in a row.
The add method is firing two events, add and beforeadd. You can instead using an array with components to add all at ones. Besides that you can use defaults and defaultType, but that will not do much I guess.
util = {
createTextField: function(myItemId) {
return Ext.create('Ext.form.field.Text', {
fieldLabel: 'Field' + myItemId + ':',
name: 'field' + myItemId // names are unique, we will use this to query components
});
}
}
Ext.onReady(function() {
Ext.create('Ext.Button', {
text: 'Click me',
renderTo: Ext.getBody(),
handler: function() {
// array to hold all components
var components = new Array();
// optimize the for loop and introduce y
for(var i = 0, y = 100; i < y; i++)
components.push(util.createTextField(i));
// add all components at ones to prevent multiple events fired
Ext.suspendLayouts();
formPanel.add(components);
Ext.resumeLayouts(true);
}
});
var formPanel = Ext.create('Ext.form.Panel', {
frame: true,
title: 'Form Fields',
width: 340,
height: 600,
bodyPadding: 5,
autoScroll: true,
// use defaultType and defaults to clean the code
defaultTypes: 'textfield',
defaults: {
autofocus: true,
enableKeyEvents: true, // this is heavy, consider if it is required
labelAlign: 'left',
labelWidth: 50,
labelStyle: 'font-size: 16px;',
width: 500
}
});
formPanel.render('form-ct');
});
My aim is simple, for some needs, I have to test the "pop-up function" in ExtJS via the widget.window.
I've created a button in HTML and a pop-u in a JS file, when I click it, everything works fine, the pop-up is well displayed.
The HTML button is coded this way :
<input type="button" id="popup-map" value="Pop Up"/>
And the JS refers to the button this way :
Ext.application({
name: 'popup',
launch: function() {
var popup,
button = Ext.get('popup-map');
button.on('click', function(){
if (!popup) {
popup = Ext.create('widget.window', {
title: 'Pop-Up',
header: {
titlePosition: 2,
titleAlign: 'center'
},
border: false,
closable: true,
closeAction: 'hide',
width: 800,
minWidth: 400,
maxWidth: 1200,
height: 500,
minHeight: 550,
maxHeight: 800,
tools: [{type: 'help'}],
layout: {
type: 'border',
padding: 2
},
items: [
{
region: 'center',
xtype: 'tabpanel',
items: [
mappanel,
{
title: 'Description',
html: 'Attributs de l\'objet sous forme de tableau'
}
]
}
]
});
}
button.dom.disabled = true;
if (popup.isVisible()) {
popup.hide(this, function() {
button.dom.disabled = false;
});
} else {
popup.show(this, function() {
button.dom.disabled = false;
});
}
});
Problem, if I have two buttons that contains the id "popup-map", only the first one declared is working. I guess it's pretty normal the way I've coded it.
How can I call the popup contains in the JS file by clicking several buttons in HTML ?
Thanks :-)
Use a CSS class instead of a duplicated id. Duplicated ids are bad, you know that... Then use Ext.query instead of Ext.get. Your code should look something like this:
Ext.onReady(function() {
var popup;
function handler(button) {
if (!popup) {
// ...
}
// you've got button and popup, do your things
}
// adds the handler to every button with class 'popup-map' on the page
Ext.query('button.popup-map', function(button) {
button.on('click', handler);
});
});
I'm using Ext.onReady to wait for the DOM to be ready before searching for buttons on the page. That also gives us a closure for our local variables popup and handler.
Thanks to #rixo, here's the code working.
I've created a empty css class called customizer.
Ext.onReady(function() {
var popup, popup_visible;
function popup_constructor() {
//alert(this.getAttribute('pwet'));
if (!popup) {
popup = Ext.create('widget.window', {
title: 'Pop-Up',
id: 'popup',
header: {
titlePosition: 2,
titleAlign: 'center',
height: 30
},
border: false,
closable: true,
closeAction: 'hide',
width: 800,
minWidth: 400,
maxWidth: 1200,
height: 500,
minHeight: 550,
maxHeight: 800,
tools: [{type: 'help'}],
layout: {
type: 'border',
padding: 10
},
items: [
{
region: 'center',
xtype: 'tabpanel',
plain: true,
items: [
{
title: 'Carte',
html: 'On mettra la carte ici',
border: false,
},
{
title: 'Description',
html: 'Attributs de l\'objet sous forme de tableau',
border: false,
}
]
}
]
});
}
popup_visible = true;
if (popup.isVisible())
{
popup.hide(this, function() {
popup_visible = false;
});
}
else
{
popup.show(this, function() {
popup_visible = false;
});
}
}
var popup_show = Ext.query('.customizer');
Ext.each(popup_show, function (item) {
item = Ext.get(item);
item.on('click', popup_constructor);
}, this);
});
I have a scroll menu contain files names. When I click on a file name in the menu, I want to create a window has the file name as a title.
In the code below I can create the window but without a title.
The problem is in the line ( title: jsonobj[ii], // I got undefined here ).
var scrollMenu = Ext.create('Ext.menu.Menu');
var files = Ext.Ajax.request({
url: 'php/getfiles.php',
success: function(response, opts) {
var jsonobj = Ext.decode(response.responseText);
for(var ii = 0; ii < jsonobj.length; ii++){
scrollMenu.add({
text: jsonobj[ii], // working good
handler: function () {
var winfile = Ext.create('widget.window', {
region: 'center',
height: 500,
width: 900,
x: 500,
y: 100,
title: jsonobj[ii], // not working
closable: true,
plain: true,
layout: 'fit',
preventBodyReset: true,
});
winfile.show();
}
});
}
},
failure: function(response, opts) {
console.log('somthing went wrong with this AJAX call' + response.status);
}
});
The problem is that all handler callbacks are defined in the same closure. That means that once ii is changed in scope of success callback - it automatically affects all handler callbacks. Since jsonobj[jsonobj.length] === undefined you always get undefined title. You should wrap handler with some other closure like below:
handler: (function(){
var title = jsonobj[ii];
return function () {
var winfile = Ext.create('widget.window', {
region: 'center',
height: 500,
width: 900,
x: 500,
y: 100,
title: title,
closable: true,
plain: true,
layout: 'fit',
preventBodyReset: true
});
winfile.show();
}
}())