Populating View in Sencha Touch 2 - model-view-controller

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.

Related

Add change event handler for custom Container of ExtJS

I have created a View by extending Ext.container.Container and have given it an alias widget.myCustomView. Since I'm using it in different places.
The view as usual Ext form components like textfield, dataview, etc. Now I adding this view into other view using xtype as follows:
{
xtype: 'myCustomView',
itemId: 'myCustomView'
}
Now, I want to add change event handler such that if any component's change is fired, I can fire the change event of myCustom view. In short, do something like this.
{
xtype: 'myCustomView',
itemId: 'myCustomView',
listeners: {
'change' : function(viewObj, eOpts) {
//do something
}
}
}
How to do it?
Use the relayEvents() method to... well, relay the change event from child fields.
Here's some basic code that does that:
Ext.define('My.Container', {
extend: 'Ext.Container'
,layout: 'form'
,initComponent: function() {
this.callParent(arguments);
// i want to support nested containers
this.parseContainerItems(this);
}
,onItemAdded: function(item) {
if (item instanceof Ext.Container) {
this.parseContainerItems(item);
} else if (item instanceof Ext.form.field.Base) {
this.relayEvents(item, ['change']);
}
}
,parseContainerItems: function(ct) {
if (ct.items) {
ct.items.each(this.onItemAdded, this);
}
}
});
Example usage:
Ext.create('My.Container', {
renderTo: 'ct' // render to a test div
,height: 200
,width: 200
,items: [{
xtype: 'textfield', name: 'foo', fieldLabel: 'Foo'
},{
xtype: 'container'
,items: [{
xtype: 'checkbox', name: 'bar', fieldLabel: 'Bar'
}]
}]
,listeners: {
change: function(item, newValue, oldValue) {
console.log(Ext.String.format('Value of item {0} changed from {1} to {2}', item.name, oldValue, newValue));
}
}
});
Going further...
As I've said my implementation is quite rudimentary since it only supports fields that are added to the container by configuration. If you want to make that component flexible, you'll have to handle fields that are added after the component creation.
For that you'll need to watch the add event of the container to relay from fields that are added after its creation. The doc says that this event bubbles from child containers, but from my tests it does not :-( So (until that's fixed?) you'll also have to watch the add event of child containers.
Here's the updated code for the parseContainerItems() method:
parseContainerItems: function(ct) {
ct.on('add', function(me, item) {
this.onItemAdded(item);
}, this);
if (ct.items) {
ct.items.each(this.onItemAdded, this);
}
}
If you also want to support the possibility of removing fields dynamically, that's when things will go awry... You'd have to implement your own version of relayEvents() because, as far as I know, it is not possible to stop relaying events with the one provided by Ext. Then you'd have to watch the remove event to remove the listeners you've added to child fields and containers.

Sencha Touch dynamically use of stores with mvc?

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.

Extjs create dynamic accordion using store

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.

Nestedlist not showing store data when inside panel

I'm having a problem loading my nestedlist data when this list is shown inside of a panel.
Here is my code:
var titleBar = Ext.create("Ext.TitleBar", {
id: 'mainNavigationBar',
xtype : 'titlebar',
layout: 'hbox',
docked: 'top',
title : 'cSenchaTitleBar',
items:[
{
xtype:"button",
text:"Menu",
align:"left",
listeners:{
tap: function(){
nestedListxx.showBy(this);
}
}
},
]
});
var nestedList =
Ext.create('Ext.NestedList', {
displayField: 'text',
title:"cSenchaMenu",
store: "oNavStore",
id: 'mainNestedList',
xtype : 'nestedlist',
width:250,
useTitleAsBackText: false,
});
var nestedListxx = Ext.create("Ext.Panel", {
width:260,
items:nestedList
});
The problem is the following:
Say that if I change
nestedListxx.showBy(this); to nestedList.showBy(this);
It works like a charm, only there are no sleek black borders around the nested list.
But if I change it back it does show the nestedlist with the nice borders but without any data.
I know for sure that I forgot to set some key configuration, only the question is: which ones
You probably need to set a layout to your Ext.Panel.
Try :
var nestedListxx = Ext.create("Ext.Panel", {
width:260,
layout:'fit',
items:nestedList
});
Hope this helps

Sencha Touch 2.0 Controller refs attribute not working?

i am wondering about the 'refs' attribute of Sencha Touch class 'Ext.app.Controller'.
I saw a video tutorial where a simple contactForm was built. No i've tried to build a contact form for my app and i get an error: 'Uncaught TypeError: Object [object Object] has no method 'getContactForm''
Here's my controller
Ext.define('MyFirstApp.controller.Main', {
extend: 'Ext.app.Controller',
views: ['Viewport', 'Home'],
refs: [
{
ref: 'contactForm',
selector: '#contactForm'
}
],
init: function() {
this.control({
'button[action=submitContact]': {
tap: 'submitContactForm'
}
});
},
submitContactForm: function() {
var form = this.getContactForm();
form.submit({
url: 'contact.php'
});
}
});
I guess it's something wrong with the 'refs', in the video that guy said the "getContactForm" method will be created because of the "ref" attribute of "contactForm" but it doesn't. What am i doing wrong here?..Thanks for help!
The refs attribute property changed from Sencha Touch 2.0 developer preview version to beta/final version. So, what you wrote were correct for dev preview but presently it just name value pair. For your case:
refs: {
contactForm: '#contactForm'
}
I agree with jeremygerrits, I can't be sure that's the correct syntax for defining refs.
Based on the documentation, I would rather do it like this:
Ext.define('MyFirstApp.controller.Main', {
extend: 'Ext.app.Controller',
views: ['Viewport', 'Home'],
config: {
refs: {
contactForm: '#contactForm'
}
}
init: function() {
this.control({
'button[action=submitContact]': {
tap: 'submitContactForm'
}
});
},
submitContactForm: function() {
var form = this.getContactForm();
form.submit({
url: 'contact.php'
});
}
});
See also: http://docs.sencha.com/touch/2-0/#!/guide/controllers
It looks as though you may have the refs configured wrong. Here's a simple controller:
Ext.define('App.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
main: 'mainpanel'
}
}
});
mainpanel is an xtype or could be a css selector and main will give you getMain() like what was talked about in the video.

Resources