Sencha Touch List with Model and Store - javascript

I am looking for a tutorial / sourcecode for a sencha touch list with a model and a store. I am facing some issues with Sencha Touch 2.2.1.
Model:
Ext.define("DeviceAPIFramework.model.OfferModel", {
extend: "Ext.data.Model",
config: {
fields: [
{ name: "description", type: "string" },
{ name: "id", type: "string" }
]
}
});
Store:
Ext.define("DeviceAPIFramework.model.OfferStore", {
extend: "Ext.data.Store",
config: {
storeId: "offerStore",
model:'DeviceAPIFramework.model.OfferModel'
}
});
Controller:
offerStore.add({description: 'test', id: 'my id'});
Ext.ComponentQuery.query('#offersListHomeView')[0].update();
View:
Ext.require("DeviceAPIFramework.model.OfferStore");
var offerStore = Ext.create("DeviceAPIFramework.model.OfferStore");
Ext.define ...........
{
xtype: 'list',
width: Ext.os.deviceType == 'Phone' ? null : 1200,
height: Ext.os.deviceType == 'Phone' ? null : 350,
title: 'test',
itemId: 'offersListHomeView',
store: offerStore,
itemTpl: '{description} {id}'
}
Image:
After executing the code from the controller, a new row gets appended, but also a weird undefined text on the upper left corner of my list. Any suggestions how to fix this issue?
I also don't like the variable offerStore outside the view. If I put it in the controller, the view is nagging.

The undefined is coming from this line:
Ext.ComponentQuery.query('#offersListHomeView')[0].update();
update is decrapted(I wrote it, because I was developing once with an old Sencha Touch version and this update was necessary) and will call setHtml(), because we are passing no arguments it is settings "undefined", which will be shown in our view. In the new sencha version, you can simply delete this line.
I also managed the global store problem with this code in the controller:
launch: function() {
this.offersStore = Ext.create('Ext.data.Store', {
model: 'DeviceAPIFramework.model.OfferModel'
});
Ext.ComponentQuery.query('#offersListHomeView')[0].setStore(this.offersStore);
},

Related

Sencha: How to use data from one file to another

Im new at this sencha thingy and im trying to experiment a bit with it. I've been making some very simple tests and now i've reached the point where i want to pass the data from one file to another. To make it easier to understand im trying to get the data from the following text box to make a simple filter tool.
the textfield has been created in the following piece of code in the file Filters.js
Ext.define('Prj01Filtro.view.main.Filters', {
extend:'Ext.form.Panel',
xtype: 'Filters',
alias: 'form.formFilter',
requires: [
'Prj01Filtros.view.main.FilterController'
],
controller: 'controllerFilter',
items:[
{
margin: '0 0 10 0',
buttons: [
{
xtype: 'textfield',
fieldLabel: 'Filter',
name: 'textFieldSearch'
}, {
name: 'buttonSearch',
text: 'Buscar',
listeners: {
click: 'onClickFilter'
}
}, {
name: 'buttonRemoveFilter',
text: 'X',
listeners: {
click: 'onClickRemove'
}
}
]
}
]
The code of the buttons have been located in a file named FilterController.js
Ext.define('Prj01Filtros.view.main.FilterController',{
extend: 'Ext.app.ViewController',
alias: 'controller.controllerFilter',
onClickFilter: function() {
//Code to apply the filter
},
onClickRemove: function() {
//code to remove the filter
}
})
Finally the code of the table is located in a file named List.js
Ext.define('Prj01Filtros.view.main.List', {
extend: 'Ext.grid.Panel',
xtype: 'mainlist',
plugins: 'gridfilters',
requires: [
'Prj01Filtros.store.Personnel'
],
title: 'Personnel',
store: {
type: 'personnel'
},
columns: [
{ text: 'Name', dataIndex: 'name', align: 'left', filter: {
type: 'string'
}},
{ text: 'Email', dataIndex: 'email', flex: 1, align: 'left', filter: {
type: 'string'
}},
{ text: 'Phone', dataIndex: 'phone', flex: 1, align: 'left', filter: {
type: 'string'
}},
],
listeners: {
select: 'onItemSelected'
},
});
So my goal is to make a function in FilterController.js that can be called from Filters.js which sets the value for the filters applied in the columns of List.js but im kind of stuck on how to set the value property for the filter from the function that i have created. If someone knows how to do it i would appreciate the help. Thanks!
I've tried many things but since im new to sencha im pretty much sure that they were incorrect anyways.
I suggest to study View Models & Data Binding and ViewModel Internals sections of Ext JS documentation. These are among the most powerful features of Ext JS so it good to develop a deep understanding.
For you current question, you need to access the store behind your List view to manage the filters, not the list itself. Once you get the store, you can set / clear the filters with setFilters and clearFilter methods on the store:
store.setFilter([{
property: 'email',
value: '<search term here>',
operator: 'like'
}]);
store.clearFilter();
To easily access the store, define the store in the view model of a view that is above both List and Filters view. This is the important part because this way you can take advantage of inheriting the view model from the container parent. Let's say you have a panel which contains both List and Filters. Define the store in the view model:
stores: {
personnel: {
type: 'personnel'
}
}
Use bind config when assigning the store in your List:
Ext.define('Prj01Filtros.view.main.List', {
...
bind: {
store: '{personnel}'
}
...
});
After all this, you can access the store from the Filters view controller's methods:
onClickFilter: function() {
this.getViewModel().getStore('personnel').setFilters(...);
}
You need the get the value the user entered into the field. You can access it from the controller with querying the textfield component, but you can also do it with the view model.

Problems with references and stores in Sencha ExtJS

I’m new here in at Stackoverflow and to Sencha ExtJS development. I’m a student from Germany and I’m current trying to get my degree in media computer sciences. As a part of my final assignment I’m currently developing the UI of a webapp for a local company.
While I was trying out the capabilities of the Sencha ExtJS framework I came across some problems, which is why I’m now reaching out to the community for help ;)
My first problem I had, was when I was playing around with the syntax for instancing classes using xtypes and the association of Stores inside the ViewModel:
For the purpose of easier to read and less cluttered code I wanted to give my stores their own xtype so I could instead of declaring all the stores and their configs inside the ViewModels’ stores config wanted to have every store inside their own file and then just create an instance of them later inside the ViewModel. The code I wrote for this looks like this:
ViewModel:
Ext.define('Example.viewmodel.MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myviewmodel',
requires: [
'Example.store.MyStore',
],
stores: {
StoreA: { xtype: 'store_a' },
StoreB: { xtype: 'store_b' },
StoreC: { xtype: 'store_c' }
},
data: {
/* This object holds the arbitrary data that populates the ViewModel and
is then available for binding. */
}
});
StoreA:
Ext.define('Example.store.StoreA', {
extend: 'Ext.data.Store',
xtype: 'store_a',
requires: [
'Example.model.ModelA'
],
storeId: 'StoreA',
autoLoad: false,
model: 'Example.model.ModelA',
listeners: {
load: 'onLoadofStoreA'
}
});
But apparently this isn’t working… My load listener of the store does not seem to fire at the method inside my controller and does not even seem to know about the view that is associated with the ViewModel. What am I doing wrong or is this just not meant to be done like that?
My Second Problem was when I was playing around with some of the UI components. My scenario was like this:
I wanted to have a menu that would slide in, where u could do some inputs that would then load the content for the view.
I found this example for a sliding menu (https://examples.sencha.com/extjs/6.7.0/examples/kitchensink/?modern#menus) and built this:
Inside my ViewController:
getMenuCfg: function (side) {
var cfg = {
side: side,
controller: example_controller',
id: 'topMenu',
items: [
{
xtype: 'container',
layout: 'hbox',
width: '100%',
items: [
{
xtype: 'fieldset',
reference: 'fldSet',
id: 'fldSet',
layout: 'vbox',
width: '50%',
defaults: {
labelTextAlign: 'left'
},
items: [
{
autoSelect: false,
xtype: 'selectfield',
label: 'Selectfield',
reference: 'sfExample',
id: 'sfExample',
listeners: {
change: 'onSFChange'
}
},
{
xtype: 'container',
layout: {
type: 'hbox',
align: 'end',
pack: 'center'
},
items: [{
xtype: 'textfield',
reference: 'ressource',
id: 'ressource',
flex: 1,
textAlign: 'left',
margin: '0 10 0 0',
label: 'Ressource',
labelAlign: 'top',
labelTextAlign: 'left',
editable: false,
readOnly: true
},
{
xtype: 'button',
shadow: 'true',
ui: 'action round',
height: '50%',
iconCls: 'x-fa fa-arrow-right',
handler: 'openDialog'
}
]
},
{
xtype: 'textfield',
reference: 'tfExample',
id: 'tfExample',
label: 'Textfield',
editable: false,
readOnly: true
}
]
},
}]
}];
The problem I come across now is, that I would no longer be able to easily get the references of components inside the menu (input fields) with this.lookupReference() as if they were just part of the view. In fact to find a workaround I had to trace a way back to the components using a debugger.
For example if another method inside my controller wanted to use a field inside this menu, instead of simply just doing this.lookupReference(‘sfExample’) I now had to do something like this:
var me = this,
vm = me.getViewModel(),
menuItems = me.topMenu.getActiveItem().getItems(),
fieldset = menuItems.getByKey('fldSet'),
selectfieldRessArt = fieldsetLeft.getItems().getByKey('sfExample');
I’m pretty sure that I am missing out on something important here and there has to be a way to do this easier. I’m really looking forward to your answers, thank you in advance ;)
use xtype only for components. if you need to define an type/alias for store, use alias config property instead and especify the alias category "store.".
Defining a store with an alias
Ext.define('Example.store.StoreA', {
extend: 'Ext.data.Store',
//use store. to category as a store
alias: 'store.store_a',
requires: [
'Example.model.ModelA'
],
storeId: 'StoreA',
autoLoad: false,
model: 'Example.model.ModelA',
listeners: {
load: 'onLoadofStoreA'
}
});
Instantianting your store by type
Ext.define('Example.viewmodel.MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myviewmodel',
requires: [
'Example.store.MyStore',
],
stores: {
StoreA: { type: 'store_a' },
StoreB: { type: 'store_b' },
StoreC: { type: 'store_c' }
},
data: {
/* This object holds the arbitrary data that populates the ViewModel and
is then available for binding. */
}
});
I Hope it can help you

JS console error shows Extjs trying to make a GET request for a class as if it was a file

Sorry if the title isn't the best.
I'm roughing out a test project in Extjs 6. I have a viewmodel class that uses a store called customers:
Ext.define('ChildSessionBinding.view.main.ChildSessionModel',{
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.binding.childsession',
requires:[
'Ext.data.Store',
'ChildSessionBinding.model.Customer'
],
stores:{
customers:{
model: 'ChildSessionBinding.model.Customer',
autoLoad: true,
session: true
}
}
});
The model it requires has hard coded test data in it:
Ext.define('ChildSessionBinding.model.Customer', {
extend: 'Ext.data.Model',
fields: [
{ name: 'name', type: 'auto' },
{ name: 'phone', type: 'auto' }
],
data:[
{name: 'test', phone: '12345'}
]
});
And the view that uses the ViewModel is just a panel that shows a simple grid:
Ext.define('ChildSessionBinding.view.main.ChildSession', {
extend: 'Ext.panel.Panel',
xtype: 'binding-child-session',
title: 'Binding Child Session Demo',
layout: {
type: 'vbox',
align: 'stretch'
},
viewModel: {
type: 'binding.childsession'
},
controller: 'binding.childsession',
session: true,
items:[
{
flex: 1,
xtype: 'grid',
bind: '{customers}',
columns:[
{
dataIndex: 'name',
flex: 1,
text: 'Name'
},
{
dataIndex: 'phone',
flex: 1,
text: 'Phone'
},
{
xtype: 'widgetcolumn',
width: 90,
widget: {
xtype: 'button',
text: 'Edit',
handler: 'onEditCustomerClick'
}
}
]
}
]
});
When I load this in the browser, the grid does not load. I popped open the javascript console and saw that it was trying to make a get request to the server using the model's fully qualified name:
I've compared it to the kitchen sink example I'm trying to duplicate as well as other viewmodel stores that I've created in other projects and I don't see anything that would cause this.
Also, to rule out any project file structure questions, here's the folder/file structure:
EDIT
Here's the stack trace from the javascript console:
Anyone see the problem?
Put the data in your store, not in your model. Model doesn't have a data property.
I haven't used much of Ext 5 or 6 but I think I have seen this error on Ext 4. If a required class is undefined during the time of a class definition Ext will try to load a file with that name at the root of your application. I think that Ext should be throwing an error here by default instead of trying to load a file since I assume that most applications are not set up to handle this.
The fix would be to have ChildSessionBinding.model.Customer defined and executed before you load ChildSessionBinding.view.main.ChildSessionModel or have your application be able to load that file where Ext expects it to be.

Loading different views for different profiles

I'm not sure I understand how to use profile views within a Sencha Touch 2 app.
Ext.define(App.view.phone.PhonePanel, {
extend: 'Ext.tab.Panel',
xtype: 'Compare'
config: {
items: [
{ xtype: 'PanelA' },
{ xtype: 'Panel B' }
]
}
})
Ext.define(App.view.tablet.TabletPanel, {
extend: 'Ext.Panel',
xtype: 'Compare'
config: {
layout: 'vbox',
items: [
{ xtype: 'PanelA', flex: 1 },
{ xtype: 'Panel B', flex: 1 }
]
}
})
And then within the Phone Profile, it adds "PhonePanel" as a view, and the Tablet profile adds "TabletPanel"; and then when that specific profile is loaded it only loads those additional views.
The problem I'm having is that Sencha is loading files from both profiles, and doing
this.getAview().push({xtype:'Compare'});
While the phone profile is active, it actually pushes the Tablet's version of the xtype. What is going on here?
These are the different steps to create profiles in a Sencha Touch 2 application :
Create app/profile/Base.js containing the following code
You're more likely to need a base profile if you execute the same code at the launch of the app for both the profiles. So this step is mandatory
Ext.define('App.profile.Base', {
extend: 'Ext.app.Profile',
launch: function () {
/* Custom Code */
Ext.fly('booting').destroy();
}
});
Create app/profile/Phone.js containing the following code
If you chose to go without the base controller, then be sure to extend Ext.app.Profile instead of App.profile.Base :
Ext.define('App.profile.Phone', {
extend: 'App.profile.Base',
config: {
controllers: ['Main'],
views: ['Main']
},
isActive: function() {
return Ext.os.is.Phone;
},
launch: function() {
Ext.create('App.view.phone.Main');
this.callParent();
}
});
Create app/profile/Tablet.js containing the following code
If you chose to go without the base controller, then be sure to extend Ext.app.Profile instead of App.profile.Base :
Ext.define('App.profile.Tablet', {
extend: 'App.profile.Base',
config: {
controllers: ['Main'],
views: ['Main']
},
isActive: function() {
return Ext.os.is.Tablet || Ext.os.is.Desktop;
},
launch: function() {
Ext.create('App.view.tablet.Main');
this.callParent();
}
});
Create app/view/phone/Main.js containing the following code
Ext.define('App.view.phone.Main', {
extend: 'Ext.Container',
config: {
fullscreen: true,
items: [{
html:'This is the main view for the phone profile'
}]
}
});
Create app/view/tablet/Main.js containing the following code
Ext.define('App.view.tablet.Main', {
extend: 'Ext.Container',
config: {
fullscreen: true,
items: [{
html:'This is the main view for the tablet profile'
}]
}
});
That's it. You should be all set.
Hope this helped
You are using the same xtype twice.
Think of an xtype as a short name for your component. Each component needs to have a unique shortname or it will just get overwritten by the more recent definition.
Change the above two components to something like xtype: 'tabletcompare' and xtype: 'phonecompare'.
AND
this.getAview().push({xtype:'tabletcompare'}) <br>
Or
this.getAview().push({xtype:'phonecompare'})
when referencing the objects.
Hope this helps!

How to load XML into a list using Sencha/Phonegap?

I'm trying to setup a native style app using sencha touch and phonegap. I'm trying to pull in data from an external XML feed into the model.
In my model (Event.js) I have this:
Ext.regModel('Event', {
fields: [
{name: 'title', type: 'string'}
]
});
In my store (eventsstore.js):
ToolbarDemo.eventstore = new Ext.data.Store({
model: 'Event',
sorters: 'title',
getGroupString : function(record) {
return record.get('title')[0];
},
proxy: {
type: 'ajax',
url: 'http://the-url-to-the-file.xml',
reader: {
type: 'xml',
root: 'events',
record: 'event'
}
},
autoLoad: true
});
And in the view (tried as a list):
ToolbarDemo.views.Eventscard = Ext.extend(Ext.List, {
title: "Events",
iconCls: "search",
store: ToolbarDemo.eventstore,
itemTpl: '{title}',
grouped: true,
indexBar: true,
cardSwitchAnimation: 'slide'
});
Ext.reg('eventscard', ToolbarDemo.views.Eventscard);
And tried as a panel:
ToolbarDemo.views.Eventscard = Ext.extend(Ext.Panel, {
title: "Events",
iconCls: "search",
dockedItems: [{
xtype: 'toolbar',
title: 'Events'
}],
layout: 'fit',
items: [{
xtype: 'list',
store: ToolbarDemo.eventstore,
itemTpl: '{title}',
grouped: true
}],
//This was an experiment, safe to leave out?
initComponent: function() {
//ToolbarDemo.eventstore.load();
ToolbarDemo.views.Eventscard.superclass.initComponent.apply(this, arguments);
}
});
Ext.reg('eventscard', ToolbarDemo.views.Eventscard);
Now when I navigate to that card view, the loading overlay/spinner is displayed but that's as far as it goes, the list of items does not appear. Any ideas of what I'm doing wrong?
I am not that much familier with this, I have used like this to display a list.. try this
ToolbarDemo.eventstore.load();
var itemTpl = new Ext.XTemplate('<div id='title'>{title}</div>');
this.eventStoreList = new Ext.List({
id: 'eventStoreList',
store: ToolbarDemo.eventstore,
itemTpl: itemTpl,
height: 370,
indexBar: false
});
this.eventStoreListContainer = new Ext.Container( {
id : 'eventStoreListContainer',
items : [this.eventStoreList]
});
this.items = [this.eventStoreListContainer];
ToolbarDemo.views.Eventscard.superclass.initComponent.apply(this);
Well, I got it working!
I added ToolbarDemo.eventstore.read(); to the end of my store code, saved the XML file locally in the root 'www' folder then using the list method worked fine!
Does any body know why this (calling a remote XML) could be a problem?
EDIT: Turns out that it works fine in the browser like that, but not the iPhone simulator. So now I've set it back to the remote URL and added the URLs to the PhoneGap Whitelist and it works great :)

Categories

Resources