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

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);
}
}

Related

List item disclosure isn't firing inside a controller

I'm trying to get the item disclosure to work in a list item in Sencha Touch using a controller ref. But the event never seems to fire/receive inside controller. All of the examples I've seen have the list item using a listener but I thought that wasn't very MVC so I'm trying to do it this way (is there any reason why they use listeners instead of a controller?)
In my view, the list is an item inside the EnquiryIndex view.
When I do this in a console window it returns the list correctly so I know the ref is working ok:
Ext.ComponentQuery.query("enquiryindexview list")[0]
See below example:
Ext.define('MyApp.controller.EnquiryIndex', {
extend: 'Ext.app.Controller',
requires: [
],
config: {
refs: {
enquiryIndexViewRef: 'enquiryindexview list'
},
control: {
'enquiryIndexViewRef': {
disclose: 'onDiscloseEnquiryIndex'
}
}
},
onDiscloseEnquiryIndex: function (rec) {
// never gets here!
}
});
Try this
config: {
control: {
'enquiryindexview list': {
disclose: 'onDiscloseEnquiryIndex'
}
}
or this
config: {
refs: {
enquiryIndexViewRef: 'enquiryindexview list'
},
control: {
enquiryIndexViewRef: {
disclose: 'onDiscloseEnquiryIndex'
}
}
Hope this helps
What you might have missed doing is adding this line in the app.js
controllers: ['EnquiryIndex'],
Try this out, it should work now.

How can I get a view in Sencha Touch 2 from within a controller by calling a function automatically generated by the ref config?

I have defined a controller in Sencha, that includes a refs attribute referencing my view, yet whenever I call the automatically generated "get" function to get the view, based on the refs attribute, it returns undefined. Here is my example:
I have the following controller in app/controller/Locals.js:
Ext.define('MobileUnion.controller.Locals', {
extend: 'Ext.app.Controller',
// Base class methods.
launch: function () {
this.callParent(arguments);
},
init: function () {
this.callParent(arguments);
},
config: {
refs: {
localsEditorView: 'localseditorview',
},
control: {
localsEditorView: {}
}
},
slideUpTransition: { type: 'cover', direction: 'up' },
onEditLocalsCommand: function() {
this.activateLocalsEditor();
},
activateLocalsEditor: function() {
var localsEditorView = this.getLocalsEditorView();
console.log(localsEditorView); // Returns "undefined" to console.
Ext.Viewport.animateActiveItem(localsEditorView, this.slideUpTransition);
}
});
I have the following view in app/views/LocalsEditor.js:
Ext.define('MobileUnion.view.LocalsEditor', {
extend: 'Ext.Panel',
alias: 'widget.localseditorview',
config: {
html: 'This is the new view which should show up on top!'
},
});
So, in the above example, if I call this.getLocalsEditorView() from within my controller, I get "undefined" even though I set a refs attribute as localsEditorView: 'localseditorview' and I defined MobileUnion.view.LocalsEditor to include an alias of widget.localseditorview. I feel like I should get the view when I do this.
By the way, I did define the view in the views attribute of my app.js, so that's not it.
Further information: there's no actual error being returned in my webkit console. Just the call to console.log() noted above in my controller returns undefined, rather than the view object.
Question: What do I have to do to make this function return the view, and not undefined? Any help would be appreciated. I've looked to make sure it's not just a typo; it does not seem to be.
The "refs" is to create references to existing components. So far all you've done is declare a class, from what you've posted you've never instanced it anywhere.
You might want to read the docs about autoCreate here:
http://docs.sencha.com/touch/2-1/#!/api/Ext.app.Controller-cfg-refs

Events not caught by Controller

I am trying to respond to a view-fired event inside a controller. The event does fire, but the controller action is never called.
View:
Ext.define("MyApp.view.Dashboard", {
extend: 'Ext.Container',
xtype: 'my_dashboard',
config: {
items: [
{
xtype: 'dataview',
listeners: {
itemtap: function(sender, index, elem, record) {
// fires with param, e.g. 'inbox'
this.fireEvent(record.get('name'));
}
}
}
...
Controller:
Ext.define('MyApp.controller.Dashboard', {
extend: 'Ext.app.Controller',
config: {
control: {
'my_dashboard': {
'inbox': 'showInbox',
...
}
}
},
showInbox: function () {
/* never gets called */
},
...
What am I doing wrong?
UPDATE:
I found a solution, but it feels very hacky. I added a bubbleEvents config to the dataview and the my_dashboard view, and the events started making their way up to the controller.
Since the dashboard can have a variable number of items, I don't know which events I need to bubble up. Of course, I could bubble up all possible dashboard events, but that just seems like a massive kludge.
Should the view fire an application event instead, e.g. MyApp.app.fireEvent()?
I would put an itemId on the dataview.
itemId: 'my_dashboard_dataview'
Then in your controller...
control: {
'#my_dashboard_dataview': {
'itemtap': 'showInbox',
...
}
}
UPDATE
Here is some code that should get you started:
Controller:
Ext.define('MyApp.controller.Dashboard', {
extend: 'Ext.app.Controller',
config: {
control: {
'my_dashboard': {
painted: 'onDashboardPainted',
inbox: 'showInbox'
}
}
},
onDashboardPainted: function(dashboard, eOpts) {
dashboard.down('dataview').on('itemtap', function(sender, index, elem, record){
dashboard.fireEvent(record.get('name'));
//check the console to make sure you the value is: inbox
console.log(record.get('name'));
});
},
showInbox: function () {
console.log('showInbox init');
},
This is definately a scope issue... in your controller add a painted function for my_dashboard... the first function variable will be the my_dashboard component itself:
painted: function(dashboard,...
Now in the painted function add the listener dynamically:
dashboard.down('dataview').on( ... rest of listener code ...
Now inside of the listener do dashboard.fireEvent(....);
Sorry for the formatting im on my mobile, if u cant get it to work i will post code tomorrow

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

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
}
...