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
Related
In a big application, i now need to access some data (json api call) from asynchronously (before, those data were accessed synchronously).
I would like not to have to change components implementation to now handle this async behaviour (too risky).
I thought about $routeProvider's "resolve" feature (with promises) that helps to abstract this async behaviour out from the components/controllers.
Unfortunately i am absolutely not using routing in any way.
Is there an implementation for that? If not, where could i start?
EDIT:
how i was before (jsonData were not loaded synchronously but it was transparent thanks to systemJS features, SystemJS, Which we are throwing in garbage now, hence the question):
https://plnkr.co/edit/BSreVYNAr7sijYwEpb5G?p=preview
How i am now:
https://plnkr.co/edit/WnX0ynOqkZsmEzIxl1SI?p=preview
Watch the console to see an example of the problems that can occur now.
I kind of made it work by going like that, but i'm not completely satisfied with it (watch the config block):
https://plnkr.co/edit/P9Rv6rnboFlaFZ0OARNG?p=preview
$provide.value('$provide', $provide);
$routeProvider.otherwise({
template: '<test></test>',
controller: function ($provide, myJsonData1) {
$provide.value('myJsonData', myJsonData1);
},
resolve: {
myJsonData1: function(){
return getMyJsonData();
}
}
});
Hope this helps :)
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).
I am trying to set up tests for my Angular.js project and I keep getting "$injector:nomod, Module 'result' is not available! You either misspelled..." error. I am sure that I am including "result" module in the "files" array inside "karma.config.js", basically it looks like this:
files: [
'../javascripts/jquery-2.1.4.min.js',
'../jquery-ui/jquery-ui.min.js',
'../D3/d3.js',
'libs/angular.min.js',
'libs/angular-route.min.js',
'libs/angular-animate.min.js',
'libs/selectize.js',
'libs/angular-selectize.js',
'libs/angular-mocks.js',
'simulator.js',
'*.js',
'services/**/*.js',
'qa/tests-*.js'
],
...
I thought initially that the ordering of the main module: 'simulator' (defined inside 'simulator.js' file) is wrong, so I specifically moved it upwards, before
the other modules, like the following stackoverflow thread recommends:
Angular module not available in Karma Jasmine test run
It did not help. Then I tried to make sure that the files are imported in the same order as in my angular apps' main entry file (except for angular-mocks.js and qa/tests-*.js), importing each single file, instead of using wildcards, but no success.
Jasmine definitely goes inside the test files but stumbles upon the line where I am trying to import the module "result":
describe('simulator.chartService', function() {
var chartService;
var graphConfig;
console.log("instantiating module result");
beforeEach(module('result'));
console.log("finished instantiating");
beforeEach(inject(function($injector) {
graphConfig = $injector.get('graphConfig');
chartService = $injector.get('chartService');
}));
it('should be created', function() {
expect(chartService.calcColors(10)).not.toBeNull();
});
});
So, I see that the error happens in-between two console.log() statements.
I suspect that still something can be wrong with the ordering of my files inside the array "files" in "karma.config.js". I have main module "simulator" which is dependent on other modules:
angular.module('simulator', ['ngRoute','ngAnimate','selectize','newexp2','newexp','login','edit','exps', 'result','templates','commons'])
Modules 'newexp2', 'newexp', 'login', 'edit', 'exps', 'result', 'templates' are all dependent on the module 'commons'.
How to correctly import interdependent modules inside the "files" array?
Is it just enough to place "simulator.js", main module, above all others,
or I also need to place all other modules before "commons.js"?
Another my suspicion is that angular.js library version that I downloaded from the official angular website, "angular-mocks.js", can be incompatible with other modules that I am using. I had such an issue with "angular-animate.js" file before.
As long as I surround my test code with $(function(){...}) (and all other my modules ARE surrounded with it) it does not generate the error while importing the result module, so I start seeing two console.log() statements without an error in-between, however, this generates some unknown error which prevents me from invoking the it part at all, whereas when I do not surround it with $(function(){...}), the it test is invoked, but the module result import fails.
So far I am pretty much stuck and do not know where to move and what to try. Any suggestion would be greatly appreciated.
OK, I figured it out. The issue was that ALL of my angular code was enclosed inside $(function(){...}). The solution is to remove all of the $function(){...}), then reorder javascript imports inside the main entry .html file, and then all of the testing starts working good.
The question might be better to mark as duplicate with:
Angular document.ready() issue
If I wanted to add my own custom "provider" to the list (in AngularPublic.js), like so:
...
$provide.provider({
$anchorScroll: $AnchorScrollProvider,
$animate: $AnimateProvider,
$browser: $BrowserProvider,
$cacheFactory: $CacheFactoryProvider,
$controller: $ControllerProvider,
$myCustomController: $MyCustomControllerProvider, <---- I made this
$document: $DocumentProvider,
$exceptionHandler: $ExceptionHandlerProvider,
$filter: $FilterProvider,
$interpolate: $InterpolateProvider,
...etc
If I used an existing provider as boilerplate, would this be a bad idea?
Yes, it is definitely a bad idea. I don't think it is reasonable to modify the source code of Angular as Angular itself is fast growing, things change every second, you may find it is hard to merge your change with newest Angular version one day.
If you only want to add your custom provider into ngModule, you can just to this.
var ngModule = angular.module('ng');
ngModule.provider('myCustom', function() {
// Your code goes here
});
Hope it may help you.
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);
}
});