In my application all component's titles/texts are localized based on store loaded before Application launch. In application i have button that changes store url and reloads the store to switch language. The problem is that all the classess are already loaded so components are rendered with previous locale. Here is the code of the button:
tbar: [{
xtype: 'button',
id: 'btn-test',
text: 'xxx',
handler: function() {
lang = 'en';
i18n.getBundlestore().load({url:'/GSIP/resources/gsip/i18n/bundle-' + lang + '.properties'});
//bun = Ext.create('I18N.ResourceBundle');
Ext.getCmp('mainview').destroy();
Ext.create('Ext.container.Viewport', {
id: 'mainview',
layout: 'border',
items: [
{
xtype: 'gsip_mainpanel',
region: 'center',
items: [{
xtype: 'gsip_categoriestabpanel'
}]
}
]
The exact same viewport creation is in my Application.js. lang and i18n are global variables. Old viewport is destroyed and new is created but how to force to reload classess. I dont want to use window.location.
Code updated:
handler: function() {
lang = 'en';
Ext.getCmp('mainview').destroy();
i18n.getBundlestore().load({url:'/GSIP/resources/gsip/i18n/bundle-' + lang + '.properties',
callback: function() {
Ext.create('Ext.container.Viewport', {
id: 'mainview',
layout: 'border',
items: [
{
xtype: 'gsip_mainpanel',
region: 'center',
items: [{
xtype: 'gsip_categoriestabpanel'
}]
}
]
});
}
});
}
CategoriesTabPanel:
Ext.define('GSIP.view.CategoriesTabPanel' ,{
extend: 'Ext.tab.Panel',
alias : 'widget.gsip_categoriestabpanel',
layout: 'fit',
items: [{
xtype: 'gsip_planytabpanel',
title: i18n.getMsg('key-1')
},{
xtype: 'gsip_adresytabpanel',
title: i18n.getMsg('key-2')
}],
initComponent: function() {
this.callParent(arguments);
}
});
and ResourceBundle (i18n variable is an instance of this class):
Ext.define('I18N.ResourceModel',{
extend: 'Ext.data.Model',
fields: ['key', 'value']
});
Ext.define('I18N.ResourceStore',{
extend: 'GSIP.core.RegisteredStore',
model: 'I18N.ResourceModel',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/GSIP/resources/gsip/i18n/bundle-' + lang + '.properties',
reader: {
type: 'json',
root: 'pl',
successProperty: 'success'
}
}
});
Ext.define('I18N.ResourceBundle' ,{
config: {
bundlestore: Ext.create('I18N.ResourceStore'),
},
constructor: function(config) {
this.initConfig(config);
return this;
},
getMsg: function(key) {
return this.bundlestore.getAt(this.bundlestore.findExact('key', key)).get('value');
}
},function(){
//callback function, called before store load :(
}
);
Within the definition of widget.gsip_categoriestabpanel you set items as a config. This means it will always reference the same object (and not the updated one). As first step, you should move the items definition to initComponent, there you can also console.log(i18n) to see it's the right one.
Related
I found an answer related to Revision History "Querying for User Story revisions in Rally"
I am having trouble determining how to populate a grid with it.
Can I use the model and populate a story that the gird references?
Here is a working example, using other examples.
I had to populate an array with revision history info and add it to a story.
Then the story populated the grid.
// Also referenced
// https://stackoverflow.com/questions/22334745/does-rally-data-custom-store-have-magic-uniqueness
//
Ext.define('CustomApp',
{
extend: 'Rally.app.App',
componentCls: 'app',
launch: function()
{
var panel = Ext.create('Ext.panel.Panel',
{
layout: 'hbox',
itemId: 'parentPanel',
componentCls: 'panel',
items: [
{
xtype: 'panel',
title: 'Artifacts updated in the last two days',
width: 600,
itemId: 'childPanel1'
},
{
xtype: 'panel',
title: 'Last Revision',
width: 600,
itemId: 'childPanel2'
}]
});
this.add(panel);
var artifacts = Ext.create('Rally.data.wsapi.artifact.Store',
{
models: ['UserStory','Defect', 'TestCase'],
fetch: ['Owner', 'FormattedID','Name','ScheduleState','RevisionHistory','Revisions','Description','CreationDate','User'],
autoLoad: true,
listeners:
{
load: this._onDataLoaded,
scope: this
}
});
},
_onDataLoaded: function(store, data)
{
this._customRecords = [];
_.each(data, function(artifact, index)
{
this._customRecords.push(
{
_ref: artifact.get('_ref'),
FormattedID: artifact.get('FormattedID'),
Name: artifact.get('Name'),
RevisionID: Rally.util.Ref.getOidFromRef(artifact.get('RevisionHistory')),
RevisionNumber: 'not loaded'
});
}, this);
this._createGrid(store,data);
},
_createGrid: function(store,data)
{
var that = this;
var g = Ext.create('Rally.ui.grid.Grid',
{
itemId: 'g',
store: store,
enableEditing: false,
showRowActionsColumn: false,
columnCfgs:
[{text: 'Formatted ID', dataIndex: 'FormattedID'},
{text: 'Name', dataIndex: 'Name'},
{text: 'ScheduleState', dataIndex: 'ScheduleState'},
{text: 'Last Revision',
renderer: function (v, m, r)
{
var id = Ext.id();
Ext.defer(function ()
{
Ext.widget('button',
{
renderTo: id,
text: 'see',
width: 50,
handler: function ()
{
that._getRevisionHistory(data, r.data);
}
});
}, 50);
return Ext.String.format('<div id="{0}"></div>', id);
}
}], height: 400,
});
this.down('#childPanel1').add(g);
},
_getRevisionHistory: function(artifactList, artifact)
{
this._artifact = artifact;
this._revisionModel = Rally.data.ModelFactory.getModel(
{
type: 'RevisionHistory',
scope: this,
success: this._onModelCreated
});
},
_onModelCreated: function(model)
{
model.load(Rally.util.Ref.getOidFromRef(this._artifact.RevisionHistory._ref),
{
scope: this,
success: this._onModelLoaded
});
},
_onModelLoaded: function(record, operation)
{
var list = [];
record.getCollection('Revisions').load(
{
fetch: true,
scope: this,
callback: function(revisions, operation, success)
{
_.each(revisions, function(artifact, index)
{
var creationdate;
if (Rally.environment.useSystemTimezone || Rally.environment.useWorkspaceTimeZone)
{
creationdate = Rally.util.DateTime.formatDate(artifact.data.CreationDate, true);
}
else
{
creationdate = Rally.util.DateTime.formatWithDefaultDateTime(artifact.data.CreationDate);
}
var nodedata =
{
rev_num: artifact.data.RevisionNumber,
descript: artifact.data.Description,
author: artifact.data.User._refObjectName,
creationdate: creationdate
};
if(nodedata.descript.indexOf('SCHEDULE STATE') > -1)
{
list.push(nodedata);
}
else
{
if(nodedata.descript .indexOf('PLAN ESTIMATE') > -1)
{
list.push(nodedata);
}
}
}, this);
var myStore = Ext.create("Rally.data.custom.Store",
{
autoLoad: true,
data : list,
});
var revGrid = Ext.create('Rally.ui.grid.Grid',
{
itemId: 'revGrid ',
store: myStore,
enableEditing: false,
showRowActionsColumn: false,
height: 400,
columnCfgs:
[
{text: 'Rev #', dataIndex: 'rev_num'},
{text: 'Description', dataIndex: 'descript'},
{text: 'Author', dataIndex: 'author'},
{text: 'Change Date', dataIndex: 'creationdate'}
]
});
this.down('#childPanel2').add(revGrid);
}
});
},
});
I'm trying to create custom property values (based on a condition of a function) for my Ext objects, instead of specifying just a value.
Example 1:
old code (working)
this.buttons = [
{
text: 'Save',
new code (not working)
this.buttons = [
{
text: function() {
return 'Save X';
},
Example 2:
old code (working)
}, {
width: 270,
labelAlign: 'right',
xtype: 'textfield',
name: 'user_id',
fieldLabel: 'User ID',
hidden: true
}]
new code (not working)
}, {
width: 270,
labelAlign: 'right',
xtype: 'textfield',
name: 'user_id',
fieldLabel: 'User ID',
hidden: function() { return true; }
}]
Example 3:
Ignore entire textfield object (lazy instance) completely based on a condition:
}, {
width: 270,
labelAlign: 'right',
xtype: 'textfield',
name: 'employee_number',
fieldLabel: 'Employee Number'
}]
You simply can't do it this way. It is not possible to replace a type with a function. In your case you assign a function reference to a variable which is expected to be boolean, same for the string.
Solution A.
You should consider to write yourself a field factory. Within that factory you can then execute any function before assigning configs. (Sort of same then B but can be used to reduce function calls)
Solution B.
Use a function reference itself. This one should then get executed. (spare the requirement of class extension and is over that reuseable)
// The data store containing the list of states
var states = Ext.create('Ext.data.Store', {
fields: ['abbr', 'name'],
data : [
{"abbr":"AL", "name":"Alabama"},
{"abbr":"AK", "name":"Alaska"},
{"abbr":"AZ", "name":"Arizona"}
//...
]
});
Ext.namespace('my.util.helper');
my.util.helper.decideHide = function() { return true; }
// Create the combo box, attached to the states data store
Ext.create('Ext.container.Container', {
renderTo: Ext.getBody(),
items: [{
xtype: 'combo',
fieldLabel: 'Choose State',
store: states,
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
test: my.util.helper.decideHide(),
listeners: {
afterrender: function(n) {
alert(n.test);
}
}
}]
});
Solution C.
And the solution I use most in such cases are simplified if else statements
// ... // more code
{
text: myCondition ? 'Text A' : 'Text B',
// more code
}
// ... // more code
Yeah that is not going to work, some Ext configs take a function that will be evaluated but most of them don't. Instead of creating anonymous functions and not invoking them I would do something like this:
Ext.define('UserPanel', {
extend : 'Ext.panel.Panel',
initComponent : function() {
this.items = [{
xtype : 'button',
text : this._getSaveButtonText()
}, {
width : 270,
labelAlign : 'right',
xtype : 'textfield',
name : 'user_id',
fieldLabel : 'User ID',
hidden : this._isUserIdHidden()
}]
this.callParent();
},
_getSaveButtonText : function() {
return 'Save';
},
_isUserIdHidden : function() {
return true;
}
});
I have a class called Zone1s in java which has 2 fields text(name of zone) and list of Zone1s.
when i convert it to json i get following response :
{"text":"Papa","Zone1s":[{"text":"Beta1","Zone1s":[{"text":"BetaBeta1","Zone1s":[]},{"text":"BetaBeta2","Zone1s":[]}]},{"text":"Beta2","Zone1s":[]}]}
i wrote a Extjs model,store and panel below:
Ext.define('Zone1s', {
extend: 'Ext.data.Model',
fields: [
{ name: 'text', type: 'string' }
],
proxy: {
type: 'ajax',
url : 'test.htm',
reader: {
type : 'json',
record: 'Zone1s'
}
},
hasMany: {model: 'Zone1s', name: 'Zone1s'},
belongsTo: 'Zone1s'
});
var store =Ext.create('Ext.data.Store', {
model: 'Zone1s',
autoLoad: true
});
Ext.create('Ext.tree.Panel', {
title: 'Simple Tree',
width: 200,
height: 150,
store: store,
renderTo: Ext.getBody()
});
i am getting following error:
me.store.getRootNode is not a function...
Can anyone please Guide me where i am wrong ?
i have gone through
How do I show nested data into a tree?
but here my Zone1s can have Zone1s in themselves that's the difference.
You should add a root attribute to your Store :
var store =Ext.create('Ext.data.Store', {
model: 'Zone1s',
autoLoad: true,
root: {
text: 'Zone1s',
id: 'Zone1s',
expanded: true
}
});
If you do not want to see the root node, use the rootVisible attribute :
Ext.create('Ext.tree.Panel', {
title: 'Simple Tree',
width: 200,
height: 150,
store: store,
rootVisible : false,
renderTo: Ext.getBody()
});
Please help me. how can I get user input.
Mytest.views.Forma = Ext.extend(Ext.Panel, {/*This is a panel which displays all*/
initComponent: function(){
Ext.apply(this, {/*derive the form*/
items: [ {
xtype: 'fieldset',
id: 'formaFieldset',
title: '',
items: [
{
name: 'from',
label: 'From'
}
]
},
{
xtype: 'button',
cls: 'btnAction',
text:'Price Check',
handler:function(){
//Here you need to print the values of form fields
}
});
}
} ]
});
Mytest.views.Forma.superclass.initComponent.call(this);
}
});
Ext.reg('forma', Mytest.views.Forma);
You can use getValues() function to obtain the values in the form field.
I am starting to use Sencha Touch and have already read their "Getting Started" gide, however I am currently stuck in what I want to do and haven't been able to find any proper tutorial or example of what I need.
I want to make a panel so that when a user clicks on a specific button the panel slides and the toolbar on top disappears (or slides as well) and a new one appear just as it would happen on a native iOS app.
Here's my Sencha code so far:
Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function() {
/*HANDLERS
*********************************************************************************/
var showAlert = function(btn, event) {
Ext.Msg.alert('Title', 'Diste ' + event.type + ' en el botón "' + btn.text + '"', Ext.emptyFn);
};
var tapHandler = function(button, event) {
};
/*BUTTONS
*********************************************************************************/
var aboutAppBtn = [{
text: 'Sobre App',
ui: 'round',
handler: showAlert
}];
var checkInBtn = [{
text: 'Check-in',
ui: 'forward',
handler: tapHandler
}];
var buscarCercaBtn = [{
text: 'Buscar local...',
ui: 'button',
handler: showAlert
}];
var buttonsGroup1 = [{
text: 'Sobre App',
ui: 'round',
handler: showAlert
}, {
text: 'Check-in',
ui: 'forward',
handler: tapHandler
}];
/*PHONE || SCREEN
**********************************************************************************/
if (Ext.is.Phone) {// Phone has far less screen real-estate
var dockedItems = [{
xtype: 'toolbar',
dock : 'top',
ui: 'light',
title: 'My Toolbar',
items: buttonsGroup1
}];
}else{
//var dockedItems = [topTB];
aboutAppBtn.push({xtype: 'spacer'});
var dockedItems = [{
xtype: 'toolbar',
dock : 'top',
ui: 'light',
title: 'My Toolbar',
items: aboutAppBtn.concat(checkInBtn)
},{
xtype: 'button',
dock: 'bottom',
ui: 'action',
text: 'Buscar local...',
handler: showAlert
}];
}
var green = {
style: 'background-color:#3b7E00; color:white;',
title: 'Green',
html: 'Green'
};
var blue = {
style: 'background-color:#0F0; color:white;',
title: 'Blue',
html: 'Blue'
};
/*PANELS
**********************************************************************************/
var mainPanel = new Ext.Panel({
dockedItems: dockedItems,
layout: 'card',
cardSwitchAnimation: {type: 'flip', duration: 500},
fullscreen : true,
items: [green, blue]
});
}
});
To make the card transition when you click a button use the setActiveItem method in your handler:
var tapHandler = function(button, event) {
mainPanel.setActiveItem(1);
};
It can also take a reference to the panel component directly (which is useful if you ever change the order of the cards and the indices change).
Your toolbar is docked to the outer container, not to the cards, so it won't change when you change cards. You could dock two different toolbars to the card panels instead if you wanted it to change (or alter it programmatically, I suppose).
Also you can use the 'spacer' type to spread your buttons apart to each side of the tool. Here is your code adjusted to do what I think you probably want (on phone only, for clarity)
Ext.setup({
onReady: function() {
/*HANDLERS
*********************************************************************************/
var showAlert = function(btn, event) {
Ext.Msg.alert('Title', 'Diste ' + event.type + ' en el botón "' + btn.text + '"', Ext.emptyFn);
};
var tapHandler = function(button, event) {
mainPanel.setActiveItem(blue, {type: 'slide'});
};
var backHandler = function(button, event) {
mainPanel.setActiveItem(green, {type: 'slide', direction: 'right'});
};
/*UI
*********************************************************************************/
var green = new Ext.Panel({
dockedItems: [{
xtype: 'toolbar',
ui: 'light',
title: 'My Toolbar',
items: [{
text: 'Sobre App',
ui: 'round',
handler: showAlert
}, { xtype:'spacer'}, {
text: 'Check-in',
ui: 'forward',
handler: tapHandler
}]
}],
style: 'background-color:#3b7E3b',
html: 'Green'
});
var blue = new Ext.Panel({
dockedItems: [{
xtype: 'toolbar',
ui: 'light',
title: 'Check-in',
items: [{
text: 'Back',
ui: 'back',
handler: backHandler
}]
}],
style: 'background-color:#3b3b7E',
html: 'Blue'
});
var mainPanel = new Ext.Panel({
layout: 'card',
fullscreen : true,
items: [green, blue]
});
}
});