Sencha - Conditionally adding namesapce in requires - extjs

I have a requirement that I want to add namespaces in requires conditionally.
e.g. In below example I want to add 'views.popupgrid' name space on specific condition. Currently it's always loaded.
requires: ['Ext.window.MessageBox','views.popupgrid','user.MyUser' ]

Conditional dependencies are not supported by the Sencha toolchain. While you would be able to write in a text editor of your choice
requires:[
(location.hash=='#test')?'testpopup':'normalpopup'
]
and this would work in the uncompiled version, Sencha Cmd would not be able to compile it correctly, and would throw errors.
Therefore, Sencha Architect does not support this syntax.
What you can do, while staying Standards-compliant: you can use Ext.Loader.loadScript, e.g. like this:
Ext.define('MyForm',{
extend: 'Ext.form.Panel'
initComponent:function() {
var me = this;
me.callParent(arguments);
if(x==3) Ext.Loader.loadScript({
url:'MyCustomFormComponent.js',
onLoad:function(){
me.add({
xtype:'mycustomformcomponent'
});
})
});
}
})
Please note that in this case you will always have to deliver MyCustomFormComponent.js alongside the minified app.js, because the dependency cannot be resolved by the toolchain. Also, depending on the connection, there may be a visible delay before the resource is loaded and the component is added to the form.
It is usually faster and smoother to always load the dependency, especially if you intend to deliver the app as a single minified javascript file (e.g. using Sencha Cmd).

Related

IntelliJ IDEA / Webstorm and AngularJS / Ionic

I love it when multiple technologies come together to produce a doozy...
The following AngularJS template squawks an error in the IDE ("can't resolve file"). I find the inspection wildly convenient and I don't simply want to turn it off.
/my_project/www/templates/logo.html
...
<img src="img/logo.png"/> <<< file at /my_project/www/img/logo.png
...
Question:
How can we allow an IDE like IntelliJ IDEA or WebStorm to play nice with Ionic/AngularJS/Cordova in this situation?
NOTE: I cannot simply mark the www folder as a "resources root" and use absolute references because ionic needs relative refs...
Or does it? Is there a way to fix this on the cordova side of things to allow absolute refs? i.e., so it doesn't break when deploying to Android (because we need the prefix file://android_asset/www/)
Inspired by this answer, I ended up creating a recursive search/replace script in the build process. I made a cordova hook for "after_prepare" and used node with the replace package. Now I can use absolute refs and get the full benefit of the IDE... and then at build-time they get converted to relative.
Here is a sample hook file to get you started. Don't forget to add refs for css files or things like templateUrl in your app.js if you're using angular/ionic. And of course don't forget to modify the platform specifics to your needs.
#!/usr/bin/env node
var replace = require("replace");
var wwwDir = process.argv[2] + '\\platforms\\android\\assets\\www';
// convert all src and href tags to relative in index.html + components\*
replace({
regex: '(src|href)=([\'"])/+',
replacement: '$1=$2',
paths: [
wwwDir + '\\components',
wwwDir + '\\index.html'
],
recursive: true,
silent: false
});

Sencha AlternateClassName do not work in compiled version

I'm working in a Sencha application.
I've created a couple of Utilities classes as singleton components (helpers, services, etc).
I'm using alternateClassName to have a shorter name for those classes.
It works perfect, but stop working after compiling for production.
I don't know why, and need help to get this working!
Looks to the following example:
I've created a demo application using sencha cmd for simplicity. The application is "Demo".
The whole application is as default, but I've added a util folder inside app, with a single file Helper.js. This is the code:
Ext.define('Demo.util.Helper', {
singleton: true,
alternateClassName: 'Helper',
test: function () {
alert('It works !');
}
});
Then, I just need to update app.js to require this new file, and update the launch function to call test method after add the main view. So here is the code to use in app.js:
requires: [
'Ext.MessageBox',
'Demo.util.Helper'
],
The launch function:
launch: function () {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
Ext.Viewport.add(Ext.create('Demo.view.Main'));
Helper.test();
},
Now, if I try the example, after load the app, an alert msg is shown successfully.
But after compile it using sencha cmd
sencha app build production
I get this error:
I know the problem is with alternate class name, because if I use the full name (instead of alternate class name), it works anyway. But I want to use alternate class name, otherwise it doesn't make any sense.
Any idea on what's wrong with compiled version ?
TIA!
Milton
After some time, we realized that Sencha has a bug when compiles singleton classes for production (works on testing also).
The solution was to remove the singleton flag, and create application variable for all of the singleton classes, in the launch method.
For example:
Demo.Helper = Ext.create('Helper');
Hope this help!
UPDATE
Last version of Sencha Cmd is full of freaking bugs!
I found a lot of other issues after fixing this ones, and finally, I found this link http://www.sencha.com/forum/showthread.php?288972-MyAppName.app-not-working-on-build-production&p=1064635

Trying to understand Ext.require, Ext.class.requires, and Ext.Loader

So I've inherited this extjs 4.1.3 project and I'm trying to understand it.
I've noticed that there are both Ext.require and Ext.define requires EVERYWHERE. The code is made of a lot of boilerplate code from sencha docs and I feel there is a lot of redundancy. It makes a whole lot of clutter and I feel like its wrong that when I add a file, I have to add it more than once (to Ext.require and Ext.define requires).
Couple of questions:
1) How can I tell if a require is actually ... required? From my understanding, it only tells the web page to load something now or later (this might be related to question 3). Am I guaranteed to see warnings from Ext saying "you should include abc" if those files are needed?
2) Is there any difference between Ext.require and Ext.define requires? Do I need both? If I only need one, is one more "standard" than the other?
3) What exactly does "Ext.Loader.setConfig({enabled: true});" do? I am guessing that lets ext dynamically load things if I don't specifically require them. Shouldn't I not need requires at all then? I'm not saying this is good practice, but is it true? Actually, if anything, isn't using this bad practice? You'll end up losing track of dependencies if you don't have them written down. Or do you "trust" Ext.Loader to take care of everything relating to dependencies so that you don't even have to worry about it.
The reason I ask because I thought this was true, but after the below experience, I am thinking it is not.
I thought I figured this out, but apparently my interpretation of Ext.Loader (Question 3) is wrong because if I comment out all of my requires, I get
[07:15:05.577] Error: [Ext.createByAlias] Cannot create an
instance of unrecognized alias: layout.border
If I take out 'Ext.layout.*. How come this isn't loaded dynamically if have Ext.Loader.setConfig({enabled: true})?
TLDR: I don't know when it is safe/good practice to use Ext.require/Ext.define requires. If I don't see any warnings and my app works, does that mean I'm good or is there still a chance something is being "loaded" as well as it could be? And what does Ext.Loader.setConfig({enabled: true}) do?
EDIT: Here is an example: the app.js file. It just feels to wordy doesn't it?
Ext.Loader.setConfig({enabled: true});
Ext.Loader.setPath('Ext.ux', 'ux');
Ext.require([
'Ext.layout.*',
'Ext.ux.*',
'Ext.grid.*',
'APP.controller.Controller',
'APP.view.MapPanel',
'APP.view.FilterPanel',
'APP.view.Viewport'
]);
var start_app = function() {
var app = Ext.application({
name: 'APP',
appFolder: 'app',
requires: [
],
autoCreateViewport: true,
uses: [
'APP.controller.Controller',
'APP.view.MapPanel',
'APP.view.FilterPanel',
'APP.view.Viewport'
],
launch: function() {
},
controllers: [
'APP.controller.Controller'
]
});
}
In the above code you only need controllers:['Controller']. In turn, in the controller file you need views:[], stores:[] and models:[] depending on what you want the controller to pull from the server.
Another example: Let's say you code a grid and it uses number column, so you need requires:['Ext.grid.column.Number' in the grid config.
What I do is that I put there minimum I think is required, and then I watch the console. Either I get an error and I fix it or I get "Synchronous Loading" warning that I also fix.
For more details see: http://www.sencha.com/blog/countdown-to-ext-js-4-dynamic-loading-and-new-class-system

UI testing an ExtJS webapp using CasperJS/PhantomJS

I'm working on UI testing an ExtJS web-app, and I'm a beginner.
I am trying to test the ExtJS widgets by using CasperJS/PhantomJS tool.
Also, I generate the required CasperJs script using Resurrectio and by making necessary changes to it.
Since ExtJs generates unique ids dynamically for the DOM elements that it creates, I want to know how to provide those ids in CasperJs script for testing.
For example, The following Casper Script was generated by Resurrectio:
casper.waitForSelector("#ext-gen1142 .x-tree-icon.x-tree-icon-parent",
function success() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
this.click("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
},
function fail() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
});
casper.waitForSelector("#gridview-1038",
function success() {
test.assertExists("#gridview-1038");
this.click("#gridview-1038");
},
function fail() {
test.assertExists("#gridview-1038");
});
Here #ext-gen1142 and #gridview-1038 are the ids dynamically created. How should one provide data in the tests? Is there any stub or mocking tools which works with ExtJs in the code to provide these ids at runtime during tests?
I came across SinonJS. Can it be used or Do I need to used CSS or XPath Locators as mentioned in this answer? How reliable it is to use CSS or Xpath Locators?
Thanks in advance!
Not so easy to answer this, but here a few thoughts...
Don't rely on generated IDs. Never. They'll change in moments you won't like and if you have luck very much earlier.
Your best friends will probably be pseudo CSS classes you attach to your components. You could also use IDs, but this is only reasonable when you have elements which occur only once in your page. If that is the case, they are very good anchors to start with selections/queries.
XPath with ExtJS is possible, but you have to carefully choose the elements. ExtJS is so verbose in generating little things so your paths can be quite complicated. And when Sencha drops support for problematic browsers (IE < 8) maybe they change their templates and your XPath doesn't find anything.
SinonJS is great. But it won't help you much in DOM problems. But sure you can use it in your tests. I suppose it will payoff most in testing parts of your controllers or non-trivial models.
Model your test components after your real UI components and screen sections. Don't just record a script. Test code should be engineered like production code. If you create reusable components of test code and logic, you don't have to fear changes. In the best case the changes in one component will only touch the testing code of that particular component.
I know you have ExtJS. But take some time to look at AngularJS and see how easy it can be to test all parts of a JavaScript web application. I'm not saying you should switch to AngularJS, but you can learn a lot. Have a look at Deft JS as it has many concepts which enhance testability of ExtJS applications.
I use Siesta for my ExtJs testing. It works amazingly good for all JavaScript (jQuery based and others), but is specifically designed for ExtJS/Sencha Touch.
It has the feature to combine CSSquery and ComponentQuery to select your elements I think that will fix a lot of problems for you.
In the paid version there is even a test recorder to record scenario's and use them for your tests.
Here's a demo
Here's some sample code:
StartTest(function(t) {
t.chain(
{ waitFor : 'CQ', args : 'gridpanel' },
function(next, grids) {
var userGrid = grids[0];
t.willFireNTimes(userGrid.store, 'write', 1);
next();
},
{ waitFor : 'rowsVisible', args : 'gridpanel' },
{ action : 'doubleclick', target : 'gridpanel => .x-grid-cell' },
// waiting for popup window to appear
{ waitFor : 'CQ', args : 'useredit' },
// When using target, >> specifies a Component Query
{ action : 'click', target : '>>field[name=firstname]'},
function(next) {
// Manually clear text field
t.cq1('field[name=firstname]').setValue();
next();
},
{ action : 'type', target : '>>field[name=firstname]', text : 'foo' },
{ action : 'click', target : '>>useredit button[text=Save]'},
function(next) {
t.matchGridCellContent(t.cq1('gridpanel'), 0, 0, 'foo Spencer', 'Updated name found in grid');
}
);
})

How to run code before controllers have been initialized

I'm building a application with Sencha Touch 2
I want to run some code at the moment where Controllers have not been initialized yet but our app requires have already been loaded.
Looking at the Ext.app.Application source code I would really like to intercept the onProfilesLoaded call. But I just don't know how to do it.
Ok, I think I figured it out on my own. Apparently you can use the override functionality to intercept.
Ext.define('MyApp.AppOverrides', {
override: 'Ext.app.Application',
onProfilesLoaded: function(){
alert('Hey Mum, I just intercepted the call!');
this.callParent(arguments);
}
});

Resources