i stuck with a problem which is really important i guess.
In a simple Sencha Touch App I have many views. My Mainview is a TabPanel with docking icons in the bottom. Sometimes in my App I switch to another views which are outside of the Tabpanel. I don't want the DOM to overload with views, i don't need anymore so i'm searching for a solution to destroy a view, when its inactive.
I've tried this, while switching into another view in my controller:
this.getMainview().destroy();
It seems that the Mainview gets deleted but I get an error:
Uncaught TypeError: Cannot read property 'dom' of null
So i guess something's wrong with the .destroy() - Method or is there a better way to handle this problem?
Before moving to new view you can call bellow code to remove current view
Ext.Viewport.remove(Ext.Viewport.getActiveItem(), true);
or you can also provide item object instead ActiveItem
I've got stucked with this problem many times before. It seems that currently, there's no efficient and actually bug-free solution in Sencha Touch 2. When the view is added again at second time, that unpleasant error will show again.
A possible solution:
This code snippet:
your_container(your_container.getActiveItem(), false);
will not actually destroy your sub-component from memory but from the DOM. Later when you add it, there will be no error (as I've tested).
Hope it helps.
I'll expose my situation and how I solved it.
I have a TabPanel with icons. One of those tabs shows a List of items. When you click on an item you're taken to a new Panel that shows its description. If you click a Back button, that Panel is destroyed and you return to the List. This way you destroy the "description" Panel which is unused now.
So what I did was creating a function to instantiate the Description Panels depending on the index of the Item clicked:
function project(i) {
var v;
switch(i) {
case 0:
v = Ext.create( 'Ext.Panel', {
title: 'title',
layout: { type: 'fit' },
id: 'project0',
iconCls: '',
style: '',
html: 'my html'
});
break;
}
return v;
}
Now, in the 'itemtap' event of the List I have this:
var lastItem = container.add(project(i));
itemsList.hide(); //hide the List and display only the new Panel in the container
Now, I have a button in the header to return to the previous View (i.e. the List), and this is the event 'tap' of that button:
container.remove(lastItem, true); //hide and destroy it
itemList.show(); //show the List again
So if I go back and forth between the List and the Description items (Panels) now there is no problem as I get a new instance everytime I clicked on them and likewise it gets destroyed when I return.
That solved my problem.
Related
I have a main window with a custom Ext.panel.Panel using ExtJS 5.0.1.
Clicking an item shown on the custom panel creates and shows a custom Ext.window.Window for editing said item.
For the purpose of getting some kind of answer, or a starting point for my own situation, I'll ask for standard Ext components.
On closing the custom window, a variable in the custom panel needs to be updated to show that changes have been made.
This is a different requirement to a confirmation message before closing the window; the window does not control saving of information to a DB, but needs to let another component know that changes have been made.
This should be as simple as setting a boolean unsavedChanges to true on the panel if the window's information has been altered; I've performed this on a simpler page, which did not have the additional window as an obstacle.
Due to the use of the window, my typical go-to methods of calculating a variable as use of this.up or this.lookupReference returns null, or throw an error.
I'm aware that I can consider going to the parent of the page, then try and work down, but I'm not experienced enough to consolidate standard javaScript with the up and down capabilities of ExtJS, or at least understand the intricacies of ExtJS to navigate past the "item window" back to the panel.
How would I be able to refer to the panel while closing the window in order to update the panel's data?
Well, there's a couple of ways.
First, you can pass in your panel, or a callback function, during the construction of the window. e.g.:
// in panel
var window = Ext.create('MyWindow', { callingPanel: this })
...
// in window
onClose: function() { this.callingPanel.doStuff(); }
The other way to be to register a listener to the 'close' event of the window.
// in panel
var window = Ext.create('MyWindow', {
listeners: {
scope: this,
close: this.doStuff
}
})
The listener approach tends to work best when you don't want to tightly couple the window to the calling panel.
The case is pretty common, when you dbl click a cell in a grid, modal window with a form appearing, there you make changes, click the Save button, and having the store in a grid updated. In 4-th I did it via loadRecord from grid to form, and then used set-method to apply changes to grid store. Now I'm trying to do it with MVVM approach, and having some stucks. Because when I set the same VM to the grid and form, after form destroying (Save or Cancel button) the VM is also destroying, and the app ruining. And so, we can't use one VM instanse in multiple components. We have to place it in a container, where a grid and a form are. All official examples are of such a type.
And the question is, if anybody resolved this issue?
fiddle
answer from sencha forum
ExtJs 5 ViewModel has nested structure for components, all sub-objects can to use parent's ViewModel. So you could try to add window object to ViewController view:
var form = Ext.create('Plus.view.FormbetV');
var window = Ext.create('Ext.Window', {
frame: true,
width: 350,
height: 200,
modal: true,
layout: 'fit'
});
window.add(form);
this.getView().add(window); // <--- add parent 'scope'
window.show();
And don't forget to remove this code:
//var viewModel = Ext.getCmp('gridbet').getViewModel();
//this.setViewModel(viewModel);
It works for me, but in this case windows size will be limited by grid size.
In addition to user1638582's answer, my own solution was to add selected record to ViewModel of form:
var form = Ext.create('Plus.view.FormbetV',{
viewModel:{
data:{
currentRec:this.getView().getSelectionModel().getSelection()[0]
}
}
});
https://fiddle.sencha.com/#fiddle/jp6
Looking at the examples, the "Data Binding -> Isolated Child Sessions" seems to be what we're looking for:
http://dev.sencha.com/ext/5.1.0/examples/kitchensink/#binding-child-session
Have you read through this blog post, in which an MVVM example for the grid is used?
I'm trying to insert a list in a navigation view after click on a button, but didnt show anything, i put a button to test and the button appeared but the list didn't.
here is the code: http://snipt.org/Bzfe0
Thanks
this line: view.add
should be view.push
push is the proper way to push new view into a navigation controller, not add
Update: I have just looked at your fiddle, let's add these 2 lines to your Main.js
xtype: 'container',
layout: 'vbox'
Explanation:
You must specify the xtype of the item which will be added, in this case, container is the best choice. If not, the framework won't understand it as a sencha component and treat as normal Javascript objects, which lack a lot of initializers.
The layout of your new item must be vbox because you might want to display both list and button in a vertical order.
I have a class called SettingsBar that extends TitleBar in Sencha Touch 2.3. This SettingsBar I'm using has several buttons on it. When you click the Settings button then the bar is added to the panel and it shows up just fine.
You can click the buttons on the SettingsBar and different things will happen in the app. I have it setup so that you can make the SettingsBar disappear if you click the Settings button again. So the Settings button adds and removes the SettingsBar.
When the SettingsBar is added, and you click some of the buttons, then the SettingsBar is removed, the state of the SettingsBar isn't saved. The buttons go back to their original text (their text changes when you click them) and the event handling for them no longer works. You just click them and nothing happens.
Here's my code that adds and removes the SettingsBar:
settingsTap: function(){
if(settingsToolbar.added){
Ext.getCmp('mainview').removeAt(2);
console.log('added: '+settingsToolbar.added);
}else{
Ext.getCmp('mainview').add(settingsToolbar);
console.log('added: '+settingsToolbar.added);
}
settingsToolbar.added = !settingsToolbar.added;
}
The event handling is being done in my controller. Why would the buttons be reset and event handling on them removed when the SettingsBar is removed from the panel?
This is troublesome and has been asked for several times.
The safest way which even works when you destroy the component completely when removing it (you should always do, it reclaims a lot of memory), is to declare the event handlers in the initialize function of that component, or its parent component, wherever you think suitable, for example:
initialize: function(){
var me = this;
me.add({
xtype: 'list',
grouped: true,
indexBar: true,
itemTpl: '{first} {last}',
listeners: [
{
event: 'itemtap',
fn: function(dataview, index, target, record, e){
// do something
}
}
]
});
}
This is an example for itemtap event on a Ext.List. Let's adapt it to your case.
By default, child components are destroyed when they are removed from a container. When speaking of Ext components, "destroy" means removing all listeners and references, so that the object can be cleaned out by the garbage collector.
You can prevent destruction of removed components by changing the autoDestroy option of the container (the title bar, in your case). Don't forget however that you'll have to call the destroy method of each components yourself when you're done with them, or you'll be creating a memory leak in your app.
I have a table with a button to add a new element and another in the row to edit the element. Those actions shares the same form with the only difference that in edit mode the form is filled. When the user clicks on the button a new window is shown with the form.
The first time that i click the button, for example, to add a new element, works fine. The form is shown. But... if i close the window and i try to edit a user, appears an extrange window without content and an error "TypeError: b is null" Is it a problem with the definition of the form? Maybe the form istance is deleted with the window?
I've a form defined in a var:
var formPanel = Ext.create('Ext.form.Panel',{
extend: 'Ext.form.Panel',
id: 'policyForm',
...
I have a button in the tbar of the grid to show the window in order to add an user and another button in the row to edit him. This is the handler of the button:
handler : function(){
Ext.create('Ext.window.Window',{
layout: 'fit',
title: 'New Policy',
items: [formPanel],
width: 650,
height: 500,
id: 'myPolicyWindow'
}).show();
}
It is very likely that those ids that you have set in your Panel and Window code are causing you to not be able to reuse the same form in different windows. You should try to avoid using the id property on Ext components, it can cause issues like this one since IDs should be unique. Use the itemId property in conjunction with Ext.ComponentQuery to allow for getting references to components without using Ext.getCmp(compId).
I agree that you shouldn't use ids. However, the actual issue is probably what you suspect: the instance of the form is getting destroyed. This is because the default closeAction of Ext.window.Window is "destroy", which will wipe out any child components as well. Either change closeAction to "hide", or create a new instance of the form panel along with the new instance of the window.