I have a ViewModel, which is empty, as the bind data is set dynamically elsewhere, which works fine -
Ext.define('TestApp.model.modelView', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test',
singleton: true
});
From my main view, I call a view on a button click, where I create a new window and display it
Ext.define('TestApp.view.main.Main', {
extend: 'Ext.container.Viewport',
xtype: 'app-main',
requires: [
'TestApp.model.modelView'
],
viewModel: {
type: 'test'
},
items: [
{
...
items: [
{
xtype: 'button',
text: 'Read Out',
margin: '5 10 0 10',
handler: function () {
win = Ext.create('TestApp.view.ReadOutButtonTemplate');
TestApp.Controllers.ReadOutButtonController.windowOpened();
}
},
Here is the window layout
Ext.define('TestApp.view.ReadOutButtonTemplate',
{
extend: 'Ext.window.Window',
alias: 'roTemplate',
itemId: 'roWindow',
requires: [
'TestApp.model.modelView'
],
viewModel: {
type: 'test'
},
controller: 'roTemplate',
xtype:'buttonTemplate',
autoShow: true,
height: 600,
width: 600,
constrainHeader: true,
title: 'Window',
Each time I create a window, I want to add it to the model view, and each time I close a window, if I have multiple open, I only want to destroy the one the cross was clicked on, which I have attempted to reflect in -
listeners:{
'close': function (win) {
win.destroy();
}
}
I have a feeling that each time I open a new window, it is creating a completely new ViewModel, which then when I destroy it, it is destroying the whole ViewModel, then not allowing me to use it for other windows that are still open, and in reality I want each window to be independent but using the same window template. Any help of thoughts on how to tackle this would be appreciated as I'm struggling to find any documentation on it.
Note - There are also controllers attached to the app, but these are working as I would expect.
Related
I've searched the net for answer but didn't find anything. Hope you can help.
So I am relativly new to extJs. I have a navigation bar on the left. When I press the first button there, a new window opens, which contains a table and loads its data automatically. The first time it works perfect but when I close the window and open it again I get the error "cannot call method getRange of null".
If I open the second window (when I click the other button in my navigation bar), I have 4 tabs, which contain a table each. Each Tab has a toolbar with buttons (create, change, etc.). Here happens the same thing as by the first window.
I can also print those tables as a List and the first time works fine, but when I cancel the print action I get the error again.
I made sure that all buttons and tables have a different reference, so I really don't know what this could be.
Any ideas?
I add my panels, which will open the new windows here:
items: [
{
xtype: 'tabpanel',
region: 'center',
items: [{
// 1. Tab
xtype: 'componentTap-panel',
title: UMA.Locale.rm.component.componentTitle,
id: 'componentTab'
}, {
// 2. Tab
title: UMA.Locale.rm.componentGroup.componentGroupTitle,
xtype: 'componentGroupTap-panel',
id: 'componentGroupTab'
}, {
// 3. Tab
title: UMA.Locale.rm.componentTemplateTitle,
xtype: 'componentTamplate-panel',
id: 'componentTemplateTab'
},
{
//4.Tab
title: UMA.Locale.rm.inventoryTitle,
xtype: 'inventoryTab-panel',
id: 'inventoryTab'
}
]
}
]
When the window opens I add my table and toolbar:
items: [{
xtype: 'toolbar',
region: 'north',
reference: 'componentToolbar',
items: [{
text: UMA.Locale.rm.buttonCreate,
action: 'createComp'
}, {
text: UMA.Locale.rm.buttonChange,
action: 'changeComp'
}, {
text: UMA.Locale.rm.buttonMove,
action: 'moveComp'
}, {
text: UMA.Locale.rm.buttonDelete,
action: 'deleteComp'
},{
text: UMA.Locale.rm.buttonPrint,
action: 'print',
margin: {
left: 8
}, {
xtype: 'componentTable-panel',
region: 'center'
}, {
xtype: 'componentsFilter-panel',
width: 300,
region: 'east'
}]
and then autoload my table:
items:[{
xtype: 'filtergrid',
reference: 'componentGrid',
paging: true,
hideHeaders: false,
region: 'center',
selModel: new Ext.selection.RowModel({
mode: "MULTI"
}),
store: {
model: 'Component',
autoLoad: true
},
columns: [{ ...
As Sergey Novikov mentioned that getRange() is a store method.
I also faced the same error for my grid's store and after some review again and again I found that whenever I close the tab and reopen it again I am getting two instance of grid's view (which can be checked by grid.getView()) and then I reached a conclusion that whenever the grid is creating the second time the selection model of grid view is having two instances because of I am using the code for selModel as new Ext.selection.CheckboxModel({
showHeaderCheckbox: true,
width: 50,
mode: 'MULTI'
})
then I changed the code for selModel as
selModel: {
selType: 'checkboxmodel',
showHeaderCheckbox: true,
width: 50,
mode: 'MULTI'
}
and the error is gone for me.
Hope this will help you. :)
Use the Object() constructor to test whether the object is one of three subtypes:
null object
object object
array object
For example:
function foo() { return {"hi":"bye" } }
function bar() { return null }
function baz() { return [1,2,3] }
function testObject(myObject)
{
if (Object(myObject).hasOwnProperty("0") )
{
/* Call getRange */
return 'yes';
}
else
{
/* throw an exception */
return 'no';
}
}
console.log(testObject(foo()), testObject(bar()), testObject(baz()) );
I just started with Extjs and I have few basic doubts.I have created a simple view(ScreenPropertiesPage) which has 1 select box and 1 custom view inside it. onchange of the select box value, view field is updated which is done in controller. I am done with creating view and controller which has listener for onchange select box value and updates associated view field.
But now the problem is : in my application I have to create 4 instances of ScreenPropertiesPage view and when onchange event is triggered from any views the textbox of 1st view is updated always. How to combine the event to specific view? What is the best procedure to combine controller and views and to reuse it(Even link to the documents from where I can learn controller view reusability is enough)? Any help is greatly appreciated.
Code skeleton for view:
Ext.define('Configurator.view.screenproperties.ScreenPropertiesPage', {
extend: 'Ext.container.Container',
alias: 'widget.screenpropertiespage',
requires: [
'Configurator.store.screenproperties.ScreenProperties'
],
autoScroll: true,
config: {
overLayMode: false
},
initComponent: function () {
var me = this;
this.items = [{
xtype: 'container',
componentCls: 'screenComboSelectorPanel',
layout: {
type: 'hbox',
align: 'center',
pack: 'center'
},
items: [{
xtype: 'combo',
store: Ext.create(
'Configurator.store.screenproperties.ScreenProperties'
),
itemId: 'screenSelector',
margin: 3,
width: 400,
listConfig: {
maxHeight: 200
},
fieldLabel: 'Screen Name',
disabledCls: 'disabledBtn',
disabled: me.getOverLayMode(),
queryMode: 'local',
emptyText: '-SELECT-',
valueField: 'screenName',
displayField: 'screenName',
forceSelection: true,
selectOnTab: true,
autoSelect: true,
height: 25,
tpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<div class="x-boundlist-item comboContainer "><div class="rowExpanedrTextArea " style="">{screenName} </div>{[this.isExpandable(xkey,parent,values,xindex)]}</div>',
'</tpl>'
),
displayTpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'{screenName}',
'</tpl>'
)
}]
}, {
xtype: 'screenpropertieseditor',
itemId: 'messagesEditor',
margin: '25',
header: true,
frame: false,
border: true,
collectionName: 'messages',
title: 'Messages'
}]
me.callParent(arguments);
}
});
When user changes the value in combobox I want to update the screenpropertieseditor type view.
Controller for view :
Ext.define('Configurator.controller.ScreenProperties', {
extend: 'Ext.app.Controller',
refs: [{
ref: 'screenPropertiesPage',
selector: 'screenpropertiespage'
}, {
ref: 'screenSelector',
selector: 'screenpropertiespage combobox[itemId=screenSelector]'
}, {
ref: 'screenPropertiesMessagesEditor',
selector: 'screenpropertieseditor[itemId=messagesEditor]'
}, {
ref: 'screenPropertiesPage',
selector: 'screenpropertiespage'
}],
init: function (application) {
var me = this;
this.control({
'screenpropertiespage combobox[itemId=screenSelector]': {
change: this.screenPropertiesPageStoreHandler
}
});
},
screenPropertiesPageStoreHandler: function (thisObj, eOpts) {
var messagesEditor = this.getScreenPropertiesMessagesEditor();
var screenSelector = this.getScreenSelector();
var screenSelected = screenSelector.getValue();
//Screen tile store first time loading handling
if (screenSelected === undefined) {
screenSelected = screenSelector.getStore().getAt(0).data.screenName;
}
var selectedRecord = screenSelector.getStore().findRecord(
'screenName',
screenSelected, 0, false, false, true);
if (selectedRecord != undefined) {
Ext.apply(messagesEditor, {
'screenName': screenSelected
});
try {
messagesEditor.bindStore(selectedRecord.messages());
} catch (e) {}
}
}
});
ScreenPropertiesPage will hava lot more extra fields along with this. I have to create multiple instances of ScreenPropertiesPage. screenPropertiesPageStoreHandler method of Configurator.controller.ScreenProperties will be triggered whenever value changes in the combobox of any ScreenPropertiesPage view. But since my ref and selector in controller are not proper it always refers to the first ScreenPropertiesPage view.
You need to know that Controller in Extjs is singleton.
But you can force Controller in your case ScreenProperties to handle multiple instances of views. This is done by firing events from particular view instance to Controller to handle more complex logic.
Before i throw an example you need to be aware that using refs with handling multiple instance of the same view is wrong because it uses this code(it is just a wrapper): Ext.ComponentQuery.query('yourComponent')[0]; So from your view instances pool it gets first.
So you need to get rid off refs in your controller since it does not work with multiple instance of the same view.
Alright, lets make this happen and implement good way to handle multiple instances of the same view/components.
In your view:
initComponent: function () {
var me = this;
this.items = [{
xtype: 'container',
componentCls: 'screenComboSelectorPanel',
layout: {
type: 'hbox',
align: 'center',
pack: 'center'
},
items: [{
xtype: 'combo',
store: Ext.create(
'Configurator.store.screenproperties.ScreenProperties'
),
itemId: 'screenSelector',
margin: 3,
width: 400,
listConfig: {
maxHeight: 200
},
fieldLabel: 'Screen Name',
disabledCls: 'disabledBtn',
disabled: me.getOverLayMode(),
queryMode: 'local',
emptyText: '-SELECT-',
valueField: 'screenName',
displayField: 'screenName',
forceSelection: true,
selectOnTab: true,
autoSelect: true,
height: 25,
tpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<div class="x-boundlist-item comboContainer "><div class="rowExpanedrTextArea " style="">{screenName} </div>{[this.isExpandable(xkey,parent,values,xindex)]}</div>',
'</tpl>'
),
displayTpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'{screenName}',
'</tpl>'
),
listeners: {
change: function (cmp, newValue, oldValue) {
this.fireEvent('onCustomChange',cmp,newValue, oldValue)
},
scope: this
}
}]
}
In your Controller - ScreenProperties you need to listen on this event and handle particular instance of component in view:
init: function (application) {
var me = this;
this.listen({
// We are using Controller event domain here
controller: {
// This selector matches any originating Controller
'*': {
onCustomChange: 'onCustonChangeHandler'
}
}
});
},
onCustonChangeHandler: function(componentInstance, newValue, oldValue) {
//Your complex logic here.
//componentInstance is the instance of actual component in particular view
}
In this way you can handle multiple instances of the same view with one controller since every particular component that is created in your view is passed by event.
I am completely new to Sencha 2 Touch. This is my second day playing with it.
I have a custom class (app/view/Howdy.js):
Ext.define('MyApp.view.Howdy', {
extend: 'Ext.Panel',
xtype: 'howdy', // <--- this creates the 'howdy' xtype reference right?
requires: [
'Ext.SegmentedButton'
],
config: {
fullscreen: true,
html: ['Hello Word.'].join("")
}
});
and I am now trying to load it into a tab when clicked:
Ext.define('MyApp.view.Main', {
extend: 'Ext.tab.Panel',
config: {
fullscreen: true,
tabBarPosition: 'bottom',
items: [
{
title: 'TAB 1',
iconCls: 'star',
xtype: 'howdy', // <--- WHY IS THIS CRASHING MY APP?
},
]
}
});
If I remove the xtype declaration inside TAB 1 and replace it with an html everything works fine. As soon as I try and load my custom view into the tab all I get is a white screen in my browser and console shows no errors ???
P.S Yes everything is setup correctly already in App.js:
views: ['Howdy','Main'],
HELP PLEASE!
Late to update this thread but the solution was simply to remove the fullscreen: true declaration from inside the config in MyApp.view.Howdy.
I hope that this will help you:
MyApp.view.Howdy
Ext.define('MyApp.view.Howdy', {
extend: 'Ext.Container',
xtype: 'howdy',
requires: [
'Ext.SegmentedButton'
],
config: {
incoCls: 'star',
title: 'TAB 1',
html: ['Hello Word.'].join("")
}
});
MyApp.view.Main
Ext.define('MyApp.view.Main', {
extend: 'Ext.tab.Panel',
config: {
fullscreen: true,
tabBarPosition: 'bottom',
items: [
{xclass: 'MyApp.view.Howdy'},
]
}
});
You should use alias: widget.XTYPE
Ext.define('MyApp.view.Howdy', {
extend: 'Ext.Panel',
alias: 'widget.howdy', // <--- this creates the 'howdy' xtype reference right?
requires: [
'Ext.SegmentedButton'
],
config: {
fullscreen: true,
html: ['Hello Word.'].join("")
}
});
A couple of things. First, xtype is what you use to define the type if you're adding it instantly...if you haven't already defined it with Ext.create. If you've already created it, then you don't need it. When creating panels, each item contains all the info for itself, title, icon, everything. Then, just add the item(s) into a tabPanel:
var a = Ext.create('Ext.Panel',{
iconCls:'star',
title:'tab1',
html:'tab one content'
});
var b = Ext.create('Ext.Panel',{
iconCls:'star',
title:'tab2',
html:'tab two content'
});
var panel = Ext.create('Ext.TabPanel',{
items:[a,b]
});
I'm having trouble knowing if I syntactically have this setup right. From another thread, I understand to add the GridPanel to the tabBar items, which I do so below. In my App.js, I define a grid copied from the ExtJS example (here).
var grid = new Ext.grid.GridPanel({
// Details can be seen at
// http://dev.sencha.com/deploy/ext-3.4.0/docs/?class=Ext.Component?class=Ext.grid.GridPanel
});
Below that, I create an instance of my app:
appname.App = Ext.extend(Ext.TabPanel, {
fullscreen: true,
tabBar: {
ui: 'gray',
dock: 'bottom',
layout: { pack: 'center' }
},
cardSwitchAnimation: false,
initComponent: function() {
if (navigator.onLine) {
// Add items to the tabPanel
this.items = [{
title: 'Tab 1',
iconCls: 'tab1',
xtype: 'tab1',
pages: this.accountPages
}, {
title: 'Tab 2',
iconCls: 'tab2',
xtype: 'tab2',
pages: this.accountPages
},
grid];
} else {
this.on('render', function(){
this.el.mask('No internet connection.');
}, this);
}
appname.App.superclass.initComponent.call(this);
}
});
The app normally loads just fine, but with the addition of grid, it breaks and nothing loads.
Syntactically, should I be defining grid inside the app instantiation like A) grid: ..., B) this.grid = new ..., or C) as I have it as a regular var named grid?
Many thanks.
There is no inbuilt GridPanel comes with Sencha Touch. So, that Ext.grid.GridPanel will not work here. However, you can use Simoen's TouchGrid extension from here.
All the source codes are available here.
I seem to be having a weird issue here. An extended component has the following code:
MyApp.panels.RelationshipDetails = Ext.extend(Ext.FormPanel, {
closable: true,
relationshipId: null,
documentId: null,
title: 'Relationship',
initComponent: function () {
if (!this.verifyRequiredData()) {
MyApp.panels.RelationshipDetails.superclass.initComponent.call(this);
return;
}
// Build components
this.tbar = this.buildToolbar();
this.items = this.buildDetailItemArray();
MyApp.panels.RelationshipDetails.superclass.initComponent.call(this);
},
verifyRequiredData: function () {
// Verification code here
},
buildDetailItemArray: function () {
return [{
xtype: 'fieldset',
title: 'Details',
collapsible: true,
autoHeight: true,
items: [{
xtype: 'hidden',
name: 'Id'
}, {
xtype: 'textfield',
fieldLabel: 'Name',
name: 'Name'
}, {
xtype: 'textfield',
fieldLabel: 'Description',
name: 'Description'
}, {
xtype: 'button',
text: 'Save',
name: 'saveButton'
}]
}];
},
buildToolbar: function () {
return new Ext.Toolbar({
// Toolbar Config
});
}
});
The issue is that when this panel renders, the toolbar is the only thing that renders. Through debugging I can see that BuildDetailItemArray() is being called correctly and returning the correct result.
It gets even weirder when I comment out the this.tbar = line, because when the toolbar is not present, the fieldset and field renders correctly. This occurs even if I extend Panel instead of FormPanel. I also tried abstracting out the form fields into it's own component, and the same thing occurs.
Anyone have any idea why this doesn't seem to work?
What sort of layout are you trying to put this panel into? Also, are you setting a height for this panel?
Often, if you aren't specifying a height for the component to be added (in your case, this panel), or you're not setting an anchor if using an AnchorLayout, component content won't be shown, but the toolbar still will.
It'd be good to know the context of this panel in your overall layout.