I used mixins(EXT Js 4) in my project. I have following structure. Two classes named Class A and Class B with following function.
Ext.define('ClassA', {
classAFunction: function() {
alert("ClassAFunction in class A");
}
});
Ext.define('ClassB', {
classBFunction: function() {
alert("ClassBFunction in class B");
},
classAFunction: function() {
alert("ClassAFunction in class B");
}
});
In my controller i used mixins to extend the capability of my controller as shown in following code.
Ext.define(Site_Controller', {
extend: 'Ext.app.Controller',
views: [
'ui.Site_View'
],
mixins: {
classA: 'ClassA',
classB: 'ClassB'
},
init: function() {
this.control({
'MainPanel button[action=save]':{
click: this.CreateSite
}
});
},
CreateSite: function() {
alert("HELLO");
this.classAFunction;
this.classBFunction;
}
});
I call createsite method of controller on the click of button which is present in view. so when createsite method called first i got "HELLO" and than classAFunction called and it gives me "ClassAFunction in class A". So it call classA function But i want to call ClassAFunction which is present in classB. So In extjs how can i achive this.
Thanks in advance.
You can access the mixins and call the function directly
this.mixins.classB.classAFunction.call(this);
Related
deftjs looks really promising as it adds exactly the necessary things I missed in the MVC implementation of ExtJs.
What I actually miss is a functionality that makes routing possible/ easy. Extjs has a Ext.ux.Router functionality but I formerly used code like this with help of this lib:
initRoutes: function () {
var me = this;
Log.debug('Books.controller.App: initRoutes');
//use PATH.JS library until ExtJs supports routing as Sencha Touch 2.0 does. (see utils\Path)
Path.map("#/home").to(function () {
me.getController('Home').index();
});
Path.map("#/trackingsheet").to(function () {
me.getController('TrackingSheet').index();
});
Path.root('#/home');
Path.listen();
}
As the procedure of creating the crucial parts in deftjs is now exactly the other way around (view creates the controller) I certainly cannot refer to a controller's method and instantiate the view and make it the visible one. I have a pretty simple card layout here - what means only one view can be visible at a time, it is not necessary to go any deeper like this (e.g. make a task pane visible or the like).
What is the preferred way to do it?
I can think of making the Viewport a view factory having some methods like the controller before.
Thanks,
da5id
I solved this problem by using Ext.util.History class in a history context class that can raise an event when the hash changes:
Ext.define('myApp.context.HistoryContext', {
mixins: {
observable: 'Ext.util.Observable'
},
constructor: function(config) {
var me = this;
if (config == null) {
config = {};
}
this.initConfig(config);
Ext.util.History.add('home');
//init Ext.util.History; if there is a hash in the url,
//controller will fire the event
Ext.util.History.init(function(){
var hash = document.location.hash;
me.fireEvent('tokenChange', hash.replace('#', ''));
});
//add change handler for Ext.util.History; when a change in the token occurs,
//this will fire controller's event to load the appropriate content
Ext.util.History.on('change', function(token){
me.fireEvent('tokenChange', token);
});
this.mixins.observable.constructor.call(this);
this.addEvents('tokenChange');
return this.callParent(arguments);
}
});
Then you can inject this context in to your controller, and observe the token change, and implement the action in dispatch method:
Ext.define('myApp.controller.HomeController', {
extend: 'Deft.mvc.ViewController',
inject: [
'historyContext'
],
control: {
appContainer: {},
home: {
click: 'addHistory'
},
about: {
click: 'addHistory'
}
},
observe: {
historyContext: {
tokenChange: "dispatch"
}
},
init: function() {
return this.callParent(arguments);
},
switchView: function(view) {
//change this to get the cards for your card layout
this.getAppContainer().add(Ext.ComponentMgr.create({
xtype : view,
flex : 1
}));
},
addHistory: function(btn) {
var token = btn.itemId;
Ext.util.History.add(token);
},
dispatch: function(token) {
// switch on token to determine which content to load
switch(token) {
case 'home':
this.switchView('view-home-Index');
break;
case 'about':
this.switchView('view-about-Index');
break;
default:
break;
}
}
});
This should be ok for the first level routing (#home, #about), but you need to implement your own mechanism to fetch the token for the second and third level routes. (#home:tab1:subtab1) You can possibly create a service class that can handle fetching the hash and inject the service to each controllers to dispatch.
For further discussion in this topic, go to https://github.com/deftjs/DeftJS/issues/44
I have an app with a carousel. On all of the carousel pages there are elements such as buttons and datepickers. I would like to handle the tapStart event on each of these elements using Sencha Touch but I haven't been able to find anything to allow me to do this.
Does anyone have an idea?
UPDATE
I asked this question on the Sencha Forums as well. Here is the link to the Sencha Forum thread: http://www.sencha.com/forum/showthread.php?262804-Handle-tapStart-Event-on-a-button&p=963782#post963782
You can try using touchstart which can be bound to any element including button
I figured out a solution to my problem with help from the Sencha Touch Forums.
First I used the initConfig function to initialize my configuration of my container.
Ext.define('MyApp.view.ViewName', {
...
// Very Important, this is what I use in the controller to handle the events
xtype: 'myxtype',
...
initConfig: function () {
var me = this;
this.config = {
...
items: {
...
{
xtype: 'button',
...
listeners: {
element: 'element',
// This is where my code handles the tapstart
// (touchstart) event
touchstart: function () {
// Fire an event on the controller (me)
me.fireEvent('buttondown');
}
}
},
...
}
}
this.callParent([this.config]); // Very Important when using initConfig
}
});
Then, in my controller I added this code:
Ext.define('MyApp.controller.MainController', {
...
config: {
views: [
'ViewName',
...
],
...
},
...
init: function () {
this.control({
'myxtype': {
buttondown: this.myFunction
}
})
},
myFunction: function () {
// Do something
}
});
I have got a TabContainer class. This class is a extend of Ext.tab.Panel.
The create works fine, but, when i try send a message to instance Firebug says:
"TypeError: tbbar.canAddTab is not a function"
The class is:
Ext.define('KMA.view.environment.TabContainer',{
extend: 'Ext.tab.Panel',
alias: 'widget.environmenttabcontainer',
initComponent: function(){
[...]
this.callParent(arguments);
},
createTab: function(aTitle,aToolTip,anItem){
return {
title: aTitle,
itemId: aTitle + "Tag",
tabconfig: {
title: aTitle,
tooltip: aToolTip,
items: anItem
}
};
},
openTabs: function(){
return this.getItems().length;
},
maxOpenTabs: function(){
return 7;
},
canAddTab: function(){
return (this.openTabs() < this.maxOpenTabs());
},
addTab: function(aTabCfg){
this.add(aTabCfg);
}
});
My example code is:
var tbbar = Ext.ComponentQuery.query('environmenttabcontainer');
console.log(tbbar);
console.log(tbbar.canAddTab());
In the first "console.log" Firebugs show the instance of TabContainer, and show the methods of the class. But, why not work ?. Any idea ?
I am guessing it is not working because Ext.ComponentQuery.query returns an array.
This works:
var t = new KMA.view.environment.TabContainer();
Ext.ComponentQuery.query('environmenttabcontainer')[0].canAddTab
> function (){
return (this.openTabs() < this.maxOpenTabs());
}
Is there a reason why you are using a component query instead of having a direct reference ?
i am wondering about the 'refs' attribute of Sencha Touch class 'Ext.app.Controller'.
I saw a video tutorial where a simple contactForm was built. No i've tried to build a contact form for my app and i get an error: 'Uncaught TypeError: Object [object Object] has no method 'getContactForm''
Here's my controller
Ext.define('MyFirstApp.controller.Main', {
extend: 'Ext.app.Controller',
views: ['Viewport', 'Home'],
refs: [
{
ref: 'contactForm',
selector: '#contactForm'
}
],
init: function() {
this.control({
'button[action=submitContact]': {
tap: 'submitContactForm'
}
});
},
submitContactForm: function() {
var form = this.getContactForm();
form.submit({
url: 'contact.php'
});
}
});
I guess it's something wrong with the 'refs', in the video that guy said the "getContactForm" method will be created because of the "ref" attribute of "contactForm" but it doesn't. What am i doing wrong here?..Thanks for help!
The refs attribute property changed from Sencha Touch 2.0 developer preview version to beta/final version. So, what you wrote were correct for dev preview but presently it just name value pair. For your case:
refs: {
contactForm: '#contactForm'
}
I agree with jeremygerrits, I can't be sure that's the correct syntax for defining refs.
Based on the documentation, I would rather do it like this:
Ext.define('MyFirstApp.controller.Main', {
extend: 'Ext.app.Controller',
views: ['Viewport', 'Home'],
config: {
refs: {
contactForm: '#contactForm'
}
}
init: function() {
this.control({
'button[action=submitContact]': {
tap: 'submitContactForm'
}
});
},
submitContactForm: function() {
var form = this.getContactForm();
form.submit({
url: 'contact.php'
});
}
});
See also: http://docs.sencha.com/touch/2-0/#!/guide/controllers
It looks as though you may have the refs configured wrong. Here's a simple controller:
Ext.define('App.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
main: 'mainpanel'
}
}
});
mainpanel is an xtype or could be a css selector and main will give you getMain() like what was talked about in the video.
Actually I'm creating my first ExtJS 4 MVC application. Following the application guide from documentation, I initialize my controller like that :
Ext.application({
name: 'RateManagement',
appFolder: 'softcom',
context: null,
constructor: function(context) {
this.context = context;
},
launch: function() {
Ext.create('Ext.Panel', {
layout: 'fit',
renderTo: 'rate-management',
items: [
{
xtype : 'ratelist'
},
{
xtype : 'rateedit'
}
]
});
},
controllers: [
'Rate'
],
});
But for future ajax call, my controller need to know the ajaxUrl which is coming from Liferay 6. In Liferay, I can get URL like that :
<portlet:resourceURL var="listRates" escapeXml="false" id="listRates"></portlet:resourceURL>
<script type="text/javascript">
var rateContext = {
contextPath: '<%=request.getContextPath()%>',
listRatesUrl : '${listRates}',
strings: strings
};
</script>
My idea is to pass the var rateContext to my controller "Rate".
Any Idea?
Thank you!!
Concept of passing variable from app to controller looks wrong to me. Instead I would create getter somewhere in your app config
Ext.application({
// ...
context: null,
getContext: function() {
return this.context;
},
constructor: function(context) {
this.context = context;
},
// ...
});
And then you can get it from controller using:
this.application.getContext()
But if you would like to use approach of passing variable to controller you always can use
yourApp.getController("Rate") (you can do it in your lounch method) in order to access the controller.