Localize button from a window - extjs

probably is a stupid question but i really don't know now, what i have to do to localize a button in a window i just redefined and create. I
use extjs 4.2.1 and i produce a kind of mvc but is more similar to the old way of use this type of framework.
I have to define a window that have two buttons 'submit' and 'close' like this:
Ext.define('newWindow',{
extend:'Ext.window.Window',
config: {
submitFn:function(){return null;}
}
bodyStyle: 'padding: 5px 5px 0',
layout:'fit',
width:460,
height:390,
plain: false,
border:false,
resizable: false,
buttons: [{
text:'submit',
handler: function(){this.up.up.submitFn()},
tabIndex:1000
},{
text: 'close',
handler: function(){
this.up().up().hide();},
tabIndex:1001
}]
})
When i create this window in my code i want to pass him a function to handler his behave but i can't..
i try to put him itemId, id but Ext.getCmp(id), Ext.ComponentQuery.query(id) doesn't do their job.
RE-EDIT:
OK the question isn't clear: I define in that way the components newWindow.
I say i don't use the mvc pattern and in a part of my program i create this component in like here;
var dlg = Ext.create('newWindow', {submitFn: submit});
Where submit is the function i need to call to submit the value present in the window, with her logic.
This is what i need to do but i ask all another way to do that.

You could always just set the window's config closable:true instead of defining your own button.

I assume all the ways you have tried to get a reference to the button didn't work because the button wasn't created when you called them. You should either wait for the button to be rendered when calling Ext.getCmp or use this.control in your controller init method. Here is an example:
Ext.define('myController', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'#submitButton': {
click: this.onSubmitButtonClick
}
});
},
onSubmitButtonClick: function() {
console.log('Click');
}
});
And here is a fiddle

Related

How to redirect to another view from button click (ExtJS 6.2)

I have this button class defined as follows :
Ext.define('Mine.view.buttons', {
extend: 'Ext.container.Container',
alias: 'widget.MyClass',
requires: [
'Mine.view.Main',
'Mine.view.newDashboard'
],
xtype: 'myclass',
items: [{
xtype: 'button',
html: '<img src=\"../../iDeviceMap.png\" width="76" height="76"/>',
text: '',
width: 76,
height: 76,
handler: function() {
this.redirectTo('main', true);
}]
});
Which i embed in a Panel view along with other components (composing the main view) defined in another class.
My problem is that this.redirectTo('main', true); doesn't work. How to do the redirection with the right "this" that of the main view where the button is defined (say Mine.view.Main) ?
Q2 : how to call the parent view (Mine.view.Main) from the handler of the button?
Thanks.
The button handler should be a function in the controller. The method in the controller with then call the redirectTo method.
Or you could get the panel's controller in the button's handler and call it from there.... best to do it in the controller so if you write a different view for a phone or tablet each view can share the controller.
A fiddle showing switching panels
Same fiddle so you can see the hash change
EDIT: #ltes - I wrote a fiddle that did what you wanted it to do. You ask a question about two methods. It would be much faster for you to simple review the documentation on each of these methods.
Ext.create method
Ext.Container down method
You don't understand the tool kit you are using. Ext.Create will create a new object this.getView().down and up() look in the hierarchy to find a component. If you want to replace a panel then use the remove() and add() method on the panel. YOu don't have to execute Ext.create when you add you can simply pass a config:
panel.add({
xtype: 'panel',
title: 'This is my new panel',
html: 'new panel data'
}

extjs contextmenu click error - method not found... but looking in wrong controller

how do I point this menu item click to launch a method in a controller.
The item click is being hit successfully but the error message states No method named "onDownloadTopdayRecapContextButton" on ExtApplication4.view.main.MainController. That is the problem, you can see the view's controller is portalRealtime-portalRealtime.
So somehow its pointing to the wrong controller. Can someone show me what I am doing wrong?
menu code
var contextMenuTopday = Ext.create('Ext.menu.Menu', {
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
grid menu is held in
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
extend: 'Ext.panel.Panel',
xtype: 'app-portalRealtime',
itemId: 'portalRealtimeItemID',
requires: [
'ExtApplication4.view.portalRealtime.PortalRealtimeController',
'Ext.form.action.StandardSubmit'
],
controller: 'portalRealtime-portalRealtime',
title: 'Main Portal',
layout: {
type: 'vbox'
},
items: [
//i deleted some grid code here
collapsible: true,
collapseDirection: 'left',
listeners: {
itemcontextmenu: function (view, rec, node, index, e) {
e.stopEvent();
contextMenuTopday.showAt(e.getXY());
return false;
}
{
You are creating the context menu outside of your view, so it does not inherit your controller.
Before using the below code please scroll to the bottom of the answer for a better solution, but this hopefully shows what is the cause of your issue.
If this doesn't solve your issue, please comment and provide a more complete code example, and I will update my answer
In these cases you can pass a controller manually, but you need to pass as a parent, as you get all kinds of problems if you re-use the same controller on multiple components (when you destroy one for example, it destroys the controller, leaving the other without)
So you could create from within your view like so:
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
initComponent:function(){
this.callParent(arguments);
this.contextMenuTopday = Ext.create('Ext.menu.Menu', {
controller:{
parent: this.getController()
},
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
}]
});
}
Then rather than use a variable to access the context menu you can access the contextMenuTopday property, as you are within a child item you may need to traverse to your actual view, the simplest way of doing this is via the up method available on components, you would need to make sure you include an xtype to do this:
Ext.define('ExtApplication4.view.portalRealtime.PortalRealtime', {
xtype:'portalrealtime'
Then from within the context menu you can do:
itemcontextmenu: function (view, rec, node, index, e) {
this.up('portalrealtime').contextMenuTopday.showAt(e.getXY());
}
A better way
Best illustrated looking at this fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1qpn
Define your menu as its own class:
Ext.define('Example.ContextMenu', {
xtype:'testmenu',
extend:'Ext.menu.Menu',
items: [{
text: 'Download Topday Recap',
iconCls: 'downloadIcon',
listeners: {
click: 'onDownloadTopdayRecapContextButton'
}
}]
});
Use a method on your controller for the itemcontextmenu event (This is good anyway as it provides a better separation of concerns):
itemcontextmenu: 'showContextMenu'
Then add a a few new methods to your portalRealtime-portalRealtime controller:
getContextMenu:function(){
if(!this.contextMenu){
this.contextMenu = this.getView().add({xtype:'testmenu'});
}
return this.contextMenu;
},
showContextMenu:function (view, rec, node, index, e) {
// we can't use showAt now we have added this to our view, as it would be positioned relatively.
this.getContextMenu().show().setPagePosition(e.getXY());
}
What we are doing here is adding the context menu to the view, so it inherits the controller (and a viewmodel if provided).
The best way to call methods on your controller for listeners/button handlers etc is to just specify the method name as a string i.e.:
listeners:{
itemcontextmenu: 'showContextMenu'
}
This will automatically look up the responsible controller and use the correct method.
If you need to call from within a component you will find that this.getController() fails unless you call on the actual component the controller is attached to - i.e. you are calling from a child component. In these cases you can use this.lookupController() to find the inherited/responsible controller and then call any methods from here e.g. this.lookupController().myMethod()

Global View + ViewController on ExtJs 5

What I want to achieve is very simple, I want to have a main menu all across my application, with the same functionality for all the views.
I would like to create a view that contains exclusively the menu portion plus its own viewcontroller. What would be the [best] way to achieve this?
I am using ExtJS 5 implementing the MVVM paradigm.
Thanks!
This is a pretty broad question about how to architect the app that is pretty difficult to answer without knowing more about other parts of the app.
Generally, anything application global (that is not the application container/viewport) is probably easiest to implement with MVC. Menu controller (MVC controller) would listen to menu events and then it would drill down the component hierarchy to call components' API methods to execute the actions.
I could be more specific if I knew the app.
I would create a main view, in which you define the fixed parts of the application, as well as a container with layout 'fit' to hold the changing "views". Instead of layout 'fit', this could also be a tab panel or something. Nothing prevents you from add behaviour to the fixed part of this main view using a view controller for it of course.
Pretty straightforward in fact. Then, you'll change the current app view by putting it into the main view's central container. You'll need some kind of decision logic and configuration data to define the available views in your application. This would probably best to wrap that in a single place dedicated to this very task only, that is an app controller (rather than the view controller).
Here's an example fiddle, and bellow is the reasoning explaining the different parts of the code:
So, you'd start with a view like that:
Ext.define('My.view.Main', {
extend: 'Ext.container.Container',
xtype: 'main', // you can do that in ext5 (like in touch)
// shortcut for that:
//alias: 'widget.main',
controller: 'main',
layout: 'border',
items: [{
xtype: 'panel',
region: 'west',
layout: {type: 'vbox', align: 'stretch', padding: 5},
defaults: {
margin: 5
},
items: [{
xtype: 'button',
text: "Say Hello",
handler: 'sayHello'
}]
},{
// target for app's current view (that may change)
xtype: 'container',
region: 'center',
layout: 'fit'
}]
});
Ext.define('My.view.MainController', {
extend: 'Ext.app.ViewController',
alias: 'controller.main',
sayHello: function() {
Ext.Msg.alert("Controller says:", "Hello :-)");
}
});
Then, you set this main view as the "viewport" of your application. I also add a method to change the center view. I think the Application instance is a good place for that, but you could move this method to another dedicated app controller...
Ext.application({
name : 'My', // app namespace
// in real life, Main view class would lie in another file,
// so you need to require it
views: ['Main'],
// from ext 5.1, this is the config to auto create main view
mainView: 'My.view.Main',
// we also register a ref for easy retrieval of the main view
// (the value 'main' is the xtype of the main view -- this is
// a component query)
refs: {
main: 'main'
},
setCenterRegion: function(cmp) {
// getter generated by refs config
// you could another layout in the main view, and another component query of course
var center = this.getMain().down('[region=center]');
// replace the current center component with the one provided
center.removeAll();
center.add(cmp);
}
});
So, now, you can change the view with code like this:
My.getApplication().setCenterRegion(myView);
You could wire it through the ViewController of the main view, and using it as handlers in your view. For example, in your ViewController:
changeView: function() {
// retrieve the next view, this is application specific obviously
var myView = ...
// My.getApplication() gives you the instance created by
// Ext.getApplication in namespace 'My'
My.getApplication().setCenterRegion(myView);
}
And, in your main view, use an item like this:
{
xtype: 'button',
text: "Change view (by view controller)",
handler: 'changeView'
}
That could be fine for simple applications, nevertheless that seems like mixing of concern. Deciding about application level view swapping seems more like an application controller's business. So, I would rather recommend to put the changeView method in an app controller, and exposes it to components with a component query, like this:
Ext.define('My.controller.Main', {
extend: 'Ext.app.Controller',
config: {
control: {
// components will have to match this component query
// to be animated with the change view behaviour
'#changeView': {
click: 'changeView'
}
}
},
changeView: function() {
My.getApplication().setCenterRegion(/*
...
*/);
}
});
And you would hook the behaviour to components in any view like this:
{
xtype: 'button',
text: "Change view (by app controller)",
// will be matched by the controller component query
itemId: 'changeView'
}

change listener doesnt work in extjs

I have a dynamic form and i want to add a listener when change a field value, but i couldnt achive to do that. I added a click listener but when i change it to the change it doesnt work.
thanks in advance.
here is the code below :
panel = Ext.define('MyApp.view.dynamicform.Form', {
extend: 'Ext.form.Panel',
alias: 'widget.dynamicformform',
title: title,
id: 'dynamicform.Form',
bodyPadding: 5,
autoScroll: true,
layout: 'auto',
defaults: {
anchor: '100%'
},
dockedItems: [],
items : genItems(storeData),
listeners: {
afterrender: function (comp) {
var element = comp.getEl();
element.on('change', function(e,el) {
alert('blabla')
});
}
},
initComponent : function() {
this.callParent(arguments);
}
});
when i write click instead of change it works perfectly. I dont get what iam doing wrong.
The afterrender event you have added the listener for is purely for the panel component alone. Therefore trying to attach a change event wont work, since you are trying to do this on the panel:
afterrender: function (comp) {
var element = comp.getEl();
//element is the panel here, not child items such as spinners...
element.on('change', function(e,el) {
alert('blabla')
});
}
You say the click is working, but I think that's just because you are clicking anywhere on the panel including on the child items you are rendering. Instead, the child items coming back in the genItems() need to contain change event listener configs.
EDIT
You could loop through the child items on comp in your afterrender event and for any that are spinners, etc, add the change events that way.

Where to use listeners and where to use controller - Sencha Touch 2

I am confused between the proper usage of Listeners vs Controllers
E.g. for the same button, I can make the handler for the button-tap event in the button description itself as :
Ext.Viewport.add({
xtype: 'button',
centered: true,
text: 'My Button',
listeners: {
tap: function() {
alert("You tapped me");
}
}
});
and also as in a separate controller as below.
Ext.define("NotesApp.controller.Notes", {
extend: "Ext.app.Controller",
config: {
refs: {
newNoteBtn: Get reference to button here
},
control: {
newNoteBtn: {
tap: "onNewNote"
}
}
},
onNewNote: function () {
console.log("onNewNote");
}
});
What is the best practice, and are there trade-offs?
Thanks
To controller or not to controller, that is the question.
Well, technically, nothing would prevent you from doing one or the other. I have established a way how to decide for myself:
I install listeners on view if the job they are doing does not cross boundaries of the view. If we take form as an example, disabling and enabling, showing and hiding of fields, if it depends only on the state of the form stay within the form - no controller.
I delegate the logic to a controller if the action in one view (a button click, for example) influences another view or the whole application.
Again, these are my preferences, you can have another.

Resources