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
Related
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.
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.
In my app, I have two pagingtoolbar in two views (separate files), how can I query them both in the controller?
dockedItems: [{
xtype: 'pagingtoolbar',
store: 'User',
dock: 'bottom',
displayInfo: true
}]
bbar: {
xtype: 'pagingtoolbar',
store: this.store,
displayInfo: true
}
Just adding to Alex Tokarev's answer, if you want to select them at run time, lets say, when you click on a button, you can use:
...
handler : function () {
var mytoolbars = Ext.ComponentQuery.query('pagingtoolbar'); // will assign all available toolbars to your mytoolbars array.
}
....
Controllers use ComponentQuery and their selectors are global, so just xtype should work:
Ext.define('MyController', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
pagingtoolbar: {
...
}
});
}
});
I was wondering myself, how it is possible to pass data from a panel to another panel? The panel, to which I want to pass the data, is defined in the items-collection of the panel, which holds the data. So far, I tried to use the getParent()-Funktion, which looks like this:
Ext.define('Sencha.view.MyPanel', {
extend: 'Ext.Panel',
xtype: 'mypanel',
requires: ['Ext.Label', 'Ext.Button'],
config: {
title: 'Details',
styleHtmlContent: true,
scrollable: 'vertical',
layout: 'vbox',
items:
[
{
xtype: 'label',
flex: 3
},
{
xtype: 'panel',
flex: 3,
data: getParent().getData(),
},
As you may suppose, it doesn't work. Does anyone has any idea, how I could forward the data and fill the data-config of the children-panel?
You can use controller to call methods in the view, and pass values to them.
So, I'm trying to write a little MVC application which uses lists a lot.
I have one view which consists of a Panel with Toolbar docked to top and List:
app.views.SalonListView = Ext.extend(Ext.Panel, {
layout: 'card',
cardSwitchAnimation: 'slide',
dockedItems: [
{
xtype: 'toolbar',
dock: 'top'
}
],
items: [
{
xtype: 'SalonList',
id: 'salon-list'
}
]
});
Ext.reg('ListView', app.views.SalonListView);
I have an xtype for list defined in another file:
app.views.SalonList = Ext.extend(Ext.List, {
layout: 'card',
itemTpl: // some tpl is here
});
Ext.reg('SalonList', app.views.SalonList);
As you may notice, I don't set the Store for my List.
What am I trying to achieve is to set store in any Controller I use with this view.
Something like:
salonList: function() {
app.stores.SalonStore.read();
this.salonsView = this.render({
xtype: 'SalonListView',
// so I need to set store for the list somewhere around here
});
}
Is there any possibility I can set the Store for the List dynamically?