How to override extJs Controller component - javascript

I have created some generic component which I am using in different product. Now here I have one window and window controller which is generic and I am overriding window class to make use of that in our product.
My Generic window.
Ext.define('App.win.Panel', {
extend: 'Ext.window.Window',
closeAction:'destroy',
maximizable:true,
hideToolbar:false,
requires: [
'App.MyWinCon.PanelController'
],
xtype: 'MyWin',
name:'MyWin',
controller: 'MyWinCon',
layout: {
type: 'border'
},
gridConfigs:{},
initComponent:function(){
var p=this;
p.items = [{
//items
}];
p.callParent(arguments);
}
});
And In my Product app I am using overriding like this way :
var Window1 = Ext.create('App.win.Panel', {
title: Windo,
modal:true,
height: '90%',
width: '95%',
parentGridObj:gridObj,
});
Window1.show();
There is no problem in that part. Window is coming.
Now in similar passion I have written controller in generic. I will show you small piece of code
Ext.define('App.MyWinCon.PanelController', {
extend: 'Ext.app.ViewController',
alias: 'controller.MyWinCon',
init: function(){
var p = this;
p.control({
#:{
beforeclose : function(this){
// SOme code
}
}
});
}
Now can anybody help me how to access this beforeclose or similar kind of methods in my app which is written in generic class.
Thanks for all the help.

You can't, or it's at least really really complicated; but there is a really really easy way with a minimum of refactoring:
Ext.define('App.MyWinCon.PanelController', {
extend: 'Ext.app.ViewController',
alias: 'controller.MyWinCon',
init: function(){
var p = this;
p.control({
#:{
beforeclose : p.beforeClose // just a reference to function below!
}
});
},
beforeClose: function(component){ // thou ought not use a variable named "this"!
// SOme code
}
Now you can access the function from your view:
view.getController().beforeClose()

Related

Creation of a global, persistent object into Extjs

Good day all.
I'm into a big project that uses EXTjs (i guess it's 4.0), the project is huge and have several years behind.
I'm not into Extjs so I'm trying to learn what to do and how to do it, and my new task is to create a persistent, global object, available into the whole application in which I need to store some information that are used in different parts of the project (let's say for example that the user can set a particular property of this object to "true" while doing some actions and this "true" it will be used into another viewcontroller to enable some functions, things like this).
so, I've created a new file called userJsonMainModel.js :
Ext.define('Tac3.userJsonMainModel', {
extend: 'Ext.data.Model',
constructor: function() {
var userJsonMainModel = this;
userJsonMainModel.callParent(arguments);
userJsonMainModel.data.tmp = {};
},
testProperty:{foo:"bar"},
testMethod: function (){
console.log("testFunction called");
}
});
and in Application.js :
requires: [
...
'Tac.userJsonMainModel'
],
stores: ['Countries', 'Kpis', 'Dimensions'],
autoCreateViewport: false,
init: function() {
var controller = this
Ext.tip.QuickTipManager.init();
Ext.setGlyphFontFamily('FontAwesome');
var userJsonMainModel = controller.createUserJsonMainModel();
console.log("into init: ", this.userJsonMainModel.testProperty);
...
createUserJsonMainModel: function() {
var controller = this;
controller.userJsonMainModel = Ext.create('Tac3.userJsonMainModel', {
controller: controller
});
console.log("check if the jsonmainmodel exist ",controller.userJsonMainModel.testProperty);
},
this is actually working, now the second step is to access the same object from another view (or its viewcontroller), this is what I've done into a a viewController:
Ext.define('Tac3.view.udesign.UdesignController', {
extend: 'Ext.app.ViewController',
alias: 'controller.udesign',
init: function(view) {
...
console.log("into init: ", this.userJsonMainModel.testProperty);
}
and this is actually throwing a:
Uncaught TypeError: Cannot read property 'testProperty' of undefined
I was pretty sure the objects defined into application.js would be globally accessible, but I guess I'm wrong, or doing something in a wrong way.
since I've found quite no examples on this topic (which is probably because it is not a standard way to do this), I'd like to ask what I'm doing wrong?
Just define a class and require it in your application:
Ext.define('MyApp.Globals', {
singleton: true,
foo: 100,
bar: 'baz'
});

Extjs opening new Ext.window.Window by clicking a button

I'm trying to edit open source program called PartKeepr (v0.1.9). In a specific part of program I want to add a button that opens a new Ext.window.Window. My codes are as following which doesn't work (I'm pretty new in extjs but I'm given a hard task I guess, so I'm open to all advice for where to start learning, I'm just trying to learn from existing codes and apply some things by looking similar parts of available code)
Ext.define('PartKeepr.FindWindow',{
extend:'Ext.window.Window',
constrainHeader: true,
title: i18n("Find Number"),
initComponent: function() {
this.okButton=Ext.create("Ext.button.Button",{
text:i18n("OK")});
this.buttons=[this.okButton];
}
});
{
xtype: 'button',
text: i18n("Find"),
name: 'findButton',
handler: Ext.bind(this.findNumber, this)
}
findNumber: function(){
var j = new PartKeepr.FindWindow();
j.show();
}
Edit: When I press the find button, console giving me the following error: ext-all.js:21 Uncaught TypeError: Cannot read property 'insert' of undefined
You need to call the superclass initComponent method:
Ext.define('PartKeepr.FindWindow', {
extend: 'Ext.window.Window',
constrainHeader: true,
title: i18n("Find Number"),
initComponent: function() {
this.okButton = Ext.create("Ext.button.Button", {
text: i18n("OK")
});
this.buttons = [this.okButton];
this.callParent();
}
});

ExtJS 5: Accessing bound store in component

I'm having a real hard time understanding how to access the actual bound store instance on a component, like a ComboBox or Grid. It appears that when you use their getStore method, it returns a different instance.
In my example, I have a custom grid class, and in its initComponent, I want to add a load listener. Unfortunately, the load listener never gets hit, but the bound store's load listener does. You can see the listener is getting set up before the store is loaded, so that's not the issue. It looks like the store instance in initComponent is a memory store, so the bound store's instance is not synced to the component at this point.
I know I can have a load listener on the bound store, but this is a custom grid class, and for any custom grid class, I want there to be a listener set up... so I don't want to have to do this all over the place in my code... I just want it in one class, as they're all going to have the same logic carried out.
Can someone explain to me why my custom grid class's load listener is not getting hit, and what can I do to fix this? Can I somehow access the bound store instance?
Ext.application({
name: 'Fiddle',
launch: function() {
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
xtype: 'myGrid',
initComponent: function() {
alert('initComponent')
this.callParent();
this.getStore().on('load', this.onLoad, this);
},
onLoad: function() {
alert('grid store loaded');
}
});
Ext.define('MyViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.myview',
onLoadBoundStore: function() {
alert('loaded bound');
}
})
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myview',
stores: {
myStore: {
fields: ['name', 'value'],
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json'
}
},
listeners: {
load: 'onLoadBoundStore'
}
}
}
});
Ext.define('MyView', {
extend: 'Ext.form.Panel',
renderTo: Ext.getBody(),
controller: 'myview',
viewModel: {
type: 'myview'
},
items: [{
title: 'blah',
xtype: 'myGrid',
reference: 'myComboBox',
bind: {
store: '{myStore}'
},
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Value',
dataIndex: 'value'
}]
}]
});
Ext.create('MyView')
}
});
Can someone explain to me why my custom grid class's load listener is
not getting hit, and what can I do to fix this?
You are not initially providing any store to your grid (the store config option is required by the way). Hence the grid is creating its own, empty store as coded here:
store = me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
That empty store is the one that gets your onLoad listener attached. It is not getting hit because the store is never loaded.
Can I somehow access
the bound store instance?
Yes, use this:
this.lookupViewModel().getStore('myStore')
You can attach your listener to the bound store instead of the empty one and see the difference. The grid's empty store eventually gets replaced by the bound one (this is why you see data in the grid, after all), but this happens after initComponent is executed. You can track the moment of setting the bound store to the grid by overriding setStore method.
I know I can have a load listener on the bound store, but this is a
custom grid class, and for any custom grid class, I want there to be a
listener set up... so I don't want to have to do this all over the
place in my code... I just want it in one class, as they're all going
to have the same logic carried out.
Since you are using MVVC it is recommended to stick to the pattern and keep views declaring view aspects only. Listeners should be declared and handled in controllers (not even in viewmodels like in your example). Otherwise, if you continue sticking to pre Ext JS 5 style and put dynamic stuff in views (i.e. the grid in your case) there is no point in using MVVC.
This is so incredibly hacky that I don't even want to post it as an answer, but I'm going to just for posterity sake. Building on Drake's answer, I figured out how to get my store using what was passed in the initial config of my grid class. The bind comes in with the braces, so that's why I'm doing a replace on it. Like I said, this probably should never be used, but it's something.
initComponent: function() {
var store = this.lookupViewModel().getStore(this.config.bind.store.replace(/[{}]/g, ''));
store.on('load', this.onLoad, this);
this.callParent();
},
Just to add one more option to the mix, you can listen to the reconfigure event on the grid, as that's what fires after binding a store is complete... so something like this would work:
Ext.application({
name: 'Fiddle',
launch: function() {
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
xtype: 'myGrid',
initComponent: function() {
alert('initComponent')
this.on('reconfigure', this.onReconfigureGrid, this);
this.callParent();
},
onReconfigureGrid: function(grid, store, columns, oldStore, oldColumns, eOpts) {
store.on('load', this.onLoad, this);
},
onLoad: function() {
alert('grid store loaded');
}
});
Ext.define('MyViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.myview',
onLoadBoundStore: function() {
alert('loaded bound');
}
})
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myview',
stores: {
myStore: {
fields: ['name', 'value'],
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json'
}
},
listeners: {
load: 'onLoadBoundStore'
}
}
}
});
Ext.define('MyView', {
extend: 'Ext.form.Panel',
renderTo: Ext.getBody(),
controller: 'myview',
viewModel: {
type: 'myview'
},
items: [{
title: 'blah',
xtype: 'myGrid',
reference: 'myComboBox',
bind: {
store: '{myStore}'
},
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Value',
dataIndex: 'value'
}]
}]
});
Ext.create('MyView');
}
});

Extending MessageBox as View - Ext JS 4.1

I'm trying to extend a MessageBox within a view so I can reuse it throughout my application.
It seems that when I do so, I lose some of the default functionality that makes the messagebox useful (msg, button definitions, icon definitons, default drag constraints, etc). Documentation is a little confusing as it seems configs should be defined within the show() function, and I'm unsure of how to set them within my view.
How can I truly extend a messagebox component as a view?
Basic MessageBox (what I want to create with my view):
Ext.Msg.show({
title:'Error',
msg: 'There was an error.',
buttons: Ext.Msg.YESNOCANCEL,
icon: Ext.Msg.QUESTION
});
Renders:
but when I show my view:
Ext.create('IOL.view.app.Message').show();
I basically end up with a vanilla Panel/Window component
Ext.define('IOL.view.app.Message', {
extend : 'Ext.window.Window',
config: {
},
constructor: function(config) {
this.initConfig(config);
this.callParent(arguments);
},
initComponent : function() {
Ext.apply(this, {
xtype: 'messagebox',
width: 400,
height: 200,
title:'Error',
html: 'There was an error.',
buttons: [
{ text: 'Button 1' }
]
});
this.callParent(arguments);
}// initComponent
});
Renders:
It seems you are extending an Ext.window.Window and applying the messagebox configs to it. Why not just extend Ext.window.MessageBox:
Ext.define('IOL.view.app.Message', {
extend : 'Ext.window.MessageBox',
width: 400,
height: 200,
title: 'Error',
html: 'There was an error.',
buttons: Ext.Msg.YESNOCANCEL,
icon: Ext.Msg.ERROR,
// whatever else you want to do
initComponent : function() {
this.callParent(arguments);
}
});
#EricCook brings up a good point below. The MessageBox class is designed for reuse in the app as a singleton not really for subclassing.
In your question you said:
I'm trying to extend a MessageBox within a view so I can reuse it
throughout my application
I can understand that if you want to create a different type of messagebox that you would call with the normal Ext.Msg.show method, you could extend the MessageBox with your own buttons or icons I suppose.
But for regular use this isn't something you need to extend. For repeated use in your app you could hold a reference to the message box config you want in the controller like:
// SomeController.js
errorMsg: {
title:'Error',
msg: 'There was an error.',
buttons: Ext.Msg.YESNOCANCEL,
icon: Ext.Msg.QUESTION
},
Then whenever you want to call that type of message you could use (assuming the scope is the controller itself, or you could get a reference to the controller beforehand):
Ext.Msg.show(this.errorMsg);

Create an extension with an xtype in ExtJS 4

I am used to ExtJS 3.X, but am struggling with ExtJS 4.
I want to create an extension of a grid and be able to use an instance of the grid with the xtype. As far as im aware, I have to set the alias as widget.xtypename but its not working for me.
var MyGrid = Ext.define('mygrid', {
extend:'Ext.grid.Panel',
alias: 'widget.mygrid',
// rest of grid...
});
Ext.create('Ext.window.Window', {
title:'My Window',
items:[{
xtype:'mygrid'
}]
})
The Error I am getting in Chrome console is Cannot create an instance of unrecognized alias: widget.mygrid
Some help would be much appretiated
Ext.define('MyApp.Grid',{
extend: 'Ext.grid.GridPanel',
alias: 'widget.mygrid',
.......
.......
}
Now you can use as xtype:'mygrid'
The problem may be that you are attempting to instantiate an object that uses your new class, immediately following the call to Ext.define. Remember that Ext.define is an asynchronous process. Anything that needs to instantiate components should be in an onReady handler, or in Ext.application (launch), or in initComponent in a component class, or in init in a controller class, for these locations are guaranteed to be called only after all the defines have completed.
Specifying an alias beginning with "widget." will allow you to use it wherever xtype is expected. In your simple example, you might try doing the following:
var MyGrid = Ext.define('mygrid', {
extend:'Ext.grid.Panel',
alias: 'widget.mygrid',
// rest of grid...
}, function() {
Ext.create('Ext.window.Window', {
title:'My Window',
items:[{
xtype:'mygrid'
}]
});
});
This will instantiate your window within the callback after the define completes.
If you are using working on a MVC application, you can fix this by adding the view information to your controller. In your controller you need to specify the view in an array named views.. Here is an example:
Ext.define('MyApp.controller.Users', {
extend: 'Ext.app.Controller',
views: ['users.List'],
...
In your case you may need to define views:['mygrid'].
If you are not using MVC architecture, you will need to use the Ext.require and specify your grid class exists.
I believe you need to add a xtype to your config:
var MyGrid = Ext.define('mygrid', {
extend:'Ext.grid.Panel',
alias: 'widget.mygrid',
xtype: 'mygrid',
// rest of grid...
});
After researching more, I would expect the alias to be all you need. Are you defining an initComponent function? Below is an example from Sencha:
Ext.define('App.BookGrid', {
extend: 'Ext.grid.Panel',
// This will associate an string representation of a class
// (called an xtype) with the Component Manager
// It allows you to support lazy instantiation of your components
alias: 'widget.bookgrid',
// override
initComponent : function() {
// Pass in a column model definition
// Note that the DetailPageURL was defined in the record definition but is not used
// here. That is okay.
this.columns = [
{text: "Author", width: 120, dataIndex: 'Author', sortable: true},
{text: "Title", flex: 1, dataIndex: 'Title', sortable: true},
{text: "Manufacturer", width: 115, dataIndex: 'Manufacturer', sortable: true},
{text: "Product Group", width: 100, dataIndex: 'ProductGroup', sortable: true}
];
// Note the use of a storeId, this will register thisStore
// with the StoreManager and allow us to retrieve it very easily.
this.store = new App.BookStore({
storeId: 'gridBookStore',
url: 'sheldon.xml'
});
// finally call the superclasses implementation
App.BookGrid.superclass.initComponent.call(this);
}
});
This one also works:
Ext.define('Path.to.ClassUsingSubcomponent', {
...
requires: ['Path.to.YourSubcomponent'],
...
}

Categories

Resources