PDA

View Full Version : Using requires with Ext.define.



incutonez
6 Feb 2012, 6:10 AM
Hello all, I don't think I'm correctly understanding what requires does. I thought it loaded the classes in the requires field before loading the current class... so because that sounds confusing, here's an example:


Ext.define('blah', {
requires: ['Ext.grid.Panel', 'path.to.sha'],
extend: 'Ext.grid.Panel',
...(other definitions)
dockedItems: [{
xtype: 'toolbar',
items: [{
xtype: 'button',
text: 'Blah grid',
menu: new sha() // Ext.create('sha') doesn't work either
}]
}] // ends dockeditems
});

*sha is in its own file in the same directory as blah, and just consists of:


Ext.define('sha', {
requires: ['Ext.menu.Menu'],
extend: 'Ext.menu.Menu',
items: [{
text: 'this is a menu item'
}]
});

So, I figured requires loads Ext.grid.Panel and sha before continuing. Ext.grid.Panel appears to work, but whenever I try to use sha as the menu, I get a "sha is undefined" error. I've checked the path to sha, and everything seems to be right there. If I include sha's code directly above blah's code, and do a 'new sha()', everything works perfectly.

Also, I've set a firebug break point in sha's code to see if it loads before blah, and it does (or at least, it stops at the break point... whether this means it's loaded for blah, I'm not sure, I was just curious).

I figured if I copied the code of sha into blah, it's not a syntactical issue... just a functionality issue with requires. So if anyone has any insight or would like more information, just let me know.

incutonez
6 Feb 2012, 6:52 AM
By adding an alias in sha "alias: 'widget.sha'" and then invoking it in blah's menu like:

menu: {xtype: 'sha'}

my problem was solved. However, the question remains... shouldn't sha have been loaded in blah? If so, how do I create a new instance of sha?

vietits
6 Feb 2012, 7:02 AM
See my fixes in red color:

Ext.define('blah', {
requires: ['Ext.grid.Panel', 'path.to.sha'],
extend: 'Ext.grid.Panel',
...(other definitions)
dockedItems: [{
xtype: 'toolbar',
items: [{
xtype: 'button',
text: 'Blah grid',
menu: Ext.create('path.to.sha') // new sha() // Ext.create('sha') doesn't work either
}]
}] // ends dockeditems
});

and:

//Ext.define('sha', {
Ext.define('path.to.sha', {
requires: ['Ext.menu.Menu'],
extend: 'Ext.menu.Menu',
items: [{
text: 'this is a menu item'
}]
});

incutonez
8 Feb 2012, 4:57 AM
Yeah, I had done that too--just forgot to include it in my original post. My problem still lies with the requires field... why is it not loading those classes before it's created?

vietits
8 Feb 2012, 3:29 PM
Check to see whether or not you enable the dynamic dependency loading feature of Ext.Loader


Ext.Loader.setConfig({
enabled: true
});

incutonez
10 Feb 2012, 7:12 AM
Yep, I've got Ext.Loader set up just like that.

dedoz
11 Feb 2012, 1:27 PM
you just are confused with javascript i think look

myFunction('sometext', { key1: 'value', key2: value2 })

will trigger an error because value2 is undefined.
this is the same as doing

myFunction(value);

value doesnt exists.

so doing a


Ext.define('blah', {
menu: new sha()
});


is pretty much the same as


someFunction(new sha());

see what happens ? before calling Ext.define, which will try to load your required files, your trying to use sha, which doesnt exists at the point before Ext.define is executed

sorry for my english

incutonez
11 Feb 2012, 6:41 PM
Right, the class is not defined, which is the reason for calling 'requires' or at least that's what I thought the point of 'requires' was... from the Sencha Docs:


List of classes that have to be loaded before instantiating this class. For example:

Ext.define (http://docs.sencha.com/ext-js/4-0/#!/api/Ext-method-define)('Mother', {
requires: ['Child'],
giveBirth: function() { // we can be sure that child class is available.
return new Child();
}
});

dedoz
12 Feb 2012, 1:09 PM
you still dont get it, in your first post, the requires is excuted after the new sha()

you were doing this (example #1)
Ext.define('name',{requires:'myClass', config1: new MyClass());

is like doing (example#2)

function1( function2() )

which is executed first ? function2.

in Example #1whos goin to try to load your required files ? Ext.define (not really but works for the example).
which is executed first ? new MyClass();

im done ;D

btw if u want to use files/classes in a Ext.define that get "loaded" first use the initComponent method.



Ext.define('blah', {
requires: ['someClass1','someClass2'],
extend: 'Ext.grid.Panel',
initComponent: function()
{ this.dockedItems = [{
xtype: 'toolbar',
items: [{
xtype: 'button',
text: 'Blah grid',
menu: Ext.create('someClass1')
}]
}]; // ends dockeditems
}
});

incutonez
12 Feb 2012, 2:01 PM
Can you explain to me what 'requires' does then? Because I figured it loaded classes, so you could use them in the current class's definition scope. I mean, if I require my 'sha' class, why would I do that if I can't use it?

I'm thinking initComponent will do the job. I will try that tomorrow. Thanks for giving me all this help... but I still don't understand why 'requires' exists...

incutonez
13 Feb 2012, 6:28 AM
A couple of things... first of all, if I try to do:


Ext.Loader.setConfig({
enabled: true
});
Ext.require(['Ext.grid.Panel', '/home/incutonez/sha.js']);

Ext.onReady(function() {
alert('blah');
});

I don't get the alert. Firebug reports no errors, but if I get rid of the '/home/incutonez/sha.js' part, it works. I've also tried omitting '.js' but still don't get the alert. I've also tried adding


Ext.Loader.setPath('Ext.my', '/home/incutonez/');
Ext.require(['Ext.grid.Panel', 'Ext.my.sha']);

but no go. Either I'm using require/requires really wrong, or it's broken. It just seems like the path can't be found, but the path is 100% right and the file exists... any help?

dedoz
14 Feb 2012, 12:40 PM
Dont focus on understand what requires do, focus on understand what is executed first

Look at this (which is not ExtJs code)
Lets say you have a class defined in sha.js file and in use.js you want to use that class

in use.js you do (this works)
-------------------------
include ('sha.js')
new sha();
-------------------------

if you do
-------------------------
new sha();
include ('sha.js')
-------------------------
it wont work, sha definition havent been include yet when you try to use it, you agree ?

now Ext.define('myThing') is just an ordinary function like defineSomething('myThing')
one thing you can pass to Ext.define is the required files, that need to be loaded before someone creates an instance of your thing.

Ext.define('myThing',{requires:'otherThing'})

see ? requires is not executed yet, is just a parameter to Ext.define.
{ requires : 'otherThing' } is just JSON, just a way to write things. but it doing nothing yet
you can do { something : 'someStuff'} you know bout JSON ? (javascript object notation)

is something like this

function sum (a,b) {
return a+b;
}
then you call this function like this
function(1,2) // returns 1+2

instead of declarating the arguments like that, you can say u expect a object as a paremeter

function sum(params) {
return params.a + params.b
}
then you call this function like this
function({ a: 1, b:2 }) // returns 1+2
but "a" in { a : 1 , b: 2} means nothing, till sum function reads it and does something with it

is the same with Ext.define
Ext.define( {'myThing', {requires : 'otherthing'})
requires is just a word, that when Ext.define is executed, he will read and do something with it.
before Ext.define the { requires : 'otherThing' } is just a pair { someKey : someValue} in JSON.

in your first post you were doing
Ext.define{ 'myThing', {requires: 'sha' , otherKey : new Sha() }
before Ext.define is executed, requires is doing nothing, and you use new Sha()

this is like doing
Ext.define{ 'myThing', {a: 'sha' , b : new Sha() }

similar to
sum({ a : 'sha', b: new Sha()});

similar to
sum({ a : 'sha', b: c});

and your browser will complain because c is undefined.

dedoz
14 Feb 2012, 12:54 PM
from your post


Ext.Loader.setConfig({
enabled: true
});
Ext.require(['Ext.grid.Panel', '/home/incutonez/sha.js']);

Ext.onReady(function() {
alert('blah');
});


Ext.Loader expect you have 1 class per file which normally share the name.
Also try to use namespace to avoid name conflicts.
Lets use INCUTONEZ as namespace and you append all your classes to this namespace.

if your sha.js file looks like this


Ext.define('INCUTONEZ.Sha', {
extends : 'Ext.grid.Panel',
... other configs ....
})

and you save this file in '/home/incutonez/sha.js
so first you set a path to Ext.Loader

Loader.setPath('INCUTONEZ','/home/incutonez')
means
" when require a file like Ext.require('INCUTONEZ.something') transtale to home/incutones/something.js "
after setting path
load your class using its name (the first paremeter of Ext.define) not the extended class

Ext.require('INCUTONEZ.sha');
this will try to load home/incutones/sha.js
and expect inside sha.js to find Ext.define('INCUTONEZ.sha', otherstuff.......)

incutonez
14 Feb 2012, 1:43 PM
Dont focus on understand what requires do, focus on understand what is executed first

I understand what's going on... I don't understand why requires exists if it doesn't load the classes I want to use in my current class's scope! I'm also not one to just blindly go use something if I have no idea what it's doing... I think my problem is getting lost in translation here. I mean, you even say it yourself...


one thing you can pass to Ext.define is the required files, that need to be loaded before someone creates an instance of your thing.

To me, this means that I can 'require' my sha class, then I can use the sha class within my blah class definition, but that doesn't seem to be the case because I get an undefined.


requires is just a word, that when Ext.define is executed, he will read and do something with it.
before Ext.define the { requires : 'otherThing' } is just a pair { someKey : someValue} in JSON.

Right, and what requires does with the string you pass to it is load the corresponding class BEFORE the current class instantiates.

I'm even more confused with what requires does, and I realize you're trying to help me out... I appreciate that, but I still feel like you're explaining requires exactly how I think it should work, yet it doesn't work that way.

Also, I tried initComponent, but that gave me even more issues... I'll post those errors tomorrow.

incutonez
14 Feb 2012, 4:48 PM
Ok, I've come up with an example.

main.html

<html>
<head>
<script type=text/javascript src='ext.js'></script>
<script type=text/javascript src='ext-all.js'></script>
<script type=text/javascript src='main.js'></script>
<link rel=stylesheet type=text/css href='resources/css/ext-all.css' />
</head>
<body>
</body>
</html>


main.js

Ext.Loader.setConfig({
enabled: true,
path: {
'incutonez': 'incutonez'
}
});

Ext.require(['incutonez.blah', 'incutonez.sha']);

Ext.onReady(function() {
var grid = Ext.create('incutonez.blah');
grid.render(Ext.getBody());
});


blah.js

Ext.define('incutonez.blah', {
requires: ['Ext.grid.Panel', 'incutonez.sha'],
extend: 'Ext.grid.Panel',
height: 200,
width: 200,
columns: [{
header: 'blah'
}]/*,
initComponent: function() {
this.dockedItems = [{
xtype: 'toolbar',
items: [{
xtype: 'button',
text: 'Blah grid',
menu: Ext.create('incutonez.sha')
}]
}];
}*/
});


sha.js

Ext.define('incutonez.sha', {
requires: ['Ext.menu.Menu'],
extend: 'Ext.menu.Menu',
items: [{
text: 'this is a menu item'
}]
});


Ok, so obviously main.js calls blah.js which calls sha.js, and both blah.js and sha.js live in the incutonez folder which lives in the extjs main folder (where I have main.js and main.html).

If I comment out the dockedItems call in blah.js, I can render the grid just fine (without the menu of course). However, if I include dockedItems, I get the 'c is not a constructor' error.

If I use initComponent like you recommended, I get 'd.dockedItems.items is undefined' which I think is because of the brackets (highlighted in red in blah.js) that you originally included, so if I take them out and just use braces, I get 'c[b].isVisible is not a function'.

Finally, if I include both blah's and sha's code in main.js, and don't use their paths (when defining), everything works fine meaning sha's menu does render in the grid.

So yeah, there's a lot going on here. What I want to know is, how would you get this working?

WidowMaker
25 Feb 2012, 10:55 AM
Hello, incutonez
your example works for me fine with small changes - you forgot to call parent initComponent method.


initComponent: function() {
this.dockedItems = [{
xtype: 'toolbar',
items: [{
xtype: 'button',
text: 'Blah grid',
menu: Ext.create('incutonez.sha')
}]
}];
this.callParent(arguments); // you should always call this in initComponent to build docketItems object from it's config.
}

I will try to explain what's happens there:
- when you reference classs by 'name' the loader tries to find apropriated file and include it in HTML/header section (look into your page source).
- included file will be parsed next after current file, this means that you can't create instances of class('name') inside of current file (this is what you doing in cofig dockedItems).
- the code inside of initComponent will executed only when you try to create an instance (so this happens when all needed files included and parsed).

incutonez
26 Feb 2012, 2:24 PM
That did it. Thanks! Why does it seem like callParent is something that should automatically happen? Doesn't make sense to me why I have to specify it... either way, thanks once again!