3

I'm kinda struggling with Javascript variable scopes in combination with a jQuery JSON call. Unforutnatly, I can't post this script on jsFiddle, because it needs some data.

I'm trying to dynamicly load data and output it on the user's screen. I've now only created the method that loads the data for the first time. Later on I'd like to make an update method which updates the data in the table rows.

But now I'm having a problem with the variable scope. When $.pcw.outstandingInvoices.init() has been called, I get the following error:

ypeError: can't convert undefined to object
this.outstandingInvoicesArray[key] = entry;

My code:

-- Post is getting to long, so removed the first code i've used. -- 

Could anyone tell me what I'm doing wrong so I can fix it?

Thanks in advance!

--- UPDATE --- I've edited the things you guys told me, but still I'm getting errors... Could anyone tell me what I'm doing wrong?

My new code and errors:

-- Post is getting to long, so removed the first update of the code. -- 

Errors:

Initializing outstandingInvoices class.
Loading outstanding invoices from server.

TypeError: context.outstandingInvoicesObject is undefined
if (context.outstandingInvoicesObject.length == 0) {

TypeError: can't convert undefined to object
self.outstandingInvoicesObject[key] = entry;

-- UPDATE 2 -- Just edited my code and now I'm not gettting errors, but the data in outstandingInvoicesObject is not properly saved, so the method addOutstandingInvoicesTable can't find any invoices. I've been analyzing the console and it seems the there is somethin wrong with order of execution of the methods...

The code:

$.pcw.outstandingInvoices = function () {
    var context = this;
    context.outstandingInvoicesObject = [];

    context.init = function ()
    {
        console.log('Initializing outstandingInvoices class.');

        context.loadData();        
        context.removeLoader();
        context.addOutstandingInvoicesToTable();
    };

    context.loadData = function ()
    {
        console.log('Loading outstanding invoices from server.');

        jQuery.getJSON('/ajax/outgoing-invoices/find-outstanding.json', function (data)
        {   
            var i = 0;
            jQuery.each(data, function (key, entry)
            {
                context.outstandingInvoicesObject[key] = entry;

                ++i;
            });

            console.log('Loaded ' + i + ' invoices');
        }).error(function () {
            console.error('Error while loading outstanding invoices.');
        });
    };

    context.removeLoader = function ()
    {
        console.log('Removing loader');

        jQuery('table#invoices-outstanding tr.ajax-loader').fadeOut();
    };

    context.addOutstandingInvoicesToTable = function()
    {
        console.log('Outputing invoices to table');

        if (context.outstandingInvoicesObject.length == 0) {
            console.log('No outstanding invoices found');
        }

        jQuery.each(context.outstandingInvoicesObject, function (key, entry)
        {
            // This is a new outstanding invoice
            var rowClass = 'info';

            switch(entry.status)
            {
                case 'Created':
                case 'Sent':
                case 'Paid': // The invoices with Paid statuses aren't show here, because we only show the oustanding invoices on this page.
                    rowClass = 'success';
                break;

                case 'First reminder':
                case 'Second reminder':
                case 'Partially paid':
                    rowClass = 'warning';
                break;

                case 'Third reminder':
                case 'Collection agency':
                case 'Judicial proceedings':
                    rowClass = 'error';
                break;
            }

            jQuery('table#invoices-outstanding tbody').append(
                outstandingInvoice = jQuery('<tr/>', {
                    id: 'outgoing-invoice-' + key,
                    class: rowClass
                }).append(
                    jQuery('<td/>', {
                        class: 'id',
                        text: key
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'debtor-name',
                        text: entry.debtor_name
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'amount',
                        text: entry.amount
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'date',
                        text: entry.created_timestamp
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'status',
                        text: entry.status
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'creator',
                        text: entry.creator
                    })
                )            
            );
        });
    }
}


// When document is ready
(function()
{
    var invoices = new $.pcw.outstandingInvoices();
    invoices.init();
})();

The console output:

Initializing outstandingInvoices class.

Loading outstanding invoices from server.
GET /ajax/outgoing-invoices/find-outstanding.json
200 OK
509ms   

Removing loader

Outputing invoices to table

No outstanding invoices found

Loaded 29 invoices

Thanks

1
  • Can you add some data samples as JSON string? Commented Feb 1, 2013 at 19:01

5 Answers 5

1

Create a backup of the object so you can use it in functions where this does not reference the object.

loadData: function ()
{
    console.log('Loading outstanding invoices from server.');
    var self = this;
    jQuery.getJSON('/ajax/outgoing-invoices/find-outstanding.json', function (data)
    {            
        jQuery.each(data, function (key, entry)
        {
            self.outstandingInvoicesArray[key] = entry;
        });
    }).error(function () {
        console.error('Error while loading outstanding invoices.');
    });
},
Sign up to request clarification or add additional context in comments.

1 Comment

Did this, thank you. Untortunatly this did not fix the problem.
1

You're creating outstandingInvoicesArray as an array, but you're trying to access it as an object:

outstandingInvoicesArray: []
[...]
this.outstandingInvoicesArray[key] = entry;

create it as an object instead:

outstandingInvoicesArray: {}

1 Comment

Did this, thank you. Untortunatly this did not fix the problem.
1

The following should fix your problems. You weren't declaring oustandingInvoicesObject the way you were intending. It had to be off 'this' or 'context' in your case.

Also, you declared oustandingInvoicesObject as an Array instead of an Object. You can't add properties to an Array like you would an Object.

Let me know how it goes.

$.pcw.outstandingInvoices = function () {
    var context = this;
    context.outstandingInvoicesObject = {};

    context.init = function ()
    {
        console.log('Initializing outstandingInvoices class.');

        context.loadData();
        context.removeLoader();
        context.addOutstandingInvoicesToTable();
    };

    context.loadData = function ()
    {
        console.log('Loading outstanding invoices from server.');

        var self = this;

        jQuery.getJSON('/ajax/outgoing-invoices/find-outstanding.json', function (data)
        {            
            jQuery.each(data, function (key, entry)
            {
                self.outstandingInvoicesObject[key] = entry;
            });
        }).error(function () {
            console.error('Error while loading outstanding invoices.');
        });
    };

    context.removeLoader = function ()
    {
        jQuery('table#invoices-outstanding tr.ajax-loader').fadeOut();
    };

    context.addOutstandingInvoicesToTable = function()
    {
        if (context.outstandingInvoicesObject.length == 0) {
            console.log('No outstanding invoices found');
        }

        jQuery.each(context.outstandingInvoicesObject, function (key, entry)
        {
            // This is a new outstanding invoice
            var rowClass = 'info';

            switch(entry.status)
            {
                case 'Created':
                case 'Sent':
                case 'Paid': // The invoices with Paid statuses aren't show here, because we only show the oustanding invoices on this page.
                    rowClass = 'success';
                break;

                case 'First reminder':
                case 'Second reminder':
                case 'Partially paid':
                    rowClass = 'warning';
                break;

                case 'Third reminder':
                case 'Collection agency':
                case 'Judicial proceedings':
                    rowClass = 'error';
                break;
            }

            jQuery('table#invoices-outstanding tbody').append(
                outstandingInvoice = jQuery('<tr/>', {
                    id: 'outgoing-invoice-' + key,
                    class: rowClass
                }).append(
                    jQuery('<td/>', {
                        class: 'id',
                        text: key
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'debtor-name',
                        text: entry.debtor_name
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'amount',
                        text: entry.amount
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'date',
                        text: entry.created_timestamp
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'status',
                        text: entry.status
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'creator',
                        text: entry.creator
                    })
                )            
            );
        });
    };
};

// When document is ready
(function(){
    var invoices = new $.pcw.outstandingInvoices();
    invoices.init();
})();

1 Comment

Thank you! Also tried this one, but the same problem remains.. Please see my updated code in the start post.
1

You should use the new keyword when initailizing the object if you want to use this:

$.pcw.outstandingInvoices = function(){
   var context = this;//replace every instance of "this" in your class with the context var

   context.init= function ()
    {
        console.log('Initializing outstandingInvoices class.');

        context.loadData();

    }
    //the rest of functions defined below
}
var invoices = new $.pcw.outstandingInvoices();
invoices.init();

Edit: to fix the remaining errors try using context instead of self, and declare outstandingInvoicesObject on the context:

$.pcw.outstandingInvoices = function () {
    var context = this;
    context.outstandingInvoicesObject = [];

    context.init = function ()
    {
        console.log('Initializing outstandingInvoices class.');

        context.loadData();

    };

    context.loadData = function ()
    {
        console.log('Loading outstanding invoices from server.');



        jQuery.getJSON('/ajax/outgoing-invoices/find-outstanding.json', function (data)
        {            
            jQuery.each(data, function (key, entry)
            {
                context.outstandingInvoicesObject[key] = entry;
            });
            //now that we have data, call add the invoices to the table
            context.removeLoader();
            context.addOutstandingInvoicesToTable();
        }).error(function () {
            console.error('Error while loading outstanding invoices.');
        });
    };

    context.removeLoader = function ()
    {
        jQuery('table#invoices-outstanding tr.ajax-loader').fadeOut();
    };

    context.addOutstandingInvoicesToTable = function()
    {
        if (context.outstandingInvoicesObject.length == 0) {
            console.log('No outstanding invoices found');
        }

        jQuery.each(context.outstandingInvoicesObject, function (key, entry)
        {
            // This is a new outstanding invoice
            var rowClass = 'info';

            switch(entry.status)
            {
                case 'Created':
                case 'Sent':
                case 'Paid': // The invoices with Paid statuses aren't show here, because we only show the oustanding invoices on this page.
                    rowClass = 'success';
                break;

                case 'First reminder':
                case 'Second reminder':
                case 'Partially paid':
                    rowClass = 'warning';
                break;

                case 'Third reminder':
                case 'Collection agency':
                case 'Judicial proceedings':
                    rowClass = 'error';
                break;
            }

            jQuery('table#invoices-outstanding tbody').append(
                outstandingInvoice = jQuery('<tr/>', {
                    id: 'outgoing-invoice-' + key,
                    class: rowClass
                }).append(
                    jQuery('<td/>', {
                        class: 'id',
                        text: key
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'debtor-name',
                        text: entry.debtor_name
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'amount',
                        text: entry.amount
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'date',
                        text: entry.created_timestamp
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'status',
                        text: entry.status
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'creator',
                        text: entry.creator
                    })
                )            
            );
        });
    }
}

6 Comments

Did this, thank you. Untortunatly this did not fix the problem.
add context to the delcaration. so context.outstandingInvoicesObject = [] instead of var outstandingInvoicesObject = []; also instead of using the self variable, use context.outstandingInvoicesObject[key] = entry;
I posted your code sample updated with these fixes that I suggested in the comments above
Just replaced the comma's with semicolons after each of the function declarations
@E.Clark This is happening because the call to get json is async, so when you populate the table the object has not yet been filled. I edited my answer so that the call call to populate the table happens in the callback of the get json method
|
0

The problems are solved now.. It was a combination of the things you guys said and the problem that the AJAX call was asynchronous.

The final working code is:

$.pcw.outstandingInvoices = function () {
    var context = this;
    context.outstandingInvoicesObject = new Object();

    context.init = function ()
    {
        console.log('Initializing outstandingInvoices class.');

        context.loadData();                
        context.removeLoader();
        context.addOutstandingInvoicesToTable();
    };

    context.loadData = function ()
    {
        console.log('Loading outstanding invoices from server.');

        $.ajax({
            url: '/ajax/outgoing-invoices/find-outstanding.json',
            dataType: 'json',
            async: false,
            success: function(data) {                
                var i = 0;            
                jQuery.each(data, function (invoiceId, invoiceDetails)
                {
                    context.outstandingInvoicesObject[invoiceId] = invoiceDetails;

                    ++i;                                
                });

                console.log('Loaded ' + i + ' invoices');       
            }
        }).error(function () {
            console.error('Error while loading outstanding invoices.');
        });
    };

    context.removeLoader = function ()
    {
        console.log('Removing loader');

        jQuery('table#invoices-outstanding tr.ajax-loader').fadeOut();
    };

    context.addOutstandingInvoicesToTable = function()
    {
        console.log('Outputing invoices to table');           

        if (context.outstandingInvoicesObject.length == 0) {
            console.log('No outstanding invoices found');            
        }

        jQuery.each(context.outstandingInvoicesObject, function (key, entry)
        {
            // This is a new outstanding invoice
            var rowClass = 'info';

            switch(entry.status)
            {
                case 'Created':
                case 'Sent':
                case 'Paid': // The invoices with Paid statuses aren't show here, because we only show the oustanding invoices on this page.
                    rowClass = 'success';
                break;

                case 'First reminder':
                case 'Second reminder':
                case 'Partially paid':
                    rowClass = 'warning';
                break;

                case 'Third reminder':
                case 'Collection agency':
                case 'Judicial proceedings':
                    rowClass = 'error';
                break;
            }

            jQuery('table#invoices-outstanding tbody').append(
                outstandingInvoice = jQuery('<tr/>', {
                    id: 'outgoing-invoice-' + key,
                    class: rowClass
                }).append(
                    jQuery('<td/>', {
                        class: 'id',
                        text: key
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'debtor-name',
                        text: entry.debtor_name
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'amount',
                        text: entry.amount
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'date',
                        text: entry.created_timestamp
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'status',
                        text: entry.status
                    })
                ).append(
                    jQuery('<td/>', {
                        class: 'creator',
                        text: entry.creator
                    })
                )            
            );
        });
    }
}

// When document is ready
(function()
{   
    var invoices = new $.pcw.outstandingInvoices();
    invoices.init();
})();

Thanks for the help, guys!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.