Extending own classes - class

i am develop an app with several windows. Many windows are similar, so i think write a superclass, and extend it.
I have, the superclass:
Ext.define('AM.view.ui.DecoratorAbstract',{
extend: 'Ext.window.Window',
alias: 'widget.decoratorAbstract',
initComponent: function(){
this.title = this.aTitle;
this.resizable = this.cfg[0];
this.closable = this.cfg[1];
this.minimizable = this.cfg[2];
//this.items = this.anItem;
this.callParent(arguments);
}
});
And the subclass:
Ext.define('AM.view.ui.DecoratorForm',{
extend: 'AM.view.ui.DecoratorAbstract',
alias: 'widget.decoratorForm',
initComponent: function(){
this.callParent();
this.buttons = [
{ text:'Guardar', action:'save', iconCls: 'ico-save' },
{ text:'Cancelar', action:'cancel', iconCls: 'ico-cancel' }
];
}
});
Both classes are included in the Controller:
Ext.define('AM.controller.Ui',{
extend: 'Ext.app.Controller',
views: [
'ui.Toolbar',
'ui.Statusbar',
'ui.AlertErr',
'ui.AlertOk',
'ui.AlertWar',
'ui.AlertDelete',
'ui.AlertUndelete',
'ui.DecoratorAbstract',
'ui.DecoratorForm',
'ui.DecoratorGrid'
],
model: [],
store: [],
});
From the Firebug js console i create the subclass:
Ext.create('AM.view.ui.DecoratorForm',{cfg:[true,true,true],aTitle: 'Title'}).show();
The window is showed but, not the buttons.
Any ideas ?.

There are a few things here... First, move this.callParent() to the end of your initComponent. This is because the initComponent further up the inheritance does something with this.buttons, and you are missing out on that by calling callParent before setting the buttons.
Next, you really shouldn't use this cfg thing that you are passing in. Just pass in the config parameters that you want to use, and they will be available:
Ext.define('AM.view.ui.DecoratorAbstract',{
extend: 'Ext.window.Window',
alias: 'widget.decoratorAbstract',
initComponent: function(){
this.callParent(arguments);
}
});
Ext.define('AM.view.ui.DecoratorForm',{
extend: 'AM.view.ui.DecoratorAbstract',
alias: 'widget.decoratorForm',
initComponent: function(){
this.buttons = [
{ text:'Guardar', action:'save', iconCls: 'ico-save' },
{ text:'Cancelar', action:'cancel', iconCls: 'ico-cancel' }
];
this.callParent();
}
});
//to instantiate:
Ext.create('AM.view.ui.DecoratorForm',{
resizable: true,
closable: true,
minimizable: true,
title: 'Title'
}).show();
Anytime you are trying to "trick" the component by using something like that cfg array, you should probably re-think what you're doing and see if there's a smarter way.
One other thing you should look into using is Ext.apply(). It will save a lot of bytes by changing what you had before into something like this:
Ext.apply(this, {
title: 'my title',
resizable: cfg[0],
closable: cfg[1],
///...etc...
})

What if you move
this.callParent(arguments);
To the end of initComponent in your DecoratorForm.

Related

ExtJS6 Extending Components

If I declare a custom component, how to I correctly apply changes to the properties when I create an extension of the component? For example:
Ext.define('GridForm',{
extend: 'Ext.window.Window',
initComponent: function(){
Ext.apply(this,{
title: 'This a test window!'
,height: 400
,width: 400
});
this.callParent();
}
});
Ext.define('LedDataForm',{
extend: 'GridForm',
initComponent: function(){
Ext.apply(this,{
title: 'OK, I want to change it to this.'
});
this.callParent();
}
});
Ext.application({
name : 'MyApp',
launch : function() {
Ext.create('LedDataForm').show();
}
});
In this example, I simply want to change the title of the window when I create "LedDataForm". All comments are appreciated.
Don't write the configs whatever you want to override in init function, instead give it as a default config.
Ext.define('GridForm',{
extend: 'Ext.window.Window',
title: 'This a test window!',// Give this as configs rather than in init function
initComponent: function(){
Ext.apply(this,{
width:400,
height:400
});
this.callParent();
}
});
Ext.define('LedDataForm',{
extend: 'GridForm',
title: 'OK, I want to change it to this.',
initComponent: function(){
Ext.apply(this,{
});
this.callParent();
}
});
Ext.application({
name : 'MyApp',
launch : function() {
Ext.create('LedDataForm',{
title:'testing'
}).show();
}
});
Why not do this:
Ext.define('GridForm',{
extend: 'Ext.window.Window',
title: 'This a test window!',
height: 400,
width: 400
});
Ext.define('LedDataForm',{
extend: 'GridForm',
title: 'OK, I want to change it to this.'
});
Ext.application({
name : 'MyApp',
launch : function() {
Ext.create('LedDataForm').show();
}
});
Simple static configuration can be applied to the class body (2nd argument passed to Ext.define).
initComponent is usually only necessary if you need to calculate values or execute initialization logic.
Also, you could take a look here as it explains a lot: The Class System.

ExtJs 6 Store not visible in Grid

I'm trying to port existing application from ExtJs 4.2.1 to 6.0.1
The problem that in debugger I see that grid has 'ext-empty-store' store instead of 'store.accounting.Quota'
I can load the store directly in panel activation listener by doing
var store = Ext.data.StoreManager.lookup('QuotaKPI.store.accounting.Quota');
store.load();
In firebug I see request and perfect json in response but nothing appears in the grid
Here are code snippets
app/store/accounting/Quota.js
Ext.define('QuotaKPI.store.accounting.Quota', {
extend: 'Ext.data.JsonStore',
model: 'QuotaKPI.model.accounting.QuotaModel',
alias: 'store.accounting.Quota',
storeId: 'QuotaKPI.store.accounting.Quota',
autoLoad: false,
proxy: {
...
}
});
app/view/accounting/QuotaGrid.js
Ext.define('QuotaKPI.view.accounting.QuotaGrid', {
extend: 'Ext.grid.Panel'
,xtype: 'QuotaGrid'
,store: Ext.data.StoreManager.lookup('QuotaKPI.store.accounting.Quota')
,columns: [
...
]
,dockedItems : [
,{xtype: 'pagingtoolbar',
dock:'bottom',
store: Ext.data.StoreManager.lookup('QuotaKPI.store.accounting.Quota'),
displayInfo: true,
displayMsg: 'Displaying Quota Details {0} - {1} of {2}',
emptyMsg: "No Quota to display"
}
]
,initComponent: function() {
this.callParent(arguments);
}
});
Store, model and grid declared in controller
Ext.define('QuotaKPI.controller.accounting.AccountingController', {
extend: 'Ext.app.Controller',
stores: ['accounting.Quota'],
models: ['accounting.QuotaModel'],
views: ['accounting.QuotaGrid']
...
And controller itself listed in app.js
Ext.application({
name: 'QuotaKPI',
controllers: [
'accounting.AccountingController'
],
init: function(app){
},
autoCreateViewport: true
});
Any help, please?
I know storeId doesn't accept some character (for example "-"), I don't know for dot... in any case I suggest to make it simple.
Try "myStoreId"
In addition you can try:
Ext.define('QuotaKPI.view.accounting.QuotaGrid', {
extend: 'Ext.grid.Panel'
,xtype: 'QuotaGrid'
,store: "myStoreId",
,columns: [
...
]
,dockedItems : [
,{xtype: 'pagingtoolbar',
dock:'bottom',
store: "myStoreId",
displayInfo: true,
displayMsg: 'Displaying Quota Details {0} - {1} of {2}',
emptyMsg: "No Quota to display"
}
]
,initComponent: function() {
this.callParent(arguments);
}
});
In addition I suggest to ensure you have a proper schema configuration (see http://docs.sencha.com/extjs/6.0/6.0.1-classic/#!/api/Ext.data.schema.Schema)
And then, you could try also with ViewModel instead of storeId (see http://docs.sencha.com/extjs/5.0/application_architecture/view_models_data_binding.html)
Don't hesitate to do a https://fiddle.sencha.com/#home
Good Luck!
Transition is not easy...

Multi model data binding

OK, I have a great confusion about data binding in SAPUI5.
After reading this and this info I still don't know why my code doesn't work.
I define the data and the model in onInit function of the controller:
var oControlsData = {
controls: [
{control: [
{title: "Input Filed"},
{visible: true},
{iconUrl: "sap-icon://edit"}
]},
{control :[
{title: "Combo Box"},
{visible: true},
{iconUrl: "sap-icon://edit"}
]},
{control :[
{title: "Radio Button"},
{visible: true},
{iconUrl: "sap-icon://bo-strategy-management"}
]}
]
};
var oControlsModel = new sap.ui.model.json.JSONModel(oControlsData);
sap.ui.getCore().setModel(oControlsModel, "controls");
Then, in onAfterRendering function I try to bind data from the model to the sap.m.List control:
var oList = sap.ui.getCore().byId("controlsList");
var oListTemplate = new sap.m.StandardListItem({
title: "{title}",
visible: "{visible}",
icon: "{iconUrl}"
});
oList.bindItems({
path: "controls>/controls/control",
template: oListTemplate
});
It seems to me the path is correct, but I still get "No Data" in the control.
What went wrong here?
If I miss something big in understanding data binding process, please give a brief explanation, because every time I have to play with data binding I wonder if it work or not.
The path in bindItems should be the path to the list of Items.
So in your case controls>/controls.
The paths of the properties of the ListItem should then be relative to each object in the list.
sap.ui.getCore().byId("controlsList").bindItems({
path: "controls>/controls",
template: new sap.m.StandardListItem({
title: "{controls>control/0/title}",
visible: "{controls>control/0/visible}",
icon: "{controls>control/0/iconUrl}"
})
});
You need the control/0/ because of your inner array. If you have control over the structure of your data, I would recommend to remove that.
var oControlsData = {
controls: [
{
title: "Input Filed",
visible: true,
iconUrl: "sap-icon://edit"
},
...
]
};
On a sidenote, why are you doing databinding in onAfterRendering?
This should be done in the View. For example in XML:
<List items="{controls>/controls}">
<StandardListItem title="{controls>control/0/title}" visible="{controls>control/0/visible}" icon="{controls>control/0/iconUrl}" />
</List>

Sencha ExtJS RESTful grid example confusion

I am very confused by the Sencha documentation for ExtJS. The documentation begins with a Getting Started guide which highlights and illustrates the importance on a suitable structure for the classes and source code of your application. But the provided examples then break all the conventions laid down by the Getting Started guide. Instead of code being broken down into appropriate Model, Store, View, etc. class files the examples are provided as a single file with example source code which is not easily re-usable in separate source files.
I started by following the Portal example (http://docs.sencha.com/ext-js/4-1/#!/example/portal/portal.html) as this is the sort of application I want to create. I wanted to enhance the Portal example and add in a screen which would display a grid and use a RESTful web service as the data backend. I have created the backend I just want to create the front-end. So I looked at the RESTful example (http://docs.sencha.com/ext-js/4-1/#!/example/restful/restful.html)
I have tried to copy the RESTful example into the recommended pattern of seperate classes e.g. Model, Store, View:
Model:
Ext.define('MyLodge.model.Member', {
extend: 'Ext.data.Model',
fields: [
{name: 'name', type: 'string'},
{name: 'email', type: 'string'},
{name: 'href', type: 'string'}
]
});
Store:
Ext.require('MyLodge.model.Member');
Ext.define('MyLodge.store.Members', {
autoLoad: true,
autoSync: true,
model: 'MyLodge.model.Member',
proxy: {
type: 'rest',
url: 'http://localhost:8888/rest/memberapi/members' ,
reader: {
type: 'json',
root: 'data'
},
writer: {
type: 'json'
}
},
listeners: {
write: function(store, operation){
var record = operation.getRecords()[0],
name = Ext.String.capitalize(operation.action),
verb;
if (name == 'Destroy' ) {
record = operation.records[0];
verb = 'Destroyed';
} else {
verb = name + 'd';
}
Ext.example.msg(name, Ext.String.format( "{0} member: {1}", verb, record.getId()));
}
}
});
View:
Ext.define('MyLodge.view.content.MemberGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.membergrid',
initComponent: function(){
var store = Ext.create('MyLodge.store.Members' );
Ext.apply( this, {
height: this.height,
store: store,
stripeRows: true,
columnLines: true,
columns: [{
id : 'name',
text : 'Name',
flex: 1,
sortable : true,
dataIndex: 'name'
},{
text : 'E-Mail',
width : 150,
sortable : true,
dataIndex: 'email'
},{
text : 'Href',
width : 200,
sortable : true,
dataIndex: 'href'
}],
dockedItems: [{
xtype: 'toolbar',
items: [{
text: 'Add',
iconCls: 'icon-add',
handler: function(){
// empty record
store.insert(0, new MyLodge.model.Member());
rowEditing.startEdit(0, 0);
}
}, '-', {
itemId: 'delete',
text: 'Delete',
iconCls: 'icon-delete',
disabled: true,
handler: function(){
var selection = grid.getView().getSelectionModel().getSelection()[0];
if (selection) {
store.remove(selection);
}
}
}]
}]
});
this.callParent(arguments);
}
});
But I am not sure where to put the code to control the grid row selection and enable the Delete button:
grid.getSelectionModel().on('selectionchange', function(selModel, selections){
grid.down('#delete').setDisabled(selections.length === 0);
});
Also when I press the Add button I get the following error:
Uncaught TypeError: Object [object Object] has no method 'insert'.
Any help would be appreciated.
You are having scoping issues. Basically the variable store is defined only in the initComponent function and therefore of local function scope.
Your handler function has it's own scope. It is firing in the scope of the toolbar button. So if you say this in the handler it would refer to the button. Hence you can say this.up('panel').store - and that gives you the correct reference to the store backing your grid panel.
Another advice is not to implement everything at once. Write a little bit to see if it works and then add to it little by little.
RE: the docs examples, I agree that it's frustrating, but there's not many options. Having a fully-MVC-style implementation of each example would not only be onerous to produce, but would also probably make point of the example get lost in the structure.
RE: your question about the where to "put" the code to control the grid, I would recommend setting up a controller with listeners for the events on the grid in the control() section. This will let you decouple the handling of the events that are fired by your grid from the view itself.

Sencha touch 2 filterby() not updating records

I have a nested list on one of the pages of a Tabbed Panel app that is pulling data from "offices.json"
I should like to be able to filter this list when a user clicks on a toolbar button. However my filterBy() function doesn't update the store and the list of offices I can see, even though I can see in the console it is iterating the records and finding a match. What am I doing wrong?
(And yes I have tried doing s.load() both before and after the filterBy to no avail!)
toolbar:{
items:[{
text: 'Near you',
id: 'btnNearYou',
xtype: 'button',
handler: function() {
s = Ext.StoreMgr.get('offices');
s._proxy._url = 'officesFLAT.json';
console.log("trying to filter");
s.filterBy(function(record) {
var search = new RegExp("Altrincham", 'i');
if(record.get('text').match(search)){
console.log("did Match");
return true;
}else {
console.log("didnt Match");
return false;
}
});
s.load();
}
}]
For the record I'm defining my store like so:
store: {
type: 'tree',
model: 'ListItem',
id: 'offices',
defaultRootProperty: 'items',
proxy: {
type: 'ajax',
root: {},
url: 'offices.json',
reader: {
type: 'json',
rootProperty: 'items'
}
}
}
No need to recreate the regex each time, cache it outside.
You can simplify the code a lot (see below).
Why are you calling load directly after? That's going to send it to the server and it will just retrieve the same dataset.
toolbar: {
items: [{
text: 'Near you',
id: 'btnNearYou',
xtype: 'button',
handler: function() {
s = Ext.StoreMgr.get('offices');
s._proxy._url = 'officesFLAT.json';
var search = /Altrincham/i;
s.filterBy(function(record) {
return !!record.get('text').match(search);
});
}
}]
}