Vinay
Vinay

Reputation: 2594

Call ExtJS function outside of scope in Javascript

I am new to ExtJS. Trying to use and customize tabs feature in application.

I want to call a function with parameters which is in ExtJs scope from Javascript Scope. Right Now I can call function without passing parameters without getting any errors. When I call same function by passing parameters(mentioned in code), It gives me following error as function is not getting any values.

Uncaught TypeError: Cannot call method 'indexOf' of null

This function should add new tab to tabpanel.

When I call same function by passing parameters from ExtJS scope it is adding tab successully. But not when function get called from javascript scope by passing parameters. Help me to understand and fix this problem.

Ext.onReady(function() {
var currentItem;
var tabs = Ext.widget('tabpanel', {
    launch: function() {
      _myAppGlobal = this;
    },
    renderTo: 'tabs',
    resizeTabs: true,
    enableTabScroll: true,
    width: 850,
    defaults: {
        autoScroll: true,
        bodyPadding: 10
    }], 
    plugins: Ext.create('Ext.ux.TabCloseMenu', {
        extraItemsTail: [
            '-',
            {
                text: 'Closable',
                checked: true,
                hideOnClick: true,
                handler: function (item) {
                    currentItem.tab.setClosable(item.checked);
                }
            },
            '-',
            {
                text: 'Enabled',
                checked: true,
                hideOnClick: true,
                handler: function(item) {
                    currentItem.tab.setDisabled(!item.checked);
                }
            }
        ],
        listeners: {
            aftermenu: function () {
                currentItem = null;
            },
            beforemenu: function (menu, item) {
                menu.child('[text="Closable"]').setChecked(item.closable);
                menu.child('[text="Enabled"]').setChecked(!item.tab.isDisabled());

                currentItem = item;
            }
        }
    })
  });

  function addTab_inside(closeable, tabtitle, targetUrl) {
      tabs.add({
          title: tabtitle,
          iconCls: 'tabs',
          autoLoad: {url: targetUrl, callback: this.initSearch, scope: this},
          closable: closeable,
          autoScroll: true,
          nocache: true,
          discardUrl: false
      }).show();
  }
});

function addTab_Outside(){
   addTab_inside(true, 'Test', 'test.php');
}

addTab_Outside function is event based and getting called onClick on xyz element.

Upvotes: 3

Views: 9265

Answers (2)

Justin
Justin

Reputation: 1310

addTab_inside(true, 'Test', 'test.php'); is going to run before Ext.onReady. So, your function is not going to exist yet. Move addTab_inside to the bottom of your Ext.onReady method.

Update

@dbrin did a great job explaining the scoping issues here. If you really wanted to get your approach to work you would need to set up some "namespacing" as I show below.

//Namespace defined in Global scope
var myApp = {};

Ext.onReady(function(){ 
  //Some stuff... 

  myApp.addTab_inside = function(closeable, tabtitle, targetUrl){
    //do work
  }
});

function addTab_Outside(){
  myApp.addTab_inside(true, 'Test', 'test.php');
}

As I mentioned before, you will still need to make sure you don't call addTab_inside before Ext is ready.

With all that said, I would suggest you check out the tutorial on the suggested MVC architecture as @dbrin mentioned.

Upvotes: 1

dbrin
dbrin

Reputation: 15673

There is no such thing as Ext scope. Ext is a set of JS objects and functions no more no less. As such everything that is applicable to JS is applicable to Ext. Any scoping issues and complications are purely that of JavaScript and are not any different for Ext than for any other JS library or utility.

Now, lets take a look at what you have done:

  1. You called Ext.onReady() function with some parameters.
  2. You defined a function addTab_Outside() in a global scope (aka window scope).

That is all.

Now lets look at the addTab_Outside function. In this function you are calling another function addTab_inside. But where is this 'inside' function? Where should JS look for this function? Since you are defining the'ouside' function in the global scope, then JS will look for the inside function in the same scope and will fail to find it as it is not created in the global scope.

So in what scope is the 'inside' function created? Well, let's go back to the first thing that you did here: Ext.onReady() function call. You called this function passing in a single parameter. That parameter is an anonymous function with 2 local variables currentItem and tabs. And you also created a local function that you named 'addTab_inside'. When I say 'local' it means that the variables are local to the function in whose scope they were created. In your case that parent function is anonymous and hence not addressable. Any local variables whithin that function can access each other of course since they are all in the same scope. So as long as 'tabs' reference 'inside' function or the currentItem you are ok.

The only way your solution will work is if you move the outside function inside your large anonymous function block. But I suspect you dont want to do that because there really is not reason for it.

Although this discussion of scopes is important to understand, my gut feel is that you should follow a different approach to whatever it is you are trying to do. If you are building a full application then I suggest you use application structure outlined in the Sencha guides, using controllers and folder structure to separate your code.

Upvotes: 2

Related Questions