so here is the problem, I use MVC and I have several stores that I declared on app.js.
But now I need to do a login validation, and only load the stores after I get the response from the server, but if leave the declaration in app.js when the app loads it automatically loads all the stores.
Here is what my app is going needs to do:
LoginView make the validation, if validation is successful it changes the view to ListView, this view has a list that loads data from a store and this view can create other views with other lists.
I tried to require the stores in the ListView, but it throws errors cannot call method getCount of null.
What can I do to make it work. Thanks for the help.
Here is some code:
Ext.define("App.view.Listview", {
extend: 'Ext.Container',
xtype: 'listview',
requires: ['App.view.Listviewdetails',
'App.view.Filtros.FiltroJanelaPrincipal.Janelafiltrotiempoview',
'App.view.Menuview',
'App.view.Resultadopesquisaview',
'App.view.Pesquisaview',
'App.view.Maisinfousuarioview',
'Ext.Label',
'Ext.field.Search',
'App.store.Tiempos',
'App.store.Empresas',
'App.store.Produtos',
'App.store.Usuarios',
'App.store.FiltrosEvento',
'App.store.Historicos',
'App.store.Pesquisas'
],
config: {
id: 'listView',
layout: 'card',
items: {
layout: 'vbox',
id: 'listaEventos',
items: [
{
xtype: 'list',
id: 'listaTiempos',
flex: 6,
emptyText: 'Empty',
store: 'Tiempos',
itemTpl: '{dataTermino} {descricaoPrevia}'
}
]
}
and one of the stores:
Ext.define("App.store.Tiempos",{
extend: 'Ext.data.Store',
config: {
model: 'App.model.Tiempo',
autoLoad: true,
proxy: 'searchProxy'
}
});
You can add the stores in require in the respective view classes. It is not compulsory to add in app.js.
So after login when the view will be instantiated the store will be loaded automatically.
Related
I'm getting this error:
[E] Ext.data.Session.checkModelType(): Unable to use anonymous models
in a Session
when trying to use a Session when binding a Grid with a Store via ViewModel:
ViewModel:
Ext.define('App.view.gridViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.gridview',
stores:{
gridstore: {
model: 'gridView',
autoLoad: true,
//This triggers the Exception:
session: true,
listeners: {
beforeload: function(store, operation, eOpts) {
var oProxy = this.getProxy();
oProxy.setExtraParams({
tableName: 'dbo.SomeTable'
, identityKey: "id"
, primaryKey: ["id"]
, mode: "readonly"
, lang: "es"
, output: 'json'
});
}
}
}
}
});
View:
Ext.define('App.view.gridView', {
extend: 'Ext.form.Panel',
//...
viewModel: {
type: 'gridview'
},
controller: 'gridview',
// Create a session for this view
session:true,
items: [{
xtype: 'grid',
reference: 'myGrid',
bind: '{gridstore}',
columns: [
//...
]
}]
//...
});
Model's data is fetch through a Proxy:
Model:
Ext.define("App.model.gridView", {
extend: 'Ext.data.Model',
schema: {
namespace: 'App.model'
},
proxy: {
//proxy remote api stuff......
}.
idProperty: 'id'.
primaryKeys: 'id'.
fields: [
//fields
]
});
I have no idea what an anonymous model is and I haven't found anything related in the web, any ideas?
Thanks in advance!
The reason seems to be that in my Server's response I have a JSON Object called "metaData", which collides with the one available in JSON Reader:
Response MetaData
The server can return metadata in its response, in addition to the
record data, that describe attributes of the data set itself or are
used to reconfigure the Reader. To pass metadata in the response you
simply add a metaData attribute to the root of the response data. The
metaData attribute can contain anything, but supports a specific set
of properties that are handled by the Reader if they are present:
http://docs.sencha.com/extjs/5.0/apidocs/#!/api/Ext.data.reader.Json
The curious thing is that I don't use any of the available metaData options for JSON Reader, nothing related to any anonymous model, therefore this might be considered a bug
Question
I used to use extJs 4 with MVC, now I want to change to extjs 5 and add ViewModel and ViewController into it. But I have no privilege to install SenchaCmd to generate and compile the app as the guides says. I wonder if SenchaCmd is necessarily in ExtJs5, because when I add a ViewController for a view, there's error - Uncaught Error: [Ext.createByAlias] Unrecognized alias: controller.mainViewController.
If there's no SenchaCmd but I want to add ViewController and ViewModel for my app, what should I do?
Code
MyApp.view.main.MainView.js
Ext.define('MyApp.view.main.MainView', {
extend: 'Ext.tab.Panel',
alias: 'widget.MainView',
// requires: ['main.MainViewModel'],
controller: 'mainViewController',
// viewModel: {
// type: 'mainView'
// },
tabPosition: 'left',
tabRotation: 0,
defaults: {
textAlign: 'left',
bodyPadding: 15
},
items: [{
title: 'test',
items: [{
xtype: 'button',
listeners: {
onClick: 'onTest'
}
}]
}]
});
CaTools.view.main.MainViewController.js
Ext.define('CaTools.view.main.MainViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.mainViewController',
onTest: function() {
console.log('test -- ');
}
});
Error
Error - Uncaught Error: [Ext.createByAlias] Unrecognized alias: controller.mainViewController
Many Thanks!!
All that Sencha CMD is doing for you - in this context, anyway - is building a bootstrap file. As part of that, it knows that when it brings in a View, and it sees that the view has a viewModel and controller attribute, it looks for ViewModel and ViewController classes by convention (Model and Controller).
So you can do that yourself. Simply require the ViewModel and ViewController classes from within your View, just as you would require any other class.
(As an alternative - define the ViewModel and ViewController as additional classes inside the View's Javascript file; that way it's always loaded when the View is)
I'm trying to do is figure out how to pass in variables to a view from a controller.
For example, let's say I have a login screen where I want to display the application version and the some other custom device information. How would I go about passing that info into the view?
Ext.define('MyApp.view.Login', {
extend: 'Ext.form.Panel',
xtype: 'loginform',
config: {
items: [
{
xtype: 'label',
cls: 'appVersion',
html: 'Version #:' + versionNumber
}
]
}
});
Also how much different would it be if I used tpl instead of html ?
Thanks for any help!
You can always pass data during view creation like this:
var loginPanel = Ext.create('MyApp.view.Login', {
ver : versionNumber // any value or data you want to pass
});
for that you might have to define ver in your view's config
Ext.define('MyApp.view.Login', {
extend: 'Ext.form.Panel',
xtype: 'loginform',
config: {
ver : '', // Initialize with empty string
items: [
{
xtype: 'label',
cls: 'appVersion',
html: 'Version #:' + versionNumber
}
]
}
});
Once created with required value you can add it anywhere you want
Ext.Viewport.add(loginPanel);
You can always use PhoneGap (Cordova) for this: http://docs.phonegap.com/en/2.3.0/cordova_device_device.md.html#Device
Also, using html or tpl is fine.
I'm beginning development of an app in extjs. I'm using the MVC approach, as provided in the extjs documentation.
I have some dynamic data which needs to present the user with a set of accordion controls. I've got the data in a store, but I do not know how to dynamically create the accordion items (unlike grid panels, there doesn't appear to be a store data method).
Here is my current accordion view code - with static items:
Ext.define('BP.view.induction.LeftPage', {
extend: 'Ext.Panel',
alias : 'widget.leftpage',
title: "Left Page",
layout: {
type: 'accordion',
align: 'stretch'
},
layoutConfig: {
// layout-specific configs go here
titleCollapse: true,
animate: true,
activeOnTop: true
},
items: [{
xtype: 'panel', // fake hidden panel, so all appear collapsed
hidden: true,
collapsed: false
},{
xtype: 'panel',
title: 'Panel 1',
html: 'Panel content!'
},{
xtype: 'panel',
title: 'Panel 2',
html: 'Panel content!'
},{
xtype: 'panel',
title: 'Panel 3',
html: 'Panel content!'
}]
});
Any guidance on how to achieve the above would be appreciated, thank you.
[Edit] In response to sra's request, here is my controller:
Ext.define('BP.controller.Induction', {
extend: 'Ext.app.Controller',
views: [
'induction.Binder'
],
stores: [
'Sections',
'Categories',
'Tasks'
],
init: function() {
console.log('Initialized Induction!');
}
});
I should note here that this controller loads a parent view, which in turn loads the LeftPage view - I'm not sure if this creates any scoping issues. Furthermore, as you can see, more than one store is loaded.
You can do like this (untested example with some tweaks)
Ext.define('BP.view.induction.LeftPage', {
extend: 'Ext.Panel',
alias : 'widget.leftpage',
title: "Left Page",
layout: null,
layoutConfig: null,
store: null,
attentive: true,
initComponent: function() {
var me = this;
// begin edit
// only set the store if is is not already defined
me.store = me.store ? me.store : Ext.StoreMgr.lookup('Sections'); // you may change this to any storename you want
// end edit
me.layout = { // don't set objects directly in class definitions
type: 'accordion',
align: 'stretch'
};
me.layoutConfig = { // dont set objects directly in class definitions
titleCollapse: true,
animate: true,
activeOnTop: true
};
me.callParent(arguments);
if (me.attentive) {
me.store('load', me.onRebuildContent, me);
if (me.store.count() == 0)
me.store.load();
} else {
me.buildContent();
}
},
buildContent: function() {
var me = this;
function addItem(rec) {
me.add({
xtype: 'panel',
title: rec.get('titleProperty'),
html: rec.get('bodyProprty')
});
};
me.store.each(addItem);
},
onRebuildContent: function() {
var me = this;
me.removeAll();
me.buildContent();
}
});
Your store will need at least two properties; one for the title and one for the content. And the store need to be loaded before you should instantiate this. But that can easily be done within your controller.
Edit based on comment and new OP info:
Well your view is a bit out of control of the controller. So I recommend you to simply use the StoreManager to receive a valid instance (I've edited the code, I just didn'T know the correct store to use). The StoreManager will know about the store as long as you list him within a controller (StoreManager is capable of much more, but that is all you need to know at the moment). For a further release you could also use the mixin bindable which would manage a storebinding more clean and enables you to update your accordion after the store receives new data (get updated)
Edit for readability
I've just cleaned it up a bit and included a switch param attentive which would allow you to use this component as directly bound to a store, reacting on all load events or as a sort of static one where the store should already be loaded. All in all this should give you a start without making it to complex.
In an MVC style Ext JS 4 application, assuming I have a single controller/view/store/model and that loads up properly- for an example, let's say this example is my code base.
My application loads up a view with a grid (list of Users), then when a row is clicked it opens and edit (User) view with a form.
Now, I want to add additional views to be displayed inside that form.
For example, I want to show a 'last 10 logins' (a list of activity records for the user) below the fields in the User form. I will have a separate view/controller/model/store for 'ActivityLog'. So I need to create the ActivityLog List view/controller and place it inside my User view (it will also have it's own code/logic to handle clicks on those records in it's grid, etc.).
Is that the correct approach?
Would the User controller load the view/controller of ActivityLog and somehow place it in to the User edit view, or do I have config data directly inside the User edit view that loads it in ?
Ok. Probably you can use something like this
// Navigation controller
Ext.define('App.controller.Navigation', {
extend: 'Ext.app.Controller',
models: [],
stores: [],
views: ['navigation.TabHost'],
init: function() {
this.control({
'tabhost': {
'render': function(tabHost) {
// Grid panels are panels too. So It does not make any sense to use additional container.
tabHost.add(Ext.create('App.view.users.List'));
tabHost.add(Ext.create('App.view.activitylogs.List'));
}
}
}
});
// Users controller
Ext.define('App.controller.Users', {
extend: 'Ext.app.Controller',
models: [],
stores: [],
views: ['users.List'],
init: function() {
this.control({
'userslist': {
'render': function(gridPanel) {
console.info('Im here');
}
}
}
});
// ActivityLog controller
Ext.define('App.controller.ActivityLog', {
extend: 'Ext.app.Controller',
models: [],
stores: [],
views: ['activitylogs.List'],
init: function() {
this.control({
'loglist': {
'render': function(gridPanel) {
console.info('Im here');
}
}
}
});
// Also you should have tree view files
// navigation.TabHost
Ext.define('App.view.navigation.TabHost', {
extend: 'Ext.tab.Panel',
alias: 'widget.tabhost',
initComponent: function() {
// ......
}
});
// users.List
Ext.define('App.view.users.List', {
extend: 'Ext.grid.Panel',
alias: 'widget.userslist',
initComponent: function() {
// ......
}
});
// activitylog.List
Ext.define('App.view.activitylogs.List', {
extend: 'Ext.grid.Panel',
alias: 'widget.logslist',
initComponent: function() {
// ......
}
});
Navigation controller will create widges and insert them to its tabhost.
But ActivityLog and Users Controllers will manipulate their views.
Would the User controller load the view/controller
Yes, you can do this.
User controller can use view from another controller. In other case controller can listen to view which was added in the another controller.
First off all you should register controllers in app.js
Ext.application({
name: 'App',
autoCreateViewport: true,
appFolder: 'js/App',
controllers: [
'User',
'ActivityLog'
],
launch: function() {
}
});
After that all views/stores/models, which was described in the controllers files, will be loaded automatically.
You will have ability to manipulate (add/remove) views wherever you want. But controllers will be listening to the views that you definitely specified.