shiznatix
shiznatix

Reputation: 1107

Get parent class property

I have a javascript class that has a method that uses jQuery to send an Ajax request and handle the response.

The problem I am having is that I can't figure out how to get the properties of the initial, parent class from within the jQuery functions. I have tried $(this).parent() but this doesn't get what I need for some reason.

My code is below. Can anyone tell me how to get to the base class from this loop?

function companiesPage()
{
    this.childCategoriesSelectid = '#childCategoryid';

    this.setChildCategories = function()
    {
        $.ajax({
            url: this.url,
            dataType: 'json',
            success: function(data)
            {
                $.each(data.childCategories, function()
                {
                    $($(this).parent().childCategoriesSelectid)//problem here
                    .append(
                        $('<option></option>')
                        .attr('value', this.childCategoryid)
                        .text(this.name)
                    );
                });
            }
        });
    }
}

Upvotes: 1

Views: 2587

Answers (2)

Robert Koritnik
Robert Koritnik

Reputation: 105019

Capture this before asynchronous Ajax call

Ajax success handler is asynchronously executed hence looses its callee context (or scope). You have to capture this free variable and use captured variable within function closure.

It seems you're expecting this to have two meanings

  1. when you use $(this).parent()... you're expecting this to be some HTMLDOMElement
  2. when you use this.name you're expecting this to be an object item in your data (likely array).

Solution of getting object instance reference

It becomes obvious that companiesPage is your class (should be Pascal cased and not camel cased). Hence the use of this within. You likely create it by:

var obj = new CompaniesPage();
obj.setChildCategories();

your code should then look like this:

var CompaniesPage = function()
{
    // keep this as public object property
    this.childCategoriesSelectId = "#childCategoryid";

    // keep this as public object method
    this.setChildCategories = function() {
        // private reference to object instance for later reuse
        var me = this;
        $.ajax({
            url: this.url, // not sure where this one's coming from
            dataType: 'json',
            success: function(data) {
                $.each(data.childCategories, function() {
                    $(me.childCategoriesSelectId).append(
                        $('<option></option>')
                            .attr('value', this.childCategoryid)
                            .text(this.name)
                    );
                });
            }
        });
    }
};

Additional optimisation of your class

You also have to realise that the way that you've defined your class-level method is not memory efficient because individual object instances won't share the same method but would rather have each their own which reflects on memory resources especially when you'd create several instances of the same class.

This is an optimised version of your class:

var CompaniesPage = function() {
    // keep this as public object property
    this.childCategoriesSelectId = "#childCategoryid";
}

CompaniesPage.prototype.setChildCategories = function() {
    // private reference to me as object instance
    var me = this;

    $.ajax({
        url: this.url, // not sure where this one's coming from
        dataType: 'json',
        success: function(data) {
            $.each(data.childCategories, function() {
                $(me.childCategoriesSelectId).append(
                    $('<option></option>')
                        .attr('value', this.childCategoryid)
                        .text(this.name)
                );
            });
        }
    });
};

Upvotes: 1

Fabr&#237;cio Matt&#233;
Fabr&#237;cio Matt&#233;

Reputation: 70139

parent() is for DOM traversal. What you have is a scoping problem.

The this keyword does not always references the same object when entering a new function scope. That is the case when using jQuery's .each() method which will set this to the object/element being iterated.

Looks like you're using a constructor-instance pattern, so you just have store a reference to the original object that the this keyword referenced to (the instance) through a var declaration. This reference will remain unchangeable in the scope chain:

function companiesPage()
{
    var _this = this; //stores a reference to this instance object
    this.childCategoriesSelectid = '#childCategoryid';

    this.setChildCategories = function()
    {
        $.ajax({
            url: this.url,
            dataType: 'json',
            success: function(data)
            {
                $.each(data.childCategories, function()
                {
                    $(_this.childCategoriesSelectid) //NO problem here :)
                    .append(
                        $('<option></option>')
                        .val(this.childCategoryid)
                        .text(this.name)
                    );
                });
            }
        });
    }
}

This way you will be able to access any of your instance's public methods and properties anywhere inside of your instance.

ps. Instanceables/Constructors usually have the first letter upper-cased, by convention.

Upvotes: 2

Related Questions