Different behavior of ExtJS application in debug and minified mode - javascript

I'm facing an strange behavior in an web application I'm currently working on. The interface is totally built with ExtJs 4. The application has two modes, Debug and Production.
In Debug mode, when user click a menu item, I load synchronously, the dependent Javascripts file. Something like this:
for ( var i = 0; i < config.dependency.length; i++ ) {
var element = document.createElement('script');
element.onload = callback;
element.onreadystatechange = function () {
if ( element.readyState == 'loaded' || element.readyState == 'complete' ) {
callback();
}
};
}
One of the module's javascript file is like this:
module.js
Ext.define('Company.view.system.Module', {
extend: 'Company.view.abstract.Panel',
alias: 'widget.system.module',
/**
* These "_items" are built into the Object in `Company.view.abstract.Panel`
* using: Ext.create(this._items[i].clazz, conf);
*
* I'm just omitting the whole business logic there
*/
_items: [{
flex: 2,
clazz: 'Company.view.system.module.Form'
}, {
flex: 5,
clazz: 'Company.view.system.module.HtmlEditor'
}]
});
Ext.define('Company.view.system.module.Form', {
extend: 'Company.view.abstract.Form',
alias: 'widget.system.module.form',
items: [{
xtype: 'fieldset',
title: 'Module Grid',
items: [{
xtype: 'system.module.grid'
}]
}]
});
Ext.define('Company.view.system.module.Grid', {
extend: 'Company.view.abstract.Grid',
alias: 'widget.system.module.grid',
columns: [{
...
}],
afterLayout: function() {
this.callParent(arguments);
alert('after layout');
}
});
Ext.define('Company.view.system.module.HtmlEditor', {
extend: 'Company.view.abstract.HtmlEditor',
alias: 'widget.system.module.htmleditor',
...
});
Everything's working as expected in Debug mode. But in Production mode, I load the whole Modules as a single generated-minified-obfuscated javascript file (modules.js) at start up (i.e. before the ViewPort is rendered), instead of loading dependent modules after menu click event.
In Production mode, every Items, which is instantiated using "xtype" (Company.view.system.module.Grid in the above sample), is not rendered at all!
Screenshots of Debug mode and Production Mode.
What do you think is going on here which I'm missing?
Update:
The problem lies with the Height of the GridPanel, as It was computed at runtime, from the browser's screen size. Hence when the component being instantiated, the Height was not computed yet! Silly mistake :)

I would try moving the system.module.grid definition before it's being used in the system.module.form.

I would advise from having two different versions. What's your reason for that?

Related

Upgrading ExtJS in old ASP.NET application from 2.3 to 6

Looking for some assistance. TLDR version: we have an ASP.NET web app that leverages ExtJS 2.3 and we are looking to upgrade to the current ExtJS version. Trying to get my head around what we’re in for.
Now for the details. I will preface by saying that I am not an expert in ExtJS nor .NET development. In fact, I’m a novice pretty much across the board when it comes to web development, so please excuse any poor explanations or misuse of terms on my part. My team is developing a web app on a “custom” framework that was developed a number of years ago at our company. It’s based on some re-runnable code generation tools that take xml templates and spit out the necessary code files. Our project is an ASP.NET MVP application that uses .aspx pages and NHibernate for ORM. Our UI is created from ExtJS—the controls are defined in each page’s .js file and then “assembled” in the .aspx page. The codebehind contains web methods that leverage the presenter of the C# code. I’ve included a snippet to demonstrate what I’m talking about below.
.aspx page:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Entity.aspx.cs" Inherits="View.Example.EntityView" MasterPageFile="~/MasterPages/Content.Master" %>
<asp:Content ID="Content1" runat="server">
<script language="javascript" type="text/javascript" src="~/Scripts/ext-2.2.1/ext-all.js"></script>
<script language="javascript" type="text/javascript" src="<%=ResolveUrl("~/Scripts/Factory/Example/Entity.js")%>"></script>
<script language="javascript" type="text/javascript">
var localConfig = new panelConfig();
localConfig.applyExtendedConfig('default_page');
localConfig.addItem(new Ext.grid.GridPanel(pageConfigs.default_page_ManageEntity));
localConfig.addItem(
new Ext.form.Hidden({
id: 'ManageEntityGrid_Rows'
}));
var default_page = localConfig.createExt();
default_page.on('render', default_page_OnShow, default_page, { single: true });
</script>
</asp:Content>
.js file:
var get_manageEntity_columns = function() {
var columns = [
{ header: "Name"
,id: 'ManageEntity-col-Name'
, dataIndex: 'Name'
, sortable: true
},
{ id: 'ManageEntity-col-ActiveFlag'
, header: 'Active Flag'
, dataIndex: 'ActiveFlag'
, hidden: true
,tags: []
, sortable: true
},
{ id: 'ManageEntity-col-CreatedTimestamp'
, header: 'Created Timestamp'
, dataIndex: 'CreatedTimestamp'
, hidden: true
,tags: []
, renderer : formattedDateTime
, sortable: true
},
{ id: 'ManageEntity-col-Id'
, header: 'Entity ID'
, dataIndex: 'Id'
, hidden: true
,tags: []
, sortable: true
}
];
return columns;
}
var get_grid_reader_manageEntity = function(custom_fields) {
var fields = [
{ name: 'ActiveFlag', mapping: 'ActiveFlag' },
{ name: 'CreatedTimestamp', mapping: 'CreatedTimestamp' },
{ name: 'Id', mapping: 'Id' },
{ name: 'Name', mapping: 'Name' }
];
if (custom_fields) {
fields = fields.concat(custom_fields);
}
return new Ext.data.JsonReader({
root: 'Results',
totalProperty: 'Total',
id: 'Id'
}, fields);
}
var get_grid_datastore_manageEntity = function() {
var store = new Ext.data.Store({
proxy: new Ext.data.PageMethodProxy({
pageMethod: 'GetManageEntity'
}),
reader: get_grid_reader_manageEntity()
, remoteSort: true
});
store.loadOrReload = function() {
if (store.rapidLoaded)
store.reload();
else
{
store.rapidLoaded = true;
store.load({ params: { start: 0, limit: gPageSize }
});
}
}
get_grid_datastore_manageEntity = function() { return store; };
return store;
}
var pageConfigs = {
default_page_ManageEntity: {
store: get_grid_datastore_manageEntity(),
columns: get_manageEntity_columns(),
viewConfig: {
forceFit: true
},
sm: get_manageEntity_sm(),
layout:'fit',
frame: true,
id: 'ManageEntity',
plugins: [
grid_filters_manageEntity
],
iconCls: 'icon-grid',
loadMask: true,
stripeRows: true,
bbar: get_grid_paging_toolbar_manageEntity(),
listeners: {
rowcontextmenu: show_grid_menu_manageEntity
,bodyscroll: function() {
var menu = get_grid_menu_manageEntity();
if (menu.isVisible()) menu.hide();
}
,headerClick: function() {
this.getStore().on('beforeload', this.saveState, this, { single: true });
}
,render: function(){
var grid = this;
Ext.onReady(function() {
add_applied_filters(grid);
var grid_state = Ext.state.Manager.get('ManageEntity') || {};
if (!grid_state.default_filter_applied) {
var filters = grid_filters_manageEntity;
var activeflag_filter = filters.getFilter("ActiveFlag");
activeflag_filter.setValue(["", new Array("1")]);
activeflag_filter.setActive(true);
grid.on('beforestatesave', function(grid, state) { state.default_filter_applied = true; });
}
grid.getStore().load({ params: { start: 0, limit: gPageSize }
});
});
}
}
}}
.aspx.cs file:
[WebMethod()]
public static ExtJSGridData GetManageEntity(PageProxyArgs args)
{
var watch = new Stopwatch();
watch.Start();
try
{
var data = new ExtJSGridData();
var criteria = GetManageEntityQuery(args);
criteria.SetFirstResult(args.Start).SetMaxResults(args.Limit);
data.Results = GetDataManageEntity(args.RecordId, criteria);
criteria.SetFirstResult(0).SetMaxResults(RowSelection.NoValue);
criteria.ClearOrders();
data.Total = criteria.SetProjection(Projections.CountDistinct("Id")).UniqueResult<int>();
data.UserUiStateSaved = UserUiStateHelper.SaveUserUiStateInTransaction(args.UserUiState);
watch.Stop();
PageLogHelper.CurrentLog.ServerTime = watch.ElapsedMilliseconds;
return data;
}
catch (Exception ex)
{
LogManager.GetLogger((MethodBase.GetCurrentMethod().DeclaringType)).Error(ex);
ErrorHandler.LogError(ex);
throw;
}
}
private static IList GetDataManageEntity(int id, ICriteria criteria)
{
var list = criteria.List<Model.BusinessObjects.Entity>();
var jsonList = Model.BusinessObjects.Entity.ToJSON(list);
return jsonList;
}
private static ICriteria GetManageEntityQuery(PageProxyArgs args)
{
ICriteria criteria = StaticPresenter.GetEntity();
var helper = new GridFilterHelper(criteria, args, _dManageEntityLookupSortInfo);
helper.ApplyFilterMap(EntityJSON.GetGridFilterMap(criteria, args.Filters));
MapManageEntityFilters(args.Filters, criteria);
helper.ApplyFilters();
if (args.SortInfo == null || string.IsNullOrEmpty(args.SortInfo.FieldName))
return criteria;
IList<IProjection> sortMap = StaticPresenter.GetSortMap_ManageEntity(args.SortInfo.FieldName, args.RecordId, args.ExtraParams, criteria);
if (sortMap == null)
sortMap = EntityJSON.GetSortMap(args.SortInfo.FieldName, criteria);
helper.ApplySort(sortMap);
return criteria;
}
So, here is where the question comes in. As mentioned, the version of ExtJS we’re using is 2.3, and we’re looking to upgrade to the current version. I’ve done some initial homework of googling and looking through the sencha documentation, but there are some things which I’m unclear on and would like to get addressed before I start getting hands on with this effort. I’ve tried to outline my specific questions below.
First and foremost: Is the way our application is built even possible with ExtJS 6? By this, I mean leveraging the ExtJS API to define controls in the .js file and then create a UI on top of a .NET C# backbone. Based on the change notes and questions from other users, it’s pretty apparent that there have been massive (understatement) changes between 2.3 and 6. I guess what I’m getting at is that based on what I’ve read it seems you can now build your entire app, including the model and view (and controller?) in ExtJS. Is this a requirement, or can we still lay ExtJS controls on top of our .NET C# model and view?
As a follow up, I’ve been seeing references about Sencha CMD to create and build the app etc. Is cmd going to be required no matter what? Or can we simply reference the ext js library like we’re currently doing?
Assuming the answer to question 1 is yes it’s possible, the next obvious question becomes: how much work is this going to be? Let’s get the “a lot” answer out of the way—I know. What I do know is that we will have to update all of our templates to use the new API syntax (new Ext… to Ext.create() etc). I’m okay with this. What I’m trying to figure out is what I don’t know. Assuming I update all of the syntax, would our application work? Or are there other things I need to change/fix in order to get it working?
Related to question 2: based on my reading it looks like the way data stores for controls has changed and they now use the model defined in ExtJS. Is this a requirement? As described earlier, we’re currently using web methods in the aspx.cs file. Am I going to need to duplicate our C# model in ExtJS?
Lastly, I see this asked a lot but I can’t seem to find a definitive answer. Classic vs modern? The answer I typically see is that modern is aimed more towards touch screens and modern browsers, while classic is more geared toward desktop users. I’ve also read in places that modern has fewer controls available. Our web app is running in a local environment and will not be going to mobile in the future, which leads me to think classic might be the right choice? I guess I’m just wondering technically what the difference is.
I’m sure there are things I don’t even know I’m missing. Any and all feedback is welcome.
It is possible, but you will have to do a lot handwriting. Just three weeks ago I had to leverage a 3.4 ASP to 6.2.1
You can either set the variables to a global variable and on start add these to the mainView ViewModel or load them right away onBeforeLaunch.
Then code your app and build it using Sencha CMD. At the end add all together in your ASP stuff.
About how much work ... depends a lot on how structured your code is, how easy it will be to rewrite the code.
Let's pretend it is written in the same style all over the application, then it will be relatively easy.

ExtJS error in initial page load due to Ext.getBody() not yet being defined

I'm trying to create a dialog window in ExtJS to perform a save function, but I'm getting problems loading the page.
A (reduced) example of the code window definition is:
Ext.define('MyRequest.SaveDraftOrTemplateWindow', {
extend: 'Ext.window.Window',
alias: 'widget.saveDraftOrTemplateWindow',
requires: ['Ext.toolbar.Toolbar'],
modal: true,
initComponent: function() {
this.items = [ saveDraftOrTemplateForm ];
Ext.apply(this, {
dockedItems: [{
xtype: 'toolbar',
items: [
{
iconCls: 'saveas-draft',
text: '<b>Save</b>',
id: 'saveDraftTemplate',
handler: saveAsDraftRequest(textFieldDraftOrTemplateName.getValue(), checkBoxSaveAsTemplate.getValue()),
scope: this
}
]
}]
});
this.callParent();
}
});
function saveAsDraftRequest(draftName, isTemplate) {
Ext.getBody().mask('Saving draft request...'); // Errors actually occurs on this line
}
// This line is the start of the stack causing the problem...
var saveDraftOrTemplateWindowInstance = Ext.create('MyRequest.SaveDraftOrTemplateWindow', {
Id: 'saveDraftOrTemplateWindow',
xtype: 'saveDraftOrTemplateWindow',
width: 400,
height: 180,
bodyPadding: 0
});
The problem is that is seems to be 'calling' the saveAsDraftRequest() function when the page initially loads which gives the Javascript error "Uncaught TypeError: Cannot read property 'mask' of null", and prevents the page loading. I don't really understand why the function is getting called at this point, as the handler presumably shouldn't be called until the button is actually clicked.
I assume that if the page were already correctly loaded then Ext.getBody() would correctly return a result instead of null, but why is this getting called during the initial page load?
You are invoking saveAsDraftRequest function in initComponent in line:
handler: saveAsDraftRequest(textFieldDraftOrTemplateName.getValue(), checkBoxSaveAsTemplate.getValue())
You should change it to
handler: saveAsDraftRequest
Then you need resolve draftName and isTemplate in handler. You can for example assign them to button:
handler: saveAsDraftRequest,
draftName: textFieldDraftOrTemplateName.getValue(),
isTemplate: checkBoxSaveAsTemplate.getValue()
Then you can access them in handler like so:
function saveAsDraftRequest(sender) {
console.log(sender.draftName);
console.log(sender.isTemplate);
}
Ah, #Lolo has given me the hint I need - I see now that the initialisation code was invoking the function to get the handler to use - what I could have done is:
handler: function() {
saveAsDraftRequest(textFieldDraftOrTemplateName.getValue(), checkBoxSaveAsTemplate.getValue());
},
... if I wanted to invoke it there.

Sencha Touch 2.3.1 - onTap() record parameter returns empty object

I have a simple Sencha App that has a main view. The view extends the Ext.navigation.View so that I can "push" to a new view when the user selects an item in the list. This happens by setting up a listener and then calling the push function on the MainView object.
However, I'm having problems getting the data across to that view. I tried using the answer from this StackOverflow question, but it didn't work.
In that answer it suggests that you use the record parameter of the itemTap() function, but this returns as an empty object.
Why does record return as an empty object?
Perhaps I'm going about this the wrong way?
In my case, I have a list of "brands", each with a title, image and description. I'd like to use that in the panel that slides in.
The launch function of my app which creates the view and ads to the viewport
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Create instance of the main view so we can use it's functions
SenchaTest.MainView = Ext.create('SenchaTest.view.Main');
// Initialize the main view
Ext.Viewport.add(SenchaTest.MainView);
},
Here is my view
Ext.define('SenchaTest.view.Main', {
extend: 'Ext.navigation.View',
xtype: 'main',
requires: [
'Ext.TitleBar',
'Ext.Video',
'Ext.carousel.Carousel',
'Ext.Img'
],
config: {
fullscreen: true,
items: [
{
title: 'Test',
layout: {
type: 'vbox',
align: 'stretch'
},
items: [{
xtype: 'highlightscarousel',
flex: 0.35
}, {
xtype: 'list',
displayField: 'title',
flex: 0.65,
store: Ext.create('SenchaTest.store.Brands'),
itemTpl: '<img src="{image}" class="listThumb"><h1 class="listTitle">{name}</h1><span class="clearFloat"></span>',
listeners: {
itemtap: function(nestedList, list, index, element, post, record) {
}
}
}]
}
]
}
});
Based on the Sencha Touch docs, the signature of the itemtap listener is:
(this, index, target, record, e, eOpts)
you're using:
(nestedList, list, index, element, post, record)
so that might be why the record is an empty object. If that's not the case, could you post a JSFiddle or some kind of working example of the problem?

Is there an example of setting and retrieving settings from a Rally SDK 2 app?

What does a settings object look like? I can't seem to updateSettings with anything and get something back interesting. I'm printing out this.settings and every time I refresh, it just logs a prototype object with no values.
This is what my test app looks like. I am putting it into a panel inside Rally, not running remotely.
<script type="text/javascript" src="/apps/2.0p2/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
/*global console, Ext */
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
//Write app code here
console.log( "settings", this.settings );
this.updateSettings( { Name: 'test', Value: Ext.JSON.encode( { test: "blah" } ) } );
}
});
Rally.launchApp('CustomApp', {
name: 'test'
});
});
</script>
Turns out there is a bug in the preview version I was using. And I was trying to pass the wrong kind of preference. Note that preferences are scoped to the App ID and not to the project or workspace. Since it needs the app's ID, it doesn't work when run outside Rally.
The bug is that the updateSettings function is missing a line. You can easily override this by adding the same function to your app definition (isn't it neat that the source is included in the docs?) Just make a function like this:
updateSettings: function(options){
Rally.data.PreferenceManager.updateAppPreferences({
appID: this.getContext().get('appID'),
settings: options.settings,
success: function(updatedSettings){
Ext.apply(this.settings, updatedSettings);
if(options.success){
options.success.call(options.scope);
}
},
scope: this
});
}
So, then, the preference object should be passed like this:
this.updateSettings( {settings: { test: "blah" ) } } );
Then, when it comes back, the getSetting("test") will give me "blah". (It creates a preference with Name equal to "test", Value equal to "blah" and an AppId equal to the current app.

How to add a toolbar to a viewport?

I'm trying to add a toolbar to a viewport, but when trying to accomplish this with the code below it doesn't appear at all (only tab panel is shown).
Ext.define(CONFIG.APP_NS+'.view.Viewport', {
extend: 'Ext.container.Viewport',
layout: {
type: 'border'
},
this.dockedItems = [
{
xtype: 'maintoolbar'
}
],
this.items = [
{
region: 'center',
xtype: 'maintabpanel'
}
];
});
// MainToolbar
Ext.define(CONFIG.APP_NS+'.view.MainToolbar', {
extend: 'Ext.toolbar.Toolbar',
alias: 'widget.maintoolbar',
initComponent: function () {
this.items = [
// <...>
]
}
});
I know I could add it to north region, but then it appears with border and border: false does nothing.
What am I doing wrong?
An Ext.container.ViewPort doesn't have a property called dockedItems, only an Ext.panel.Panel has that. That's why your toolbar isn't showing, its being ignored completely because the viewport doesn't know what to do with dockedItems.
I would put the toolbar in the north region like you suggested.
The border: false config doesn't work in the toolbar at the moment, and it is a known bug. It might be worth posting a help article on the Sencha forum where you will get some assistance from the ExtJS team.

Categories

Resources