So i have created two views : one a login dialog and the other (the following) is a dashboard basically.
On login click i use this.redirectTo("dashboard",true); hoping that it will trigger the routing linked handler in the next view (the following) but it didn't work; so I set the trigger manually and trigger the handler using an instance of the view.
Ext.define('Mine.view.newDashboard', {
extend: 'Ext.Container',
alias: 'widget.newDashboard',
id: 'project1',
routes:{
'#dashboard':{
action:'onDashboardView'
}
},
onDashboardView:function(){
var dash = Ext.create('widget.newDashboard', {
renderTo: Ext.getBody(),
hideMode: 'visibility'
});
dash.show();
},....
My question is how to do the routing properly like in the described first way so that the first displays when the URL changes to include the '#dashboard' part?
UPDATE2 : for now previous and next of the browser are doing nothing.
Thanks !
You are making progress. Remove the hash from the routes
Ext.define('Mine.view.newDashboard', {
extend: 'Ext.Container',
alias: 'widget.newDashboard',
id: 'project1',
routes:{
'dashboard':{ // REMOVE THE #
action:'onDashboardView'
}
},
onDashboardView:function(dash){
dash.show();
},....
Fiddle
Fiddle - see the url change
Related
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'
}
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()
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'
}
My problem is, when i click on the Button, the following Error is displayed:
TypeError: EntryForm.show is not a function
Main.js
Ext.define('MyApp.view.main.Main', {
extend: 'Ext.container.Container',
.....
do Stuff
.....
tbar: [{
text: 'Button',
handler: function(){
var mask = Ext.create('MyApp.view.main.EntryForm');
mask.show(this);
EntryForm.js
Ext.define('MyApp.view.main.EntryForm',{
extend: 'Ext.Widget',
....
generate my items for the form
....
When I use the EntryForm widget in the main.js class and use the create instead of the define and save it in a variable it works without problems.
I do not fully understand your question, but I think you need to add the EntryForm view to the Viewport before trying to show it, e.g.
var mask = Ext.create('MyApp.view.main.EntryForm');
Ext.Viewport.add(mask);
If EntryForm is set to hidden by default, then you would still need the
mask.show();
This link may also help http://training.figleaf.com/tutorials/senchacomplete/chapter2/lesson3/5.cfm
Please, help me. I am creating a TabPanel using the MVC. At the time of rendering panel add tab. Here is the code of the two views and controller. The result is a distorted picture.
The title of the tab is drawn twice: at the top and bottom (stretched to full screen). When I change in the controller function addNewTab() the line "tp.add({xtype: 'mytab'}).show();"
to the other "tp.add({title: 'new Tab', html: 'MVC New Tab Example'}).show();", then everything is rendered properly. I will be grateful for the help.
Views:
Ext.define('MY.view.Tab', {
extend: 'Ext.tab.Tab',
alias: 'widget.mytab',
initComponent: function() {
this.title = 'new Tab';
this.html = 'MVC New Tab Example';
this.callParent(arguments);
}
});
Ext.define('MY.view.TabPanel', {
extend: 'Ext.tab.Panel',
alias: 'widget.mytabpanel',
initComponent: function() {
this.id = 'MYTabPanel';
this.callParent(arguments);
}
});
Controller:
Ext.define('MY.controller.TabPanel', {
extend: 'Ext.app.Controller',
requires: ['MY.view.Tab'],
init: function() {
this.control({
'#MYTabPanel': {
render: this.addNewTab
}
});
},
addNewTab: function(tp) {
tp.add({xtype: 'mytab'}).show(); //it work bad
//tp.add({title: 'new Tab', html: 'MVC New Tab Example'}).show(); //it work good
}
});
Your mytab class extends Ext.tab.Tab. That means that this code tp.add({xtype: 'mytab'});
is adding a Tab as a main view for the TabPanel. A tab is created automatically for every panel or container you add to the tab panel and consists of just the button-like component at the top of the view.
That means that when you call the code above, a Tab is created and pushed into the TabPanel as a view, then the TabPanel creates another another Tab using the same title and attaches it to the top of the Tab you just added.
This code tp.add({title: 'new Tab', html: 'MVC New Tab Example'})' works because you are actually adding a panel (The default xtype used by Ext is panel) and the TabPanel is creating the tab for you using the title you've provided.
To fix: make MY.view.Tab extend Panel instead of Tab. If you're trying to customize just the tab for a particular view, dig into the source for Ext.tab.Panel and check out the undocumented tagConfig property that you can add to TabPanel items.