It'd be super useful if I could access instances of my views and controllers in my ext.js application from Chrome's console. Does anyone have a clue how to do this?
coffeescript:
window.cms = Ext.create 'Ext.app.Application',
name: 'CMS'
controllers: [
'MyController'
...
It would seem that cms.getController('MyController') would do what I want, but I get a constructor back instead of the instance I'm looking for.
You need to create an application instance reference in the Application. Like this:
Ext.application({
name: 'CMS',
controllers: ['MyController'],
launch:function () {
CMS.app = this;
...
}
});
then you can use
CMS.app.getController('MyController') ...
You can use:
CMS.getApplication().controllers.get('ControllerName')
then you will get the actual instance of the controller
I don't think you get a constructor, it's just that chrome shows constructor when you call console.log on an Ext-JS object
Related
I am getting a little deeper into my first functional app and need to better understand what it going on in my controller.
Here I have a controller that handles the action when a user clicks on an 'Option'. Looking at the this object raises a few questions:
What exactly is this? I would expect it to be an instance of my Option model, but it is missing some properties (like "identity: 'model: Option'").
If this is an instance of my Option model, why is the 'model' property undefined? Why doesn't it just know that?
What is this.content? It looks like some stuff is inside content (id and isSuppressed) and some is not (this.isSelected) - why is that?
Disclaimer: Though there aren't any presenting problems so far, there certainly could be errors in my ember app architecture.
Screenshot debugging controller:
Option Model & Controller
App.Option = Ember.Object.extend({
identity: 'model: Option',
id: '',
cost: '',
isSelected: false,
isSuppressed: false
});
App.OptionController = Ember.Controller.extend({
actions: {
toggleOption: function() {
this.set('isSelected', !this.get('isSelected'));
var id = this.get('content.id');
this.send('deselect', this.get('content.id'));
}
}
});
App.OptionsController = Ember.ArrayController.extend({
actions: {
deselect: function(exception) {
var opts = this.rejectBy('id', exception)
opts.setEach('isSuppressed', true);
}
}
});
It depends where this is, if your in the controller it's the controller. If your controller is an ObjectController/ArrayController it will proxy get/set calls down to the underlying model. content/model are the same thing in the context of the controller.
The properties rarely live directly on the instance, usually they are hidden to discourage accessing the properties without using the getters/setters.
In your code above there is a good chance your OptionController should be extending ObjectController. Unless the controller isn't backed by a model. If you use Ember.Controller.extend then it won't proxy getters/setters down to the model, it will store, retrieve properties from the controller itself.
Let's say we have
Ext.application({
name: 'APP',
//this is my global helper method.
determineSomething: function() {
return true;
}
});
and a view that should access the method determineSomething():
Ext.define('APP.view.Main', {
extend: 'Ext.Panel',
config: {
myConfigValue : APP.app.determineSomething()
}});
This will work fine as long as you use the Sencha class loading system (because the js-file with this Main-View is loaded by Sencha after APP is available.).
But now let's say we want to minify our script. This means that the browser parses the Main.js file before the Sencha application is loaded. But at this time APP is not yet ready and we can not access it.
One solution would be to simply make a non ext config class / array / whatever with the method but is this a nice solution? What would be a clean solution for this problem?
I would keep my helper functions into a singleton Helper class which gets instantiated whenever app is loaded. For example this is how my helper class look like:
Ext.define('MyntraTabApp.util.Helper', {
singleton : true,
alternateClassName : 'Helper',
determineSomething : function(){
// do something
}
});
I can use it like this wherever I want
Helper.determineSomething();
I want to add views and stores in controller dynamically. So, I've had this:
Ext.define('App.controller.MyController', {
extend: 'Ext.app.Controller',
stores: ['App.store.Users'],
views: ['App.view.Users.Index'],
I'm creating this controller dynamically with:
var controller = this.getController("Users");
How can I add store and views dynamically, something like:
var controller = this.getController(moduleID);
controller.stores = [];
controller.views = [];
controller.stores.push('App.store.Users');
controller.views.push('App.view.Users.Index');
But when I do that, it's not working. Console is telling me that Ext can't get "buffered from undefined" so I'm thinking that I have to do this with Ext.apply() or Ext.merge() or something like that to get getters and setters for stores.
What do you think?
EDIT for #asgoth:
When you use this.getController("nameOfController"); and if the controller doesn't exists, Ext-JS creates one for you. That's working 100% because when I console.log(controller); I'm getting data (and docs says that too). :)
You do not have that much choices, because you will need to have the arrays ready when you are instantiating the controller. By default this happens only once cause it should be managed by the Ext.app.Application Controller (instance).
First point is that you cannot use the getController method here because it does not accept any additional configuration. So the easiest solution would be the implementation of your own getController method, slightly renamed to avoid overriding.
here is a example one:
getControllerInstance: function(name, cfg) {
var me = this.application,
controllers = me.controllers,
controller = controllers.get(name);
if (!controller) {
controller = Ext.create(me.getModuleClassName(name, 'controller'), Ext.ApplyIf({
application: me,
id: name
},cfg);
controllers.add(controller);
if (me._initialized) {
controller.doInit(me);
}
}
return controller;
}
Please note that this variant does not add values to any array param instead it will override any any existing param!
Also note that all your controller will need to inherit from the controller that has this method.
I'm working with Ember.Router, and one thing I can't figure out is how to bind objects to controllers that the Router is instantiating.
For instance, here is a controller class (extended) that the Router will instantiate for a specific route ('page'), as well as a controller object (created), say to handle user administration tasks on a part of the application outside of the Router:
// controller used by Router to render the "page" route
App.PageController = Em.ObjectController.extend({
content: Em.Object.extend({
foo: 'bar'
})
});
// global controller for users
App.usersController = Em.ObjectController.extend({
content: Em.Object.extend({
fooBinding: App.PageController.foo
// the above will not work since Em.Router
// instantiates the page controller dynamically
})
});
So when the router loads it will instantiate App.PageController into App.router.pageController, but that's after App.usersController is already created. So how can App.usersController access data in a controller that the Router is managing?
Any ideas?
There are a few mistakes in your sample.
First, you should never directly setup a property with an Object value at declaration time: this value would be shared across all instances of the class. Here, it does not really matter, but it's a bad practice. In this case, the good way of setting up the PageController content is to bind it in router, at connectOutlet call, like that:
connectOutlets: function (router) {
var theContainerController = router.get('theContainerController'),
objectWithFooBar = Ember.Object.create({
foo: 'bar'
});
theContainerController.connectOutlet('page', objectWithFooBar);
}
Second mistake is the naming of usersController: it should be UsersController, as it is a class, which will be injected in the router as usersController during initialize call. It seems also quite strange to have users pluralized & ObjectController. Certainly should be singularized...
Last, and certainly what will be the most interesting regarding the question, once you will have preceding remarks applied, you will be able to setup the binding using:
App.UserController = Em.ObjectController.extend({
fooBinding: 'App.router.pageController.foo'
});
App.router can be setup before your call to App.initialize. It is definitively a bad coupling to have UserController using a global symbol to directly access to PageController, but it does the job in your case.
A definitely yet better solution would also be to bind UserController's content in a connectOutlet call.
I know this question was already posted in StackOverflow but I either didnt understand or sencha changed somewhat.
My app loads a form panel for login, then I would like to save the user info that have just loged on. This way I can change my view anytime I want and still know the name of the loged in user.
Here is my main code:
//<debug>
Ext.Loader.setPath({
'Ext': 'sdk/src'
});
//</debug>
Ext.application({
name: 'APP',
loadedUser: 'the test',
requires: ['Ext.MessageBox'],
views: ['Main', 'Home', 'Login'],
models: ['User'],
stores: ['Users'],
controllers: ['Main'],
icon: {
57: 'resources/icons/Icon.png',
72: 'resources/icons/Icon~ipad.png',
114: 'resources/icons/Icon#2x.png',
144: 'resources/icons/Icon~ipad#2x.png'
},
phoneStartupScreen: 'resources/loading/Homescreen.jpg',
tabletStartupScreen: 'resources/loading/Homescreen~ipad.jpg',
setLoadedUser: function(arg) {
this.loadedUser = arg;
},
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
Ext.Viewport.add(Ext.create('APP.view.Main'));
},
onUpdated: function() {
Ext.Msg.confirm("Application Update", "This application has just successfully been updated to the latest version. Reload now?", function() {
window.location.reload();
});
}
});
The 'loadedUser' its what I wanted to be my global variable, and the method setLoadedUser(arg) its suposed to change that value.
I can access 'loadedUser' no problem, but I can't change its value.
Another question: loadedUser can it be an array/data structure?
How are you accessing the function? This works for me. Remember you should access it like this:
APP.app.setLoadedUser('test');
And yes, it can be any value. :)
You can also use localStorage to, set/get Your variables:
Set it as:
localStorage.setItem('currentUserId', userID)
Get it as:
localStorage.getItem('currentUserId')
You can use it, anywhere in Your script.
Yes, the works when the function is inside of the app.js file.
It does not work if the function is inside of the controller file.
So if you have a project application called IronMan, the call from the view code to the global function, flyAway(), in your app.js file would look like:
IronMan.app.flyAway();