sencha touch 2 optimization - sencha-touch-2

Attached is a my controller file .. i basically want to switch views .. adding and removing a panel in a container with 2 buttons .. in the method for home and popular button i am using Ext.create again and again wouldnt that overload my application becoz iam not destroying my views iam adding and removing them .. My main question is how can i create global var 's for this situation like i create var homepanel = Ext.create just once and then i can reuse that var when i want to remove or add it from my mainContainer.. need serious guidance on this .. searched the whole documention but i dont have any clue about it
Ext.define('app.controller.MainController', {
extend: 'Ext.app.Controller',
config: {
refs: {
homeBtn: '#homeBtn',
popularBtn: '#popularBtn',
homePanel: '#homePanel',
mainContainer: '#mainContainer'
},
control: {
homeBtn:{
tap: 'homeBtnAction'
},
popularBtn:{
tap: 'popularBtnAction'
}
}
},
launch: function(app) {
this.callParent(arguments);
console.log("main launched");
var mainCont = this.getMainContainer();
var homepanel = Ext.create('app.view.Home.HomePanel');
mainCont.add(homepanel);
console.log("homePanelAdded");
},
homeBtnAction: function(){
console.log("home page called");
var mainCont = this.getMainContainer();
var homepanel = Ext.create('app.view.Home.HomePanel');
var popularpanel = Ext.create('app.view.Popular.PopularPanel');
mainCont.remove(popularpanel);
mainCont.add(homepanel);
},
popularBtnAction: function(){
console.log("popular page called");
var mainCont = this.getMainContainer();
var homepanel = Ext.create('app.view.Home.HomePanel');
var popularpanel = Ext.create('app.view.Popular.PopularPanel');
mainCont.remove(homepanel);
mainCont.add(popularpanel);
}
});
NOTE: Iam using Ext.define to create my views and using MVC structure.

Use this,
var homepanel = this.getHomePanel() || Ext.create('app.view.Home.HomePanel');
if this.getHomePanel() does not return anything it'll create the panel for you. After that you'll use the already created panel.
Other note, unless you are manipulating the buttons in some manner there is no need to give them an id or a ref.
Set up your button in your view like so
{
xtype : 'button',
text : 'Home Panel',
action : 'goHome'
}
then in the control section of your controller use this
'button[action=goHome] :
{
tap: 'homeBtnAction'
}

One option is : in "launch", you create both views (with Ext.Create) and use Ext.getCmp in action button callbacks to retrieve the previously created views.

Related

sencha touch getView()?

How can I call getView(view_name)` in Sencha touch? I usually do this on extjs but I can't in sencha touch. I could not understand the application concept.
run_edit: function(data) {
$this = this;
this.mode = "update";
this.data = data;
this.win = this.getView('Group_prop').create();
var form = this.win.down('form');
var util = this.getController('controller_Helper');
form.getForm().loadRecord(data);
util.form_lock({
form:form,
items:['GROUP_KODE']
});
util.form_require({
form:form,
items:['GROUP_KODE','GROUP_NAMA']
});
this.win.show();
},
I see you are trying to create a view and set it to window, in sencha touch you can do it like this:
Ext.Viewport.add(Ext.create('MyApp.view.ViewName'));
instead of Viewport you can take any other container and set newly created view to it
Ext.getCmp('myContainerId').add(Ext.create('MyApp.view.ViewName'));
to fetch this view later, you have to specify id config in view and then get it like this:
var view = Ext.getCmp('ViewId');
Ok so it seems like you are trying to get the view: Group_prop. Make sure this view has an id or preferably an itemId set in its config. e.g
Ext.define('MyApp.view.GroupProb', {
extend: 'Ext.Panel',
alias: 'widget.group_prob',
config: {
...
itemId: 'groupProb',
...
},
....
});
Now in your controller you need to create a reference for this view to access it properly. So your controller would look something like this:
Ext.define('MyApp.controller.MyController', {
extend: 'Ext.app.Controller',
config: {
refs : {
groupProb : {
autoCreate: true,
selector: '#groupProb',
xtype: 'group_prob'
}
},
control: {
...
},
...
},
run_edit: function(data) {
$this = this;
this.mode = "update";
this.data = data;
this.win = this.getView('Group_prop').create();
var form = this.win.down('form');
var util = this.getController('controller_Helper');
form.getForm().loadRecord(data);
util.form_lock({
form:form,
items:['GROUP_KODE']
});
this.win.show();
},
...
});
Now from your run_edit function, its seems like you are working with windows from the this.win variable (correct me if I'm wrong). Well in Sencha Touch, you work with Panels. Also at the end of this function you call the show function on this.win, which suggests that you want to execute run_edit when the this.win is shown. That being said, you may want to your run_edit function to look something like this:
run_edit: function() {
var me = this,
mode = 'update',
data = data,
groupProbPanel = me.getGroupProb();
// This assumes that your form component has an itemId.
// You need one inorder use the down method.
var form = groupProbPanel.down('#form_itemId');
// You may want to double check this. I don't think that is how you
// you get the controller.
var util = this.getController('controller_Helper');
form.getForm().loadRecord(data);
util.form_lock({
form:form,
items:['GROUP_KODE']
});
}
Since we want this to happen when groupProbPanel is shown we need to set a show event listener in our control config. So your controller's config should look like this:
...,
config: {
refs : {
groupProb : {
autoCreate: true,
selector: '#groupProb',
xtype: 'group_prob'
}
},
control: {
groupProb : {
show: 'run_edit'
},
...
},
...
},
...
Two ways is there to call the Views
1.
Ext.Viewport.setActiveItem({xtype:'TwowayMakePayment'}); // view xtype
2.
var getti=Ext.create('VUCFyn.view.AfterLogin'); //create object 4 d view
Ext.Viewport.add(getti); // next add the object
Ext.Viewport.setActiveItem(getti); // final Active that obj

Sencha Touch 2: Call controller function from within Ext.Msg.confirm

I'm just getting started with Sencha Touch 2 and I have never worked with Sencha Touch 1.x before. I've just finished this tutorial (which is the best starter tutorial I have found so far) http://miamicoder.com/2012/how-to-create-a-sencha-touch-2-app-part-1/ and now I want to go ahead and extend this Notes App.
I have a controller and 2 views, a list view and an edit view. In the edit view I want to be able to delete the current record. The delete function is in the controller. After tapping the delete button, I want to show a confirmation dialog ("Are you sure you want to delete...?"). After the user presses yes, the delete function should be called.
Now my problem is: How do I call the controllers delete function from within Ext.Msg.confirm?
Here are the relevant snippets of my code. Please let me know if something important is missing.
Please see the "onDeleteNoteCommand" function. "this.someFunction" obviously doesn't work since "this" is a DOMWindow.
Ext.define('TestApp2.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
noteEditorView: 'noteeditorview'
},
control: {
noteEditorView: {
deleteNoteCommand: 'onDeleteNoteCommand',
}
}
},
onDeleteNoteCommand: function() {
console.log('onDeleteNoteCommand');
var noteEditor = this.getNoteEditorView();
var currentNote = noteEditor.getRecord();
Ext.Msg.confirm(
"Delete note?",
"Do you reall want to delete the note <i>"+currentNote.data.title+"</i>?",
function(buttonId) {
if(buttonId === 'yes') {
//controller functions!! how to call them?
this.deleteNote(currentNote);
this.activateNotesList();
}
}
);
},
deleteNote: function(record) {
var notesStore = Ext.getStore('Notes');
notesStore.remove(record);
notesStore.sync();
},
activateNotesList: function() {
Ext.Viewport.animateActiveItem(this.getNotesListView(), this.slideRightTransition);
},
slideLeftTransition: { type: 'slide', direction: 'left' },
slideRightTransition: { type: 'slide', direction: 'right' },
launch: function() {
this.callParent();
Ext.getStore('Notes').load();
console.log('launch main controller');
},
init: function() {
this.callParent();
console.log('init main controller');
}
});
When you enter callback function of Ext.Msg the scope changes from controller scope to global scope (window), so you must set up it as parameter of confirm method:
Ext.Msg.confirm(
"Delete note?",
"Do you reall want to delete the note <i>"+currentNote.data.title+"</i>?",
function(buttonId) {
if(buttonId === 'yes') {
this.deleteNote(currentNote);
this.activateNotesList();
}
},
this // scope of the controller
);
For more info please check sencha docs: http://docs.sencha.com/touch/2-0/#!/api/Ext.MessageBox-method-confirm

Add a custom button in column header dropdown menus {EXTJS 4}

I want a button in column header dropdown menu of grid in extjs4.
so that i can add or delete columns which are linked in database.
Any help will be appreciated...
Thankyou..:)
Couple of months ago I had the same problem. I've managed to solve it by extending Ext.grid.header.Container (I've overrided getMenuItems method). However, recently, I've found another solution which requires less coding: just add menu item manualy after grid widget is created.
I'll post the second solution here:
Ext.create('Ext.grid.Panel', {
// ...
listeners: {
afterrender: function() {
var menu = this.headerCt.getMenu();
menu.add([{
text: 'Custom Item',
handler: function() {
var columnDataIndex = menu.activeHeader.dataIndex;
alert('custom item for column "'+columnDataIndex+'" was pressed');
}
}]);
}
}
});
Here is demo.​
UPDATE
Here is demo for ExtJs4.1.
From what I have been seeing, you should avoid the afterrender event.
Context:
The application I am building uses a store with a dynamic model. I want my grid to have a customizable model that is fetched from the server (So I can have customizable columns for my customizable grid).
Since the header wasn't available to be modified (since the store gets reloaded and destroys the existing menu that I modified - using the example above). An alternate solution that has the same effect can be executed as such:
Ext.create('Ext.grid.Panel', {
// ...
initComponent: function () {
// renders the header and header menu
this.callParent(arguments);
// now you have access to the header - set an event on the header itself
this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
this.createHeaderMenu(menu);
}, this);
},
createHeaderMenu: function (menu) {
menu.removeAll();
menu.add([
// { custom item here }
// { custom item here }
// { custom item here }
// { custom item here }
]);
}
});
For people who would like to have not just one "standard" column menu but have an individual columnwise like me, may use the following
initComponent: function ()
{
// renders the header and header menu
this.callParent(arguments);
// now you have access to the header - set an event on the header itself
this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
menu.on('beforeshow', this.showHeaderMenu);
}, this);
},
showHeaderMenu: function (menu, eOpts)
{
//define array to store added compoents in
if(this.myAddedComponents === undefined)
{
this.myAddedComponents = new Array();
}
var columnDataIndex = menu.activeHeader.dataIndex,
customMenuComponents = this.myAddedComponents.length;
//remove components if any added
if(customMenuComponents > 0)
{
for(var i = 0; i < customMenuComponents; i++)
{
menu.remove(this.myAddedComponents[i][0].getItemId());
}
this.myAddedComponents.splice(0, customMenuComponents);
}
//add components by column index
switch(columnDataIndex)
{
case 'xyz': this.myAddedComponents.push(menu.add([{
text: 'Custom Item'}]));
break;
}
}
I took #nobbler's answer an created a plugin for this:
Ext.define('Ext.grid.CustomGridColumnMenu', {
extend: 'Ext.AbstractPlugin',
init: function (component) {
var me = this;
me.customMenuItemsCache = [];
component.headerCt.on('menucreate', function (cmp, menu) {
menu.on('beforeshow', me.showHeaderMenu, me);
}, me);
},
showHeaderMenu: function (menu) {
var me = this;
me.removeCustomMenuItems(menu);
me.addCustomMenuitems(menu);
},
removeCustomMenuItems: function (menu) {
var me = this,
menuItem;
while (menuItem = me.customMenuItemsCache.pop()) {
menu.remove(menuItem.getItemId(), false);
}
},
addCustomMenuitems: function (menu) {
var me = this,
renderedItems;
var menuItems = menu.activeHeader.customMenu || [];
if (menuItems.length > 0) {
if (menu.activeHeader.renderedCustomMenuItems === undefined) {
renderedItems = menu.add(menuItems);
menu.activeHeader.renderedCustomMenuItems = renderedItems;
} else {
renderedItems = menu.activeHeader.renderedCustomMenuItems;
menu.add(renderedItems);
}
Ext.each(renderedItems, function (renderedMenuItem) {
me.customMenuItemsCache.push(renderedMenuItem);
});
}
}
});
This is the way you use it (customMenu in the column config let you define your menu):
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
plugins: ['Ext.grid.CustomGridColumnMenu'],
columns: [
{
dataIndex: 'name',
customMenu: [
{
text: 'My menu item',
menu: [
{
text: 'My submenu item'
}
]
}
]
}
]
});
The way this plugin works also solves an issue, that the other implementations ran into. Since the custom menu items are created only once for each column (caching of the already rendered version) it will not forget if it was checked before or not.

Extending controller in ExtJS 4 MVC application

I building my ExtJS 4 application following the MVC structure. I want to make an extendable grid MyGrid with some functionality that I can reuse several times. Therefore, I guess, it should have its own controller which is also extended, so that the functionality is inherited. How is this properly done?
In the code below I illustrate how I extend the controller MyGrid with MyExtendedGrid. I realize that I'm overriding the init function in the MyGrid controller, so that it is never called. Is the problem simply solved by calling the "super" init in MyGrid from MyExtendedGrid init, or merge the control objects? Is that the proper way to do this in the MVC spirit? If so, how?
controller/MyGrid.js :
Ext.define('App.controller.MyGrid', {
extend: 'Ext.app.Controller',
refs: [
{
ref: 'myGridView',
selector: 'mygrid'
}
],
init: function() {
var me=this;
me.control({
'mygrid textfield[name=searchField]': {
change: function() {
var view = me.getMyGridView();
// Do something with view
}
}
});
}
});
controller/MyExtendedGrid.js :
Ext.define('App.controller.MyExtendedGrid', {
extend: 'App.controller.MyGrid',
views: [
'grids.MyExtendedGrid'],
refs: [
{
ref: 'myExtendedGridView',
selector: 'myextendedgrid'
}
],
init: function() {
var me=this;
me.control({
'myextendedgrid': {
// Some control code
// Using getMyExtendedGridView()
}
});
}
});
view/grids/MyGrid.js :
Ext.define('App.view.grids.MyGrid', {
extend: 'Ext.grid.Panel',
alias : 'widget.mygrid',
requires: [
],
store: '', // Not defined here
columns: [ ], // Not defined here
initComponent: function() {
var me = this;
me.tbar = [
'Search',
{
xtype: 'textfield',
name: 'searchField',
hideLabel: true,
width: 150
}
];
me.callParent(arguments);
}
});
view/grids/MyExtendedGrid.js :
Ext.define('App.view.grids.MyExtendedGrid', {
extend: 'App.view.grids.MyGrid',
alias : 'widget.myextendedgrid',
store: 'MyStore',
columns: [
// ...
],
initComponent: function() {
var me = this;
me.bbar = [
//...
];
me.callParent(arguments);
}
});
It's actually a bit trickier...
Here is what we did in our application (we have exact same situation - some kind of base controller, that is reused in many different places)
Keep init function in base controller.
Define common base method in this base controller (like gridRendered - where you need to do something for all controllers all the time).
Subscribe to the events in all child controllers but subscribe events using methods of base controller. It won't work otherwise - base controller doesn't have proper refs to properly subscribed to events.
I can post couple source snippets, but I think it's pretty straightforward.
Ok, after some thinking I decided on the following solution, which has the advantage that mygrid does not need to know about myextendedgrid.
I extend my gridview as in the question.
I gave the base grid its own controller for doing common functionality, for instance deleteButton.setDisable(false) when something is selected in the grid.
Next, I remind myself that using refs:[ (for instance with selector: 'mygrid') would ambiguously point to both instances of the base class any extended instances. When using me.control({ I instead get the relevant grid by traversing from the activated element using up:
me.control({
'mygrid textfield[name=searchField]': {
change: function(searchfield) {
var grid=searchfield.up('mygrid'); // (mygrid or myextendedgrid!)
// Do something with view
}
}
...
The extended grid I give its own controller and here I could use refs. I don't extend the controller from the MyGrid class (but rather from 'Ext.app.Controller'), unless I would like to use functions or variables from the MyGrid controller. All the controllers are started from app.js using:
Ext.application({
controllers: [
'MyGrid'
'MyExtendedGrid',
],
...
In order to get the grid when rows are selected in the grid, I stored the grid in the selection model as below:
In controller/MyGrid.js :
me.control({
'mygrid': {
afterrender: function(grid) {
var selModel=grid.getSelectionModel();
selModel.myGrid=grid;
},
selectionchange: function(selModel, selected, eOpts) {
var grid=selModel.theLookupGrid;
// Do something with view
}
...

How do I get a Sencha controller to respond to a swipe event in a view?

I have a dataview that I would like to detect a swipe on. It'd be great if I could listen for that in the controller, but as far as I understand I can't do that. My testing bears this out. So instead I need to listen in the view for the event. Currently I'm doing that in the initialize method of my data view like so:
initialize: function() {
var el = Ext.get("list");
el.on('swipe', function(event) {
alert(event.direction);
});
}
So a couple of things:
Is my understanding correct, that I have to listen for DOM events like this in the view?
Is this the best way to set the swipe listener on the dataview? I couldn't seem to make it work through the config object.
How do I then let my controller know about the swipe? It will need to manipulate the view when the swipe happens (like change the view size). What are the best practices in this area?
Thanks in advance.
It is always better to put the events for a component inside the controller. So, first create a ref for that dataview in your controller.
refs : {
listView : 'list' //Or a selector to get the reference
},
control : {
listView : {
// Dataview has an "itemswipe" event - not "swipe" event
itemswipe : function(dataview, index, target, record){
//Do here what you want
}
}
}
This should work (not tested).
I think this is what you are after, its the same idea just changing the scope to the controller:
Ext.define('app.controller.myListControler', {
extend: 'Ext.app.Controller',
config: {
refs: {
list: { selector: 'myList', autoCreate: true, xtype: 'myList' }
}
},
init: function () {
},
launch: function () {
this.getList().on('swipe', this.onSwipe);
},
onSwipe: function (event) {
console.log(event.direction);
}
}