kmad
kmad

Reputation: 101

Promises miss understand

Hi i have simple code like that:

jQuery(function ($) {
    function Item(val) {
        this.val = val
        var self = this;
        this.generateTrDOM = function () {
            var tr = '<tr>';
            tr += '<td>' + self.val + '</td>';
            tr += '</tr>';
            return tr;
        };
    }

    function ItemsCollection() {
        this.someHandler = $('#some_table_id');
        this.data = [];
        var self = this;


        this.getData = function () {
            return new Promise(function (resolve, reject) {
                $.post(base_url + 'controller/action', {
                    action_type: 'get_items'
                }, function (data) {
                    self.prepareData(data).then(resolve());
                }, "json");
            });
        };
        this.prepareData = function (data) {
            return new Promise(function (resolve, reject) {
                for (var x = 0; x < data.length; x++) {
                    self.data.push(
                        new Item(data[x])
                    );
                }
            });
        };
        this.updateTable = function () {
            for (var x = 0; x < self.data.length; x++) {
                self.someHandler.append(self.data[x].generateTrDOM());
            }

        };
    }

    var data = new ItemsCollection();
    data.getData() //this is done second
        .then(
            data.updateTable(); //this is done first - i dont not want to
        );
});

I want to data.updateTable() took place after the data.getData() after AJAX request but its start before. I read about the promises and in my other project its worked very well.

Which I did not understand. Thanks for some advices.

Upvotes: 3

Views: 113

Answers (2)

Taki
Taki

Reputation: 17654

try to avoid nested promises to keep your async code linear.

check this post : Are nested promises normal in node.js? ( i know this is not node but it's the same idea :P )

and to do so, you'll need to call getData, resolve it, then call prepareData and resolve it , then updateTable like :

jQuery(function ($) {
    function Item(val) {
        this.val = val
        var self = this;
        this.generateTrDOM = function () {
            var tr = '<tr>';
            tr += '<td>' + self.val + '</td>';
            tr += '</tr>';
            return tr;
        };
    }

    function ItemsCollection() {
        this.someHandler = $('#some_table_id');
        this.data = [];
        var self = this;


        this.getData = function () {
            return new Promise(function (resolve, reject) {
                $.post(base_url + 'controller/action', {
                    action_type: 'get_items'
                }, function (data) {
                    resolve(data); 
                }, "json");
            });
        };

        this.prepareData = function (data) {
            return new Promise(function (resolve, reject) {
                for (var x = 0; x < data.length; x++) {
                    self.data.push(
                        new Item(data[x])
                    );
                }               
                resolve(self.data);
            });
        };

        this.updateTable = function (data) {
            for (var x = 0; x < self.data.length; x++) {
                self.someHandler.append(data[x].generateTrDOM());
            }
        };
    }

    var data = new ItemsCollection();

    data.getData()
        .then((result) => {
            return data.prepareData(result);            
        })  
        .then((prearedData) => {
            return data.updateTable(prearedData); 
        });
});

here's a working fiddle for that https://jsfiddle.net/aejvsxke/5/ ( i replaced your $post with a $.get to a fake api and added console.log in each function for testing purposes, so you can see the order of the execution )

use this to compare the two codes and see the differences : https://www.diffchecker.com/diff

hint : for this.getData you can return the $.post directly as it returns a promise itself (no need to wrapp it in a promise and no need for the callback ) as of jQuery 1.5 : https://api.jquery.com/jquery.post/

so it becomes like this :

this.getData = function () {
    return $.post(base_url + 'controller/action', {
                action_type: 'get_items'        
            }, "json"); 
};

i hope this resolves your problem ;) or at least gives you an idea :P

Upvotes: 1

Stef Ch&#228;ser
Stef Ch&#228;ser

Reputation: 2058

This should fix the problem. As jfriend00 said, you have to pass a function reference to then(..). If you pass data.updateTable() to then(..) the function is executed immediately.

var data = new ItemsCollection();
data.getData()
  .then(data.updateTable);

Upvotes: 2

Related Questions