I am trying to build a CRM web application using extjs4 MVC.
After design a simple web page, I try to use controller to control the menu on the left panel.
But the controller is so difficult to understand for me.
Because of some reasons on ui design, there is a panel in the outer of the menu tree panel.
Here is my code.
app/view/MenuBar.js
Ext.define('Crm.view.MenuBar',{
extend: "Ext.panel.Panel",
alias: 'widget.crm_menubar',
requires: ['Crm.store.Menus'],
initComponent: function(){
var store = Ext.create('Crm.store.Menus');
Ext.apply(this,{
xtype:'panel',
title: "menu"
width: 212,
frame:true,
hideCollapseTool:true,
split: true,
collapsible:true,
collapseMode: 'mini',
items: [
Ext.create('Ext.tree.Panel',{
id: 'menutree',
border: false,
height: '100%',
rootVisible: false,
store: store
})
]
});
this.callParent();
}
});
app/store/Menus.js
Ext.define('Crm.store.Menus',{
extend: 'Ext.data.TreeStore',
root: {
expanded: true,
children: [
{ text: "subrootitem1",
expanded: true,
children:[
{ id: 'a', text: "item1", leaf: true},
{ id: 'b', text: "item2", leaf: true },
]
},
{ text: "subrootitem2",
expanded: true, children: [
{ id: 'c', text: "item1", leaf: true },
{ id: 'd', text: "item2", leaf: true}
]
}
]
}
});
app/controller/Menu.js
Ext.define('Crm.controller.Menu',{
extend: 'Ext.app.Controller',
refs: [{ref: 'menubar', selector: 'crm_menubar'}],
init: function(){
alert('test'); // this line can already execute when page is loading
this.control({
'crm_menubar': {
itemmousedown: this.onItemClicked
}
});
},
onItemClicked: function(){
alert('clicked');
}
});
I want interact with the menu. But the code up this line do not work.
At last the 'refs' is obscure. Can you give me some solution
Try registering your controller to the treepanel:
this.control({
'crm_menubar treepanel[id="menutree"]': {
itemclick: this.onItemClicked,
scope : this
}
});
Related
I am using a carousel and would like to lock the carousel until a button is clicked. Is there an easy way to do this? Thanks!
My code so far:
Ext.define('BabyBen.view.MainCarousel', {
extend: 'Ext.carousel.Carousel',
xtype: 'maincarousel',
config: {
fullscreen: true,
activeItem: 1,
indicator: false,
scrollable: {
direction: 'vertical',
directionLock: true
},
items: [{
xtype: 'whatscreen'
}, {
xtype: 'startscreen'
}, {
xtype: 'whenscreen'
}]
}
});
You need to write a custom view for lockable carousel:
Ext.define("myApp.view.LockableCarousel",{
extend: 'Ext.Carousel',
initialize: function () {
this.onDragOrig = this.onDrag;
this.onDrag = function (e) { if(!this.locked){this.onDragOrig(e);} }
},
locked: false,
lock: function () { this.locked = true; },
unlock: function () { this.locked = false; }
});
Then you can extend this custom carousel anywhere using extend as well as you need to apply custom lock and unlock function for your desired lockable carousel through button handler:
Ext.define("myApp.view.CustomCarousel",{
xtype: 'CustomCarousel',
extend: 'myApp.view.LockableCarousel',
config: {
id: 'LockableCarousel',
title: 'Example4',
iconCls: 'cloud',
indicator: false,
items: [
{
html : 'Item 1',
style: 'background-color: #5E99CC'
},
{
items: [
{
xtype : 'button',
text: 'Lock',
handler:function() {
Ext.getCmp('LockableCarousel').lock();
}
},
{
xtype : 'button',
text: 'Unlock',
handler:function() {
Ext.getCmp('LockableCarousel').unlock();
}
}
]
}
]
}
});
Working Demo
I have a quite simple mobile app I want to build with Sencha Touch 2. I have quite a lot of experience with ExtJs, but not really with their MVC architecture. What I want to achieve is :
first a main screen with toolbar and some icons rendered in the middle which are to be used to navigate across the app functionality.
clicking one of the icons should switch to a screen with a scrollable list.
What I'm struggling with is the proper place to define the views, and controllers. As well as should for example the main screen use a controller ? Should I create a viewport manually or not ?
What I have right now, which is not rendering anything apart of the toolbar :
app.js
Ext.application({
name: 'SG',
views: [
'Main',
'MainScreen'
],
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
Ext.Viewport.add(Ext.create('SG.view.Main'));
}
})
Main.js
Ext.define('SG.view.Main', {
extend: 'Ext.Container',
requires: [
'Ext.TitleBar',
'ShopGun.view.MainScreen'
],
config: {
layout : 'fit',
items: [
{
title: 'Welcome',
iconCls: 'home',
position: 'top',
scrollable: true,
items: [
{
docked: 'top',
xtype: 'titlebar',
title: 'SG Alpha 1'
}
Ext.create('SG.view.MainScreen', {
docked: 'bottom'
})
]
}
]
}
});
MainScreen.js
Ext.define('SG.view.MainScreen', {
extend: 'Ext.Container',
xtype: 'mainScreen',
initialize : function(){
Ext.define("MenuIcon", {
extend: "Ext.data.Model",
config: {
fields: [
{name: "Name", type: "string"},
{name: "Icon", type: "string"}
]
}
});
this.store = Ext.create('Ext.data.Store', {
model: 'MenuIcon',
data: [
{
Name: "A",
Icon: "a.png"
},
{
Name: "B",
Icon: "b.png"
}
]
});
this.html = 'foo';
this.callParent(arguments);
}
});
And finally an image of what I'd like to get :
EDIT:
A senchafiddle demo here : http://www.senchafiddle.com/#jSqtV (which is not rendering at all but doesn't throw any errors).
I am working with the mvc nested-loading example: http://docs.sencha.com/ext-js/4-1/#!/example/app/nested-loading/nested-loading.html. While trying to build my own project out of this I ran in to a problem trying to render the data in my content view. For some reason the templated data is not loading. I have a feeling it's something to do with xtype: 'component'. I changed it to panel and I seen the border but still no data. I also included the app.jsb3 file and that does not work either. I can see the data listed in the bind method but gets added.
My json data:
[
{id: 1, name: 'This is page one', url: 'http://my.test.com/test.html'},
{id: 2, name: 'This is page two', url: 'http://my.test.com/test2.html'}
]
My Model:
Ext.define('TST.model.Projects', {
extend: 'Ext.data.Model',
fields: ['id', 'name', 'url']
});
My Store:
Ext.define('TST.store.Projects', {
extend: 'Ext.data.Store',
model: 'RLA.model.Projects',
autoLoad: true,
proxy: {
type: 'ajax',
url : 'resources/json/projects.json'
}
});
My Controller:
Ext.define('TST.controller.Menu', {
extend: 'Ext.app.Controller',
stores: ['Projects'],
models: ['Projects'],
refs: [
{ref: 'mainLeftMenu', selector: 'mainleftmenu'},
{ref: 'mainContent', selector: 'maincontent'}
],
init: function() {
this.control({
'mainleftmenu': { selectionchange: this.onLeftMenuChange },
});
this.getProjectsStore().on({
scope: this,
load : this.onProjectsStoreLoad
});
},
onProjectsStoreLoad: function(store, records) {
Ext.defer(function() {
if (records.length) {
var record = records[0];
this.getMainLeftMenu().getSelectionModel().select(record);
console.log("iamhere");
}
}, 500, this);
},
/* load the project menu items */
onLaunch: function() {
this.getMainLeftMenu().bindStore(this.getProjectsStore());
},
/* update content on new selection */
onLeftMenuChange: function (view, records) {
if (records.length) {
this.showContent(records[0]);
}
},
showContent: function(record) {
this.getMainContent().bind(record);
}
});
Here is my leftContent view:
Ext.define('TST.view.main.LeftMenu', {
extend: 'Ext.view.View',
alias: 'widget.mainleftmenu',
initComponent: function() {
Ext.apply(this, {
id: 'leftmenu',
dock: 'left',
width: 200,
border: true,
cls: 'leftMenu',
selModel: {
deselectOnContainerClick: false
},
itemSelector: '.items',
tpl: [
'<div class="menuTitle">Projects</div>',
'<tpl for=".">',
'<div class="items">{name}</div>',
'</tpl>'
]
});
this.callParent(arguments);
}
});
Here is my content view:
Ext.define('TST.view.main.Content', {
extend: 'Ext.panel.Panel',
alias: 'widget.maincontent',
initComponent: function() {
Ext.apply(this, {
cls: 'content',
flex: 2,
border: false,
autoScroll: true,
layout: {
type: 'hbox',
align: 'middle',
pack: 'center',
availableSpaceOffset: Ext.getScrollbarSize().width
},
items: [
{
xtype: 'component', // think it has something to do with this?
itemId: 'contentCt',
width: 500,
height: 200,
border: 2,
tpl: [
'<div class="url">{url}</div>'
]
}]
});
this.callParent(arguments);
},
bind: function(record) {
this.child('#contentCt').update(record.getData());
}
});
And firebug shows that record.getData() returns:
object { id=1, name="This is page one", url="http://my.test.com/test.html"}
You will need to post more code, since this works without issue:
Ext.define('TST.view.main.Content', {
extend: 'Ext.panel.Panel',
alias: 'widget.maincontent',
initComponent: function() {
Ext.apply(this, {
cls: 'content',
flex: 2,
border: false,
autoScroll: true,
layout: {
type: 'hbox',
align: 'middle',
pack: 'center',
availableSpaceOffset: Ext.getScrollbarSize().width
},
items: [{
xtype: 'component', // think it has something to do with this?
itemId: 'contentCt',
width: 500,
height: 200,
border: 2,
tpl: ['<div class="url">{url}</div>']
}]
});
this.callParent(arguments);
},
bind: function(data) {
this.child('#contentCt').update(data);
}
});
Ext.onReady(function(){
var p = new TST.view.main.Content({
width: 500,
height: 200,
renderTo: document.body
});
p.bind({
url: 'foo'
});
});
I'm trying to create a Sencha Touch 2 form panel for a model in which one of the fields contains the URL to an image file. If I include a textfield, it'll display the text of the URL correctly, but what I really want is to display the image found at that URL, and I'm not sure how to do that. If I use xtype: image, I think I need a src config, and I'm not sure how to specify that the desired value is in one of the form fields. My view looks like this:
Ext.define("CatalogApp.view.ItemDetailView", {
extend: "Ext.form.Panel",
requires: "Ext.form.FieldSet",
alias: "widget.itemdetailview",
config:{
scrollable:'vertical'
},
initialize: function ()
{
this.callParent(arguments);
var backButton = {
xtype: "button",
ui: "back",
text: "Home",
handler: this.onBackButtonTap,
scope: this
};
var topToolbar = {
xtype: "toolbar",
docked: "top",
title: "Item Detail",
items: [
backButton
]
};
var mainLayout = {
xtype: "container",
layout: 'hbox',
items: [
{
xtype: 'textfield',
width: 200,
name: 'thumbUrl'
},
{
xtype: "fieldset",
flex: 1,
items : [
{
xtype: 'textfield',
name: 'itemNbr',
label: 'Item Nbr',
disabled: true
},
{
xtype: 'textfield',
name: 'itemDesc',
label: 'Item Desc',
disabled: true
}
]
}
]
};
this.add([
topToolbar,
mainLayout
]);
},
onBackButtonTap: function ()
{
console.log("backToHomeCommand");
this.fireEvent("backToHomeCommand", this);
}
});
How can I set up this view to display the image correctly?
You have to define new Sencha component: ImageField
Ext.define('Ext.ux.field.ImageField', {
extend: 'Ext.field.Field',
requires: [
'Ext.Img'
],
xtype: 'imagefield',
config: {
component: {
xtype: 'image'
}
},
updateValue: function(value, oldValue) {
var me = this,
component = me.getComponent();
component.setSrc(value);
},
proxyConfig: {
width: '100%',
height: '100%'
}
});
Than in form:
Ext.define("CatalogApp.view.ItemDetailView", {
extend: "Ext.form.Panel",
requires: "Ext.form.FieldSet",
alias: "widget.itemdetailview",
config:{
scrollable:'vertical'
},
initialize: function ()
{
this.callParent(arguments);
var backButton = {
xtype: "button",
ui: "back",
text: "Home",
handler: this.onBackButtonTap,
scope: this
};
var topToolbar = {
xtype: "toolbar",
docked: "top",
title: "Item Detail",
items: [
backButton
]
};
var mainLayout = {
xtype: "container",
layout: 'hbox',
items: [
{
xtype: 'imagefield', // only this change
width: 200,
height: 150,
name: 'thumbUrl'
},
{
xtype: "fieldset",
flex: 1,
items : [
{
xtype: 'textfield',
name: 'itemNbr',
label: 'Item Nbr',
disabled: true
},
{
xtype: 'textfield',
name: 'itemDesc',
label: 'Item Desc',
disabled: true
}
]
}
]
};
this.add([
topToolbar,
mainLayout
]);
},
onBackButtonTap: function ()
{
console.log("backToHomeCommand");
this.fireEvent("backToHomeCommand", this);
}
});
Cheers, Oleg
I'm having a dumb problem and I would like you to give me a hand.Thanks in advance.
The situatios is as follows: I have 2 wiews (both created with sencha architect 2.0), one for login, and another for general purposes. And I would like to load the second view on successful response when trying to log in, this is, after any successful login. The main problem is that I've tried with Ex.create, Ext.Viewport.add, Ext.Viewport.setActiveItem, but I can't manage to make the second view to appear on screen, the login screen just keeps there and the app does not load the other view. Another thing, I don't have to use a navigation view for this.
Here is the code of my controller, from which I want to load my second view. And as you'll see, I even created a reference of the view, which has autoCreate enabled and has that ID "mainTabPanel":
Ext.define('MyApp.controller.Login', {
extend: 'Ext.app.Controller',
config: {
refs: {
loginButton: {
selector: '#login',
xtype: 'button'
},
username: {
selector: '#user',
xtype: 'textfield'
},
password: {
selector: '#pass',
xtype: 'passwordfield'
},
mainTabPanel: {
selector: '#mainTabPanel',
xtype: 'tabpanel',
autoCreate: true
}
},
control: {
"loginButton": {
tap: 'onLoginButtonTap'
}
}
},
onLoginButtonTap: function(button, e, options) {
Ext.Ajax.request({
url: '../../backend/auth.php',
method: 'POST',
params: {
user: this.getUsername().getValue(),
pass: this.getPassword().getValue()
},
success: function(response) {
var json = Ext.decode(response.responseText);
if (json.type == 'success') {
// LOAD THE DAMN SECOND VIEW HERE!
//var paneltab = Ext.create('MyApp.view.MainTabPanel');
//Ext.Viewport.add(paneltab);
//Ext.Viewport.setActiveItem(this.getMainTabPanel());
} else {
alert(json.value);
}
},
failure: function(response) {
alert('The request failed!');
}
});
}
});
And here is the code of my login view:
Ext.define('MyApp.view.LoginForm', {
extend: 'Ext.form.Panel',
config: {
id: 'loginForm',
ui: 'light',
items: [
{
xtype: 'fieldset',
ui: 'light',
title: 'Log into the system',
items: [
{
xtype: 'textfield',
id: 'user',
label: 'User',
name: 'user'
},
{
xtype: 'passwordfield',
id: 'pass',
label: 'Pass',
name: 'pass'
}
]
},
{
xtype: 'button',
id: 'login',
ui: 'confirm',
text: 'Login'
}
]
}
});
And finally, the code of the view I want to load. This view loads normally if I set it as the Initial View, but does not load when a successful login occurs:
Ext.define('MyApp.view.MainTabPanel', {
extend: 'Ext.tab.Panel',
config: {
id: 'mainTabPanel',
layout: {
animation: 'slide',
type: 'card'
},
items: [
{
xtype: 'container',
layout: {
type: 'vbox'
},
title: 'Tab 1',
iconCls: 'time',
items: [
{
xtype: 'titlebar',
docked: 'top',
title: 'General Report',
items: [
{
xtype: 'button',
iconCls: 'refresh',
iconMask: true,
text: '',
align: 'right'
}
]
},
{
xtype: 'container',
height: 138,
flex: 1,
items: [
{
xtype: 'datepickerfield',
label: 'From',
placeHolder: 'mm/dd/yyyy'
},
{
xtype: 'datepickerfield',
label: 'To',
placeHolder: 'mm/dd/yyyy'
},
{
xtype: 'numberfield',
label: 'Hours'
}
]
},
{
xtype: 'dataview',
ui: 'dark',
itemTpl: [
'<div style="height:50px; background-color: white; margin-bottom: 1px;">',
' <span style="color: #0000FF">{user}</span>',
' <span>{description}</span>',
'</div>'
],
store: 'hoursStore',
flex: 1
}
]
},
{
xtype: 'container',
title: 'Tab 2',
iconCls: 'maps'
},
{
xtype: 'container',
title: 'Tab 3',
iconCls: 'favorites'
}
],
tabBar: {
docked: 'bottom'
}
}
});
Please, I need help... :)
I'm stuck here for like 3 days now and can't figure out what the problem is. Thank you.
Could you post your app.js too?
I'm trying your code here and it load the view as expected. Here is my app.js:
Ext.application({
name: 'MyApp',
requires: [
'Ext.MessageBox'
],
controllers: ['Login'],
views: ['LoginForm','MainTabPanel'],
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'
},
isIconPrecomposed: true,
startupImage: {
'320x460': 'resources/startup/320x460.jpg',
'640x920': 'resources/startup/640x920.png',
'768x1004': 'resources/startup/768x1004.png',
'748x1024': 'resources/startup/748x1024.png',
'1536x2008': 'resources/startup/1536x2008.png',
'1496x2048': 'resources/startup/1496x2048.png'
},
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
//Ext.Viewport.add(Ext.create('MyApp.view.Main'));
Ext.Viewport.add(Ext.create('MyApp.view.LoginForm'));
},
onUpdated: function() {
Ext.Msg.confirm(
"Application Update",
"This application has just successfully been updated to the latest version. Reload now?",
function(buttonId) {
if (buttonId === 'yes') {
window.location.reload();
}
}
);
}
});
Destroy the login panel, You don't really need it anymore...
success: function(response) {
var json = Ext.decode(response.responseText);
if (json.type == 'success') {
// LOAD THE DAMN SECOND VIEW HERE!
var paneltab = Ext.create('MyApp.view.MainTabPanel');
Ext.getCmp('loginForm').destroy();
Ext.Viewport.add(paneltab);
} else {
alert(json.value);
}
},
There are several problems here:
Your autoCreate rule uses an xtype: 'tabpanel' which will only ever create a vanilla Ext.TabPanel with no items in it. You'd need to assign an xtype attribute to your MyApp.view.MainTabPanel like xtype: 'mainTabPanel' and then use that xtype value in your autoCreate rule.
This then explains why this code won't work since this.getMainTabPanel() will return the wrong object. Simpler would be to just use Ext.Viewport.setActiveItem(paneltab).
In general, you usually don't want assign an id to a view (id: 'mainTabPanel'). Safer to just use an xtype to fetch it. Although you don't need it in this case, avoiding global id's allows you to create multiple instances of a view (or any other class type).