淘汰,Web API&SignalR-未捕获类型错误

Knockout, Web API & SignalR - Uncaught TypeError

本文关键字:类型 错误 SignalR- Web API amp 淘汰      更新时间:2023-09-26

我试图为我的observableArray的一个元素设置一个值,但得到了一个我无法解决的错误:

Uncaught TypeError: Property 'Locked' of object #<Object> is not a function 

这是我写的一段代码:

$(function () {
    // -----------------------------------------------------------------------//
    // ** brand - model ** //
    // -----------------------------------------------------------------------//
    var Brand = function (e) {
        var self = this;
        self.Id = ko.observable(e ? e.Id : '');
        self.Name = ko.observable(e ? e.Name : '').extend({ required: true });
        self.Description = ko.observable(e ? e.Description : '');
        self.LogoId = ko.observable(e ? e.LogoId : '');
        self.Logo = (e ? (e.LogoId != null ? ko.observable(new Logo(e.Logo)) : null) : null);
        self.DisplayOrder = ko.observable(e ? e.DisplayOrder : '');
        self.Deleted = ko.observable(e ? e.Deleted : '');
        self.State = ko.observable(e ? e.State : '');
        self.DateChanged = ko.observable(e ? e.DateChanged : '');
        self.DateCreated = ko.observable(e ? e.DateCreated : '');
        self.Locked = ko.observable(e ? e.Locked : '');
        // validation
        self.Errors = ko.validation.group(self);
        self.IsValid = function () {
            if (self.Errors().length > 0) {
                self.Errors.ShowAllMessages();
                return false;
            }
            return true;
        };
    };

    // -----------------------------------------------------------------------//
    // ** logo - model ** //
    // -----------------------------------------------------------------------//
    var Logo = function (e) {
        var self = this;
        self.Id = ko.observable(e ? e.Id : '');
        self.FileName = ko.observable(e ? e.FileName : '');
        self.URL = ko.observable(e ? e.URL : '');
        self.PictureType = ko.observable(e ? e.PictureType : '');
        self.Deleted = ko.observable(e ? e.Deleted : '');
        self.State = ko.observable(e ? e.State : '');
        self.DateChanged = ko.observable(e ? e.DateChanged : '');
        self.DateCreated = ko.observable(e ? e.DateCreated : '');
    };

    // -----------------------------------------------------------------------//
    // ** view - model ** //
    // -----------------------------------------------------------------------//
    var BrandViewModel = function (hub) {
        // init
        var self = this;
        var url = "/api/brand/brands";
        // public data properties
        self.Brands = ko.observableArray([]);
        self.NewBrand = ko.observable(new Brand());
        // -----------------------------------------------------------------------//
        // ** Web API Actions ** //
        // -----------------------------------------------------------------------//
        // load
        self.Load = function () {
            // block
            self.BlockBrands();
            // Initialize the view-model
            $.ajax({
                url: url,
                type: 'GET',
                contentType: 'application/json; charset=utf-8',
                success: function (data) {
                    // add brands
                    self.Brands(data);
                    // tooltip
                    self.InitTooltip();
                },
                error: function (err) {
                    self.ShowError(err);
                },
                complete: function () {
                    self.UnblockBrands();
                }
            });
        }

        // -----------------------------------------------------------------------//
        // ** SignalR Actions ** //
        // -----------------------------------------------------------------------//
        self.LockItem = function (id) {
            // find item
            var brand = self.getBrandById(id);
            brand.Locked(true);
        }
        self.UnlockItem = function (id) {
            // find item
            var brand = self.getBrandById(id);
            brand.Locked(false);
        }
        // -----------------------------------------------------------------------//
        // ** Utilities ** //
        // -----------------------------------------------------------------------//
        self.getBrandById = function (Id) {
            return ko.utils.arrayFirst(self.Brands(), function (item) {
                if (item.Id == Id) {
                    return item;
                }
            });
        }

        self.Load();
    };
    // -----------------------------------------------------------------------//
    // ** init ** //
    // -----------------------------------------------------------------------//
    var hub = $.connection.brand;
    var brandViewModel = new BrandViewModel(hub);
    // -----------------------------------------------------------------------//
    // ** signalR ** //
    // -----------------------------------------------------------------------//

    hub.client.LockItem = function (id) {
        brandViewModel.LockItem(id);
    }
    hub.client.UnlockItem = function (id) {
        brandViewModel.UnlockItem(id);
    }
    $.connection.hub.start();
    // -----------------------------------------------------------------------//
    // ** knockout ** //
    // -----------------------------------------------------------------------//
    // knockout validation
    ko.validation.configure({
        insertMessages: true,
        decorateElement: true,
        errorElementClass: 'error'
    });
    // knockout binding
    ko.applyBindings(brandViewModel);
});

HTML-淘汰绑定

<table data-bind="visible: Brands().length > 0" class="table table-striped table-bordered table-hover" id="brands">       
    <tbody data-bind="foreach: Brands">
        <tr>
            <td class="align-center">
                <!-- ko if: Logo -->
                <img data-bind="attr: { src: Logo.URL() + '?width=50&height=50' }" class="img-polaroid" />
                <!-- /ko -->
            </td>
            <td data-bind="text: Name()"></td>
            <td data-bind="date: DateChanged()" class="align-center"></td>
            <td class="align-center">
                <!-- ko ifnot: Locked -->
                <a data-bind="click: $root.Edit" class="btn blue tip" data-original-title="wijzigen"><i class="icon-edit"></i></a>
                <a data-bind="click: $root.ShowDeleteModal" class="btn red tip" data-original-title="verwijderen"><i class="icon-trash"></i></a>
                <!-- /ko -->
                <!-- ko if: Locked -->
                <div class="btn black"><i class="icon-lock"></i></div>
                <!-- /ko -->
            </td>
        </tr>
    </tbody>
</table>

我在赋值时做错了什么吗?我也试过这样做:brand.Locked=true。这一次我没有失误,但淘汰赛没有回应。

问题是,当您调用ko.utils.arrayFirst(self.Brands())时,您的Brands不再是observables,而是常规的javascript objects(将'Locked'作为属性,而不是observable函数),这是因为当您从服务器检索数据并将其推送到Brands数组中时,您不会用ko.observableArray包装它。

尝试:

success: function (data) {
              // add brands
              self.Brands(ko.observableArray(data));

在您的getBrandById函数中:

self.getBrandById = function (Id) {
            return ko.utils.arrayFirst(self.Brands(), function (item) {
                if (item.Id() == Id) {
                    return item;
                }
            });

编辑:

实际上,由于Brands数组包含Brand对象,因此ko.observableArray还不足以将每个Brand的内部属性转换为obversable。您需要使用mapping插件,如下所示:

success: function (data) {
             // add brands
             self.Brands = ko.mapping.fromJS(data);

点击此处了解更多关于ko.utils.mapping插件的信息。