data-bindingknockout.jsknockout-2.0knockout-templating

Uncaught ReferenceError: Unable to process binding "template: function (){return { foreach:third} }" Message: third is not defined in knockout js


I am still new to KnockoutJs, I am having an issue with data binding the table will have uncaught Reference error on binding..

I am calling data via ajax call and compared with another array and store the compared value in one variable. These variable should bind the value and display values in table. In this binding they caught an error, Uncaught ReferenceError: Unable to process binding "template: function (){return { foreach:third} }" Message: third is not defined..

My sample code is :

window.onload=function(){   
//setInterval(function() {
jQuery(function($){
    var ListSortModel = function () {
            var self = this;
            self.first = ko.observableArray([
                { "id": 101, "rank": 5},
                { "id": 103, "rank": 1},
                { "id": 102, "rank": 6},
                { "id": 106, "rank": 4}, 
                { "id": 104, "rank": 3},                    
                { "id": 105, "rank": 2}
            ]);

            self.second = ko.observableArray();
            //setInterval(function() {
            function myAjaxCheck(callback) {    
                $.getJSON("sample.php", function(data) {
                    console.log("ajax called");
                    self.second = JSON.stringify(data);
                    //console.log(self.second);

                    callback(data);


                }); 
            }
            //}, 3000); 

        var myVariable; 
        myAjaxCheck(function(returnedData){ //anonymous callback function
            myVariable = returnedData;
            //console.log(myVariable);
            //console.log(myVariable.length);

            //alert("outside ajax call");
            var a = self.first();
            console.log("First array "+JSON.stringify(a));
            ///var b = self.second();
            var b = myVariable;
            console.log("second array "+ JSON.stringify(b));
            console.log("1st array : "+a.length+ " 2nd array : " + b.length);

        //if(a.length == 0 && b.length == 0) {  
            var totallen = 0;
            if(a.length >= b.length){
                totallen = a.length;
            }else{
                totallen = b.length;
            }
            for(var i=0;i<a.length;i++)
                for(var k=0;k<b.length;k++)
                    if(a[i].id == b[k].id) {
                        if(a[i].rank > b[k].rank){
                            b[k].img = 0;
                        }else if(a[i].rank < b[k].rank){
                            b[k].img = 1;
                        }else if(a[i].rank == b[k].rank){
                            b[k].img = 2;
                        }
                        a.splice(i,1);
                        i--;
                        break;
                    }
            a = a.concat(b);
            console.log("Third array: " + JSON.stringify(a));

        //}

            for(i=0;i<totallen;i++){
                if(a[i].img == undefined){
                    if(a[i].rank < totallen){
                        a[i].img =0;
                    }else if(a[i].rank > totallen){
                        a[i].img = 1;
                    }else if(a[i].rank == totallen){
                        a[i].img = 2;
                    }
                }
            }

            a.sort(function(obj1,obj2) {
                return obj1.id > obj2.id;
            });     

            /* compared array values stored in third array */
            self.third = ko.observableArray(a);   // Error in binding value

            temp = 1;
            self.addImg = function(index) {       
                if(self.third()[index].img == 0){
                    return 'upImg';
                }else if(self.third()[index].img == 1){
                    return 'downImg';
                }
                else if(self.third()[index].img == 2){
                    return;
                }                       
            };      




            self.moveUp = function(item, cnt) {
                var prev = item.prev();
                if (prev.length == 0)
                    return;
                prev.css('z-index', 999).css('position','relative').animate({ top: item.height() * cnt }, 250);
                item.css('z-index', 1000).css('position', 'relative').animate({ top: '-' + prev.height() * cnt }, 300, function () {
                    prev.css('z-index', '').css('top', '').css('position', '');
                    item.css('z-index', '').css('top', '').css('position', '');
                    for (;cnt>1;cnt--)
                        prev=prev.prev();
                    item.insertBefore(prev);
                });
            }

            self.moveDown = function(item, cnt) {
                    var next = item.next();
                    if (next.length == 0)
                        return;
                    next.css('z-index', 999).css('position', 'relative').animate({ top: '-' + item.height() * cnt }, 250);
                    item.css('z-index', 1000).css('position', 'relative').animate({ top: next.height() * cnt }, 300, function () {
                        next.css('z-index', '').css('top', '').css('position', '');
                        item.css('z-index', '').css('top', '').css('position', '');
                        for (;cnt>1;cnt--)
                            next=next.next();
                        item.insertAfter(next);
                    });
            }

            /* sorting based on rank after display third array*/
            self.SortbyRank = function() {
                setTimeout(function(){
                    console.log("testData");
                    self.third().sort(function(obj1,obj2) {
                        return obj1.rank > obj2.rank;
                    });

                    //Animate after sorting as Sorting is multi fold and fast
                    self.third().forEach(element => {
                        //console.log("Array element is " + element.id + " rank " + element.rank + " Index is " + $("#id_"+element.id).index());
                        if (element.rank > ($("#id_"+element.id).index()+1)){
                            //setTimeout(function(){
                                self.moveDown($("#id_"+element.id), (element.rank - ($("#id_"+element.id).index()+1)));
                            //},1000);
                        } else if (element.rank < ($("#id_"+element.id).index()+1)){
                            //setTimeout(function(){
                                self.moveUp($("#id_"+element.id), (($("#id_"+element.id).index()+1) - element.rank));
                            //},1000);
                        }
                    });
                },1000);
            }           

            window.setInterval(function() { 
                self.SortbyRank(); 
            }, 5000);

            /* window.setInterval(function() { 
                self.third.valueHasMutated(); 
            }, 6000); */

        });
    };
    ko.applyBindings(new ListSortModel());
});     

//}, 5000);

} This is my script data and my sample json data is,

[
{ "id": 101, "rank": 5},
{ "id": 102, "rank": 6},                    
{ "id": 106, "rank": 1},
{ "id": 103, "rank": 4},
{ "id": 104, "rank": 2},
{ "id": 105, "rank": 3}]

I have bind values in table with data-bind: third, they do not bind the value in third array. what is the problem in this sample.

<div class="container-fluid tablebody" data-bind="template: { foreach: third }">
        <div class="row tablerow" data-bind="attr: {id: 'id_' + id }">
            <div class="col-sm-1 cell" data-bind='text: id'></div>
            <div class="col-sm-1 cell"  data-bind='text: rank, css: $parent.addImg($index())'></div>
            <!-- <div class="col-sm-1 cell" width="10%" id="testData" data-bind="css: $parent.addImg($index())"></div> -->
        </div>
    </div>

How to bind the third array values in table..


Solution

  • You are defining self.third not in the constructor, but in an async callback function.

    By the time knockout is applying its bindings, there is no third property on your viewmodel, because the ajax call hasn't yet completed.

    The solution is to define the observable property in the constructor, and set its values in the callback.

    Define first:

    // ...
    self.second = ko.observableArray();
    self.third = ko.observableArray(); // <-- define here, right after second
    // ...
    

    Set later:

    /* compared array values stored in third array */
    self.third(a); // <-- set here, by calling it