mishoboss
16 Dec 2011, 12:47 AM
Thank you for that suggestion. I did it, but the Heap keeps going larger and larger and the app gets slower:
Ext.getCmp('content').on('activeitemchange', function(container, newcard, oldcard, opts) { oldcard.removeAll(true); });
I think there are other objects created that I don't remove. But I don't know why. This is the app - http://m-design.bg/sencha/. Click on the first 4 rows to go to other pages. This way the app creates and removes items. And here is the whole app code. I would be very thankful if you take a snap look at it and tell me if you see something wrong :) Thank you.
Ext.require(['Ext.Panel', 'Ext.Button', 'Ext.Toolbar', 'Ext.util.JSONP', 'Ext.dataview.ComponentView']);
var UIobjects = new Object();
var currentCard = "card1";
var broadCrumb = new Array();
function pushWidget(widget, container) {
if (widget) {
container.push(widget);
}
}
function buildUIArray(json, type, parent) {
if (json) {
var container;
if (type == 'page') {
UIobjects[json.id] = new Array();
container = UIobjects[json.id];
} else if (type == 'frame') {
parent.push(new Object({
xtype: 'fieldset',
title: json.label
}));
container = parent[parent.length - 1]['items'] = new Array();
}
var page_data = json.widget;
if (Ext.isArray(page_data)) {
for (var i in page_data) {
pushWidget(addsWidget(page_data[i], container), container);
}
} else {
pushWidget(addsWidget(page_data, container), container);
}
json = null;
} else {
alert('There was an error retrieving the UI.');
}
}
function addsWidget(data, container) {
var widget;
if (data.type == "Switch") {
widget = new Object({
xtype: 'togglefield',
label: data.label
});
} else if (data.type == "Slider") {
widget = new Object({
xtype: 'sliderfield',
label: data.label,
value: data.item.state,
minValue: 0,
maxValue: 100
});
} else if (data.type == "Text") {
widget = new Object({
xtype: 'textfield',
label: data.label,
value: data.item ? data.item.state : data.label,
readOnly: true
});
} else if (data.type == "Group") {
widget = new Object({
xtype: 'button',
text: data.label,
style: 'display:block',
page_id: data.linkedPage.id,
handler: tapHandler,
baseCls: 'x-form-label x-field',
labelCls: ''
});
buildUIArray(data.linkedPage, 'page', '');
} else if (data.type == "Frame") {
buildUIArray(data, 'frame', container);
}
return widget;
}
var tapHandler = function (btn, evt) {
broadCrumb.push(btn.page_id);
Ext.getCmp("content").getLayout().setAnimation({
type: 'slide',
direction: 'left'
});
goToPage(btn.page_id);
}
var goToPage = function (page) {
if (currentCard == "card1") {
currentCard = "card2";
} else {
currentCard = "card1";
}
Ext.getCmp(currentCard).setItems(UIobjects[page]);
Ext.getCmp("content").setActiveItem(currentCard);
}
Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function () {
//var server_url = 'http://192.168.90.176:8080';
var server_url = 'http://m-design.bg/sencha';
var backPage = function () {
if (broadCrumb.length > 1) {
broadCrumb.pop();
Ext.getCmp("content").getLayout().setAnimation({
type: 'slide',
direction: 'right'
});
goToPage(broadCrumb[broadCrumb.length - 1]);
}
}
var makeJSONPRequest = function () {
Ext.getCmp('content').setMask({
message: 'Loading...'
});
Ext.util.JSONP.request({
url: 'http://m-design.bg/sencha/json.txt',
//url: server_url+'/rest/sitemaps/demo',
callbackKey: 'jsoncallback',
params: {
key: Math.random()
},
callback: function (result) {
buildUIArray(result.homepage, 'page', '');
Ext.getCmp('content').unmask();
broadCrumb[0] = result.homepage.id;
//console.log(UIobjects);
Ext.getCmp(currentCard).setItems(UIobjects[result.homepage.id]);
result = null;
}
});
};
var panel = Ext.create('Ext.Panel', {
layout: {
type: 'card',
animation: {
type: 'slide',
direction: 'left'
}
},
fullscreen: true,
id: 'content',
autoDestroy: true,
animation: {
type: 'slide',
direction: 'left'
},
items: [{
id: 'card1',
scrollable: 'vertical',
autoDestroy: true
}, {
id: 'card2',
scrollable: 'vertical',
autoDestroy: true
}, {
docked: 'top',
xtype: 'toolbar',
ui: 'light',
items: [{
text: 'Back',
handler: backPage
}, {
xtype: 'spacer'
}, {
text: 'Load UI',
handler: makeJSONPRequest
},
]
}]
});
Ext.getCmp('content').on('activeitemchange', function (container, newcard, oldcard, opts) {
oldcard.removeAll(true);
});
}
});
mishoboss
17 Dec 2011, 6:12 AM
I just can't get through this problem. I debug the app via Google Chrome. I take heap snapshots continuously and compare them. It seems that there are created way more Object, Array and String entries than deleted.
I've done some changes since my previous post. I've attached listeners to the buttons with delegation and I also remove listeners from the old card on card change. I thought maybe listeners are my problem, but it seems they're not.
Please, take a look at the app HERE
(http://m-design.bg/sencha/)Don't enter anything in the Server field, just press "Login", then select the Demo interface.
And the code:
Ext.require(['Ext.Panel', 'Ext.Button', 'Ext.Toolbar', 'Ext.util.JSONP', 'Ext.dataview.ComponentView']);
//-------- PATCH FOR BUTTON TO ACCEPT HTML TEXT -----------
//----- won't be needed in the next Sencha releases -------
Ext.define('Ext.overrides.button.updateHtml', {
override: 'Ext.Button',
updateHtml: function (html) {
var element = this.textElement;
if (html) {
element.show();
element.update(html);
} else {
element.hide();
}
}
});
//-------------------- END PATH -----------------------
var UIobjects = new Object();
var currentCard = "card1";
var broadCrumb = new Array();
var broadCrumbText = '';
var server_url;
var sitemapsStore = new Ext.data.Store({
fields: ['name', 'link']
});
function showLoginWindow() {
var login = Ext.create('Ext.Panel', {
floating: true,
modal: true,
centered: true,
width: '90%',
height: 300,
items: [{
title: 'Login',
xtype: 'toolbar',
ui: 'light',
docked: 'top'
}, {
xtype: 'urlfield',
label: 'Server',
id: 'server_settings',
autoCorrect: true,
placeHolder: 'http://localhost:8080',
required: true,
value: localStorage.getItem('openHAB_server')
}, {
xtype: 'textfield',
label: 'Username',
id: 'username_settings',
placeHolder: 'username',
disabled: true
}, {
xtype: 'passwordfield',
label: 'Password',
id: 'password_settings',
placeHolder: 'password',
disabled: true,
style: 'margin-bottom:10px;'
}, {
xtype: 'button',
text: 'Login',
style: 'display: block; margin: auto; width:150px;',
handler: function () {
server_url = Ext.getCmp('server_settings').getValue();
if (server_url.substring(0, 7) != "http://") {
server_url = "http://" + server_url;
}
localStorage.setItem('openHAB_server', server_url);
Ext.util.JSONP.request({
url: server_url + '/rest/sitemaps/jsonp',
//url: 'http://m-design.bg/sencha/sitemaps.txt',
callbackKey: 'jsoncallback',
headers: {
'Accept': 'application/json',
},
params: {
key: Math.random()
},
callback: function (result) {
login.destroy(true);
sitemapsStore.loadData(result.sitemaps);
showSitemapsWindow();
},
onFailure: function (result) {
console.log('error');
}
});
}
}]
});
Ext.getCmp('content').add(login);
}
function showSitemapsWindow() {
var sitemapSelect = Ext.create('Ext.Panel', {
floating: true,
modal: true,
centered: true,
width: '90%',
height: 300,
layout: 'fit',
scrollable: 'vertical',
items: [{
title: 'Interfaces',
xtype: 'toolbar',
ui: 'light',
docked: 'top'
}, {
xtype: 'list',
store: sitemapsStore,
singleSelect: true,
itemTpl: '{name}',
onItemDisclosure: function (record, btn, index) {
loadUIData(record.data.link);
sitemapSelect.destroy(true);
}
}]
});
Ext.getCmp('content').add(sitemapSelect);
}
function loadUIData(url) {
Ext.getCmp('content').setMask({
message: 'Loading...'
});
Ext.util.JSONP.request({
url: server_url + '/rest/sitemaps/demo/jsonp',
//url,
//url: 'http://m-design.bg/sencha/ui.txt',
callbackKey: 'jsoncallback',
headers: {
'Accept': 'application/json',
},
params: {
key: Math.random()
},
callback: function (result) {
buildUIArray(result.homepage, 'page', '');
Ext.getCmp('content').unmask();
broadCrumb[0] = new Array(result.homepage.id, result.name);
Ext.getCmp('title').setHtml(result.name);
//console.log(UIobjects);
Ext.getCmp(currentCard).setItems(UIobjects[result.homepage.id]);
Ext.getCmp(currentCard).on({
delegate: 'button',
tap: tapHandler
});
result = null;
}
});
};
function backPage() {
if (broadCrumb.length > 1) {
broadCrumb.pop();
Ext.getCmp("content").getLayout().setAnimation({
type: 'slide',
direction: 'right'
});
goToPage(broadCrumb[broadCrumb.length - 1][0]);
}
}
function pushWidget(widget, container) {
if (widget) {
container.push(widget);
}
}
function buildUIArray(json, type, parent) {
if (json) {
var container;
if (type == 'page') {
UIobjects[json.id] = new Array();
container = UIobjects[json.id];
} else if (type == 'frame') {
parent.push(new Object({
xtype: 'fieldset',
title: json.label
}));
container = parent[parent.length - 1]['items'] = new Array();
}
var page_data = json.widget;
if (Ext.isArray(page_data)) {
for (var i in page_data) {
pushWidget(addsWidget(page_data[i], container), container);
}
} else {
pushWidget(addsWidget(page_data, container), container);
}
json = null;
} else {
alert('There was an error retrieving the UI.');
}
}
function addsWidget(data, container) {
var widget;
if (data.type == "Switch") {
if (data.item.type == "RollershutterItem") {
widget = createRollershutterWidget(data.label, data.icon, data.item.state)
} else {
widget = createToggleWidget(data.label, data.icon, data.item.state);
}
} else if (data.type == "Slider") {
widget = createSliderWidget(data.label, data.icon, data.item.state);
} else if (data.type == "Text") {
if (data.linkedPage) {
widget = createLinkWidget(data.label, data.icon, data.linkedPage.id, data.linkedPage.label);
buildUIArray(data.linkedPage, 'page', '');
} else {
widget = createTextWidget(data.label, data.icon, data.item.state);
}
} else if (data.type == "Group") {
widget = createLinkWidget(data.label, data.icon, data.linkedPage.id, data.linkedPage.label);
buildUIArray(data.linkedPage, 'page', '');
} else if (data.type == "Selection") {
widget = createSelectionWidget(data.label, data.icon, data.item.state, data.mapping);
} else if (data.type == "Frame") {
buildUIArray(data, 'frame', container);
}
return widget;
}
var tapHandler = function (btn, evt) {
broadCrumb.push([btn.page_id, btn.page_label]);
Ext.getCmp("content").getLayout().setAnimation({
type: 'slide',
direction: 'left'
});
goToPage(btn.page_id);
}
var goToPage = function (page) {
if (currentCard == "card1") {
currentCard = "card2";
} else {
currentCard = "card1";
}
Ext.getCmp(currentCard).setItems(UIobjects[page]);
Ext.getCmp("content").setActiveItem(currentCard);
}
Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function () {
var panel = Ext.create('Ext.Panel', {
layout: {
type: 'card',
animation: {
type: 'slide',
direction: 'left'
}
},
fullscreen: true,
id: 'content',
autoDestroy: true,
items: [{
id: 'card1',
scrollable: 'vertical',
autoDestroy: true,
padding: 6,
cls: 'card1',
}, {
id: 'card2',
scrollable: 'vertical',
autoDestroy: true,
padding: 6,
cls: 'card2',
}, {
docked: 'top',
xtype: 'toolbar',
ui: 'light',
items: [{
id: 'back_btn',
ui: 'back',
text: 'Back',
handler: backPage,
hidden: true
}, {
xtype: 'spacer'
}, {
id: 'title',
xtype: 'label',
cls: 'oph_title'
}, {
xtype: 'spacer'
}
]
}]
});
Ext.getCmp('content').on('activeitemchange', function (container, newcard, oldcard, opts) {
oldcard.removeAll(true);
oldcard.clearListeners();
newcard.on({
delegate: 'button',
tap: tapHandler
});
if (broadCrumb.length == 1) {
Ext.getCmp('back_btn').hide();
} else {
Ext.getCmp('back_btn').show();
}
broadCrumbText = '';
for (var k in broadCrumb) {
broadCrumbText += broadCrumb[k][1];
if (k != broadCrumb.length - 1) {
broadCrumbText += ' > '
}
}
Ext.getCmp('title').setHtml(broadCrumbText);
});
showLoginWindow();
}
});
function createSliderWidget(label, icon, state) {
return {
xtype: 'sliderfield',
label: '<img class="oph_icon" src="' + server_url + '/images/' + icon + '.png" />' + label,
labelWidth: '60%',
value: 45,
minValue: 0,
maxValue: 100
};
}
function createTextWidget(label, icon, state) {
return {
xtype: 'textfield',
label: '<img class="oph_icon" src="' + server_url + '/images/' + icon + '.png" />' + label.replace(/\[(.*?)\]/, ''),
labelWidth: '60%',
value: label.match(/\[(.*?)\]/)[1],
readOnly: true
};
}
function createToggleWidget(label, icon, state) {
return {
xtype: 'togglefield',
label: '<img class="oph_icon" src="' + server_url + '/images/' + icon + '.png" />' + label,
labelWidth: '60%',
value: 1 //state == 'ON' ? 1 : 0
};
}
function createRollershutterWidget(label, icon, state) {
return {
xtype: 'field',
label: '<img class="oph_icon" src="' + server_url + '/images/' + icon + '.png" />' + label,
labelWidth: '60%',
html: '<div class="x-button-normal x-button x-layout-box-item oph_rollershutter_btn" style="margin-left:7px;"><span class="x-button-icon arrow_up x-icon-mask" ></span></div><div class="x-button-normal x-button x-layout-box-item oph_rollershutter_btn"><span class="x-button-icon delete x-icon-mask" ></span></div><div class="x-button-normal x-button x-layout-box-item oph_rollershutter_btn"><span class="x-button-icon arrow_down x-icon-mask" ></span></div>'
};
}
function createLinkWidget(label, icon, page_id, page_label) {
return {
xtype: 'button',
html: '<img class="oph_icon" src="' + server_url + '/images/' + icon + '.png" />' + label,
style: 'display:block',
baseCls: 'x-form-label x-field oph_group_btn',
page_id: page_id,
page_label: page_label,
labelCls: ''
};
}
function createSelectionWidget(label, icon, state, options) {
return {
xtype: 'selectfield',
labelWidth: '60%',
//value: state == "Undefined" ? options[1].command : state,
label: '<img class="oph_icon" src="' + server_url + '/images/' + icon + '.png" />' + label,
options: options,
displayField: 'label',
valueField: 'command'
}
};
Powered by vBulletin® Version 4.1.5 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.