te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - KnockoutJS Binding Issue - Cannot read property - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - KnockoutJS Binding Issue - Cannot read property - Stack Overflow

programmeradmin3浏览0评论

I have what is likely a simple Knockout question but I'm a plete beginner with it. I was tossed this page of code that someone else has worked on but never finished.

When this page first loads, the data is retrieved and the main grid loads properly. The problem es in when I attempt to auto-select the first record in the results so that a detail list gets filled out below the grid.

When that happens, I receive the following message.

Uncaught TypeError: Unable to process binding "text: function (){return selected.RequestLog.Timestamp }" , Message: Cannot read property 'Timestamp' of undefined

Here is the code snippets with which I'm working. The data ing back is from Entity Framework.

var siteLogModel = function () {
            var self = this;

            self.errorList = ko.observableArray([]);
            self.selected = ko.observable();

            self.updateErrorList = function (page) {
                jQuery.ajax({
                    type: "POST",
                    url: "/Admin/ErrorPage",
                    data: { pageNum: page },
                    success: function (result) {
                        self.errorList(result);
                        self.selected(result[0]);

                        // Since we have success, add the click handler so we can get the details about a row by id.
                        //addRowHandlers();
                    },
                    error: function (result) {
                        jQuery("#status").text = result;
                    }
                });
            };
        };

This is the actual binding that tries to happen after the data is loaded. RequestLog does not seem to exist at binding time, even though it does seem to be ok if I set a breakpoint in the above function on the line self.selected(result[0]).

I think this is a scope problem but I can't for the life of me think of how best to fix it. Any help would be appreciated.

    <div class="param">
       <span>Time</span>
       <label data-bind="text: selected.RequestLog.Timestamp"></label>
    </div>

UPDATE: Here is the document ready portion.

jQuery(document).ready(function () {

            var vm = new siteLogModel();
            vm.updateErrorList(0);
            ko.applyBindings(vm);
        });

I have what is likely a simple Knockout question but I'm a plete beginner with it. I was tossed this page of code that someone else has worked on but never finished.

When this page first loads, the data is retrieved and the main grid loads properly. The problem es in when I attempt to auto-select the first record in the results so that a detail list gets filled out below the grid.

When that happens, I receive the following message.

Uncaught TypeError: Unable to process binding "text: function (){return selected.RequestLog.Timestamp }" , Message: Cannot read property 'Timestamp' of undefined

Here is the code snippets with which I'm working. The data ing back is from Entity Framework.

var siteLogModel = function () {
            var self = this;

            self.errorList = ko.observableArray([]);
            self.selected = ko.observable();

            self.updateErrorList = function (page) {
                jQuery.ajax({
                    type: "POST",
                    url: "/Admin/ErrorPage",
                    data: { pageNum: page },
                    success: function (result) {
                        self.errorList(result);
                        self.selected(result[0]);

                        // Since we have success, add the click handler so we can get the details about a row by id.
                        //addRowHandlers();
                    },
                    error: function (result) {
                        jQuery("#status").text = result;
                    }
                });
            };
        };

This is the actual binding that tries to happen after the data is loaded. RequestLog does not seem to exist at binding time, even though it does seem to be ok if I set a breakpoint in the above function on the line self.selected(result[0]).

I think this is a scope problem but I can't for the life of me think of how best to fix it. Any help would be appreciated.

    <div class="param">
       <span>Time</span>
       <label data-bind="text: selected.RequestLog.Timestamp"></label>
    </div>

UPDATE: Here is the document ready portion.

jQuery(document).ready(function () {

            var vm = new siteLogModel();
            vm.updateErrorList(0);
            ko.applyBindings(vm);
        });
Share Improve this question edited Jan 22, 2014 at 20:31 Rob Horton asked Jan 22, 2014 at 18:41 Rob HortonRob Horton 8253 gold badges10 silver badges28 bronze badges 1
  • What does your result object look like? Also, there may be an issue with how you are using observableArray. There is no need to pass the constructor an empty array (though it probably won't hurt) and you can use self.errorList.push(result) to add values. – bigbangtheorem Commented Jan 22, 2014 at 18:47
Add a ment  | 

1 Answer 1

Reset to default 13

Your selected observable does not have a .RequestLog property at the time ko is evaluating the binding expression. That error is ing from javascript, not ko (though ko wraps the exception in the error message you see). When running, selected.RequestLog === undefined is true, and you can't invoke anything on undefined. It's like a null reference exception.

It makes sense if you are calling applyBindings before the ajax call finishes.

One way to fix this by doing a puted instead:

<div class="param">
   <span>Time</span>
   <label data-bind="text: selectedRequestLogTimestamp"></label>
</div>

self.selectedRequestLogTimestamp = ko.puted(function() {
    var selected = self.selected();
    return selected && selected.RequestLog
        ? selected.RequestLog.TimeStamp
        : 'Still waiting on data...';
});

With the above, nothing is ever being invoked on an undefined variable. Your label will display "Still waiting on data" until the ajax call finishes, then it will populate with the timestamp as soon as you invoke self.selected(result[0]).

Another way to solve it is by keeping your binding the same, but by giving the selected observable an initial value. You can leave all of your html as-is, and just to this:

self.selected = ko.observable({
    RequestLog: {
        TimeStamp: 'Still waiting on data'
    }
});

... and you will end up with the same result.

Why?

Any time you initialize an observable by doing something like self.prop = ko.observable(), the actual value of the observable is undefined. Try it out:

self.prop1 = ko.observable();
var prop1Value = self.prop1();
if (typeof prop1Value === 'undefined') alert('It is undefined');
else alert('this alert will not pop up unless you initialize the observable');

So to summarize what is happening:

  1. You initialize your selected observable with a value equal to undefined in your viewmodel.
  2. You call ko.applyBindings against the viewmodel.
  3. ko parses the data-bind attributes, and tries to bind.
  4. ko gets to the text: selected.RequestLog.Timestamp binding.
  5. ko invokes selected(), which returns undefined.
  6. ko tries to invoke .RequestLog on undefined.
  7. ko throws an error, because undefined does not have a .RequestLog property.

All of this happens before your ajax call returns.

Reply to ment #1

Yes, you can call applyBindings after your ajax success event. However, that's typically not always what you should do. If you want to, here's one example of how it could be done:

self.updateErrorList = function (page) {
    self.updateErrorPromise = jQuery.ajax({
        type: "POST",
        url: "/Admin/ErrorPage",
        data: { pageNum: page },
        success: function (result) {
            self.errorList(result);
            self.selected(result[0]);
        },
        error: function (result) {
            jQuery("#status").text = result;
        }
    });
};

jQuery(document).ready(function () {
    var vm = new siteLogModel();
    vm.updateErrorList(0);
    vm.updateErrorPromise.done(function() {
        ko.applyBindings(vm);
    });
});

Yet another way would be to go ahead and eager-bind (applyBindings before the ajax call finishes), but wrap your markup in an if binding like so:

<div class="param" data-bind="if: selected">
   <span>Time</span>
   <label data-bind="text: selected.RequestLog.Timestamp"></label>
</div>
发布评论

评论列表(0)

  1. 暂无评论