【问题标题】:ko.toJSON($root,null,2) return errorko.toJSON($root,null,2) 返回错误
【发布时间】:2013-01-11 21:12:22
【问题描述】:

我正在尝试使用<pre>标签调试ko(版本:2.2.1):

 <pre data-bind="text:ko.toJSON($root,null,2)"></pre>

但我明白了:

Uncaught Error: Unable to parse bindings.
Message: TypeError: Object object has no method 'getType';
Bindings value: text:ko.toJSON($root,null,2) 

更新:

似乎 $root 对象实际上是 windows 对象,为什么会发生,我如何确保它仍然在我的 ViewModel 范围内?

场景是这样的:

我有一个视图,其中还包含一个弹出模板。当用户单击按钮时,弹出窗口会显示,这就是我收到此错误的时候($root 失去了 ViewModel 范围并成为窗口对象)。

查看:

        <a  href="#" class="caspButton" data-bind="visible: editMode(), click:setEditMode">Done</a> 
        <!-- ko if: entities().length > 0 -->
        //THIS OPENS THE PROBLEMATIC POPUP
        <a href="#caspPopupAddEntities" class="caspButton caspPlus" data-bind="visible: editMode(), click:bindPopup.bind($root)"></a>
        <!-- /ko -->

        <!-- ko if: parentChildArr().length > 0 -->
        <a href="sp/book/addChildEntity" class="caspButton caspPlus"  data-bind="visible: editMode(),cafeHrefParam: {entity: 'entity',st:'st',parentEntityType: parentTypeName,parentPropName:parentPropName }" title="Add Entity" data-cafeDialog="popup"></a>
        <!-- /ko -->

        <header>
            <h2 class="caspFancy" data-bind="text: $root.title"></h2>
        </header>

        <div class="caspData">
            <!-- ko if: entities().length > 0 -->
            <ul data-bind="foreach: entities">
                <li data-bind="css: {caspEditable: $root.editMode(),caspListSeperator: !$root.editMode()}"> 
                    <a class="caspDelete caspPosition" href="#removeEntities" title="Delete" data-bind="visible: $root.editMode(),click: $root.bindPopup"
                    data-delete="true"></a>

                    <div class="caspInnerData">
                        <a class="caspBookLink" data-bind="attr: {href: 'sp/book/book' }, cafeHrefParam: { chapter: 'chapter', page: 'page', id: $data.id }, text: name,css: {caspBullet: !$root.editMode()}"></a>

                        <!-- ko if: shortDescription -->
                        <p data-bind="text: shortDescription"></p>
                        <!-- /ko -->
                    </div>
                    <!-- end .caspInnerData -->
                </li>
            </ul>
            <!-- /ko -->

            <!-- ko if: parentChildArr -->
            <ul data-bind="foreach: parentChildArr">
                <!-- ko if: children().length > 0 -->
                <li data-bind="css: {caspEditable: $root.editMode()}"> 

                    <div class="caspInnerData"> 
                    <div class="caspParent"> 
                        <span data-bind="text: $root.parentTypeName"></span> :
                         <a data-bind="attr: {href: 'sp/book/book' }, cafeHrefParam: { chapter: $root.parentTypeNamePlural, page: 'page', id: $data.id }, text: parent" class="caspBookLink"></a> 
                     </div>                   

                        <ul data-bind="foreach:children">
                            <li>
                                <a class="caspDelete" href="#removeEntities" title="Delete" data-bind="visible: $root.editMode(),click: $root.bindPopup"
                                data-delete="true"></a>

                                <a data-bind="attr: {href: 'sp/book/book' }, cafeHrefParam: { chapter: 'chapter', page: 'page', id: $data.id }, text: name" class="caspBookLink caspBullet"></a>                             
                            </li>
                        </ul>

                    </div>
                    <!-- end .caspInnerData -->
                </li>
                <!-- /ko -->
            </ul>
            <!-- /ko -->                

        </div>
        <!-- end .caspData -->

//HERE IS THE PROBLEM - '$root' becomes the windows object when i open this popup
 <div id="caspPopupAddEntities" data-role="popup" class="popup">
            <div class="caspBtnWrapper"> 

                <a href="#" data-role="button" class="caspButton cafeRight" data-bind="click:$root.saveEntity.bind($root)">Done</a>
                <a href="#" data-role="button" class="caspButton cafeLeft" data-bind="click:$root.cancel">Cancel</a>
            </div>
            <!-- end .caspBtnWrapper -->
            <header>
             <h1 class="caspFancy">Add New</h1>

         </header>
         <div class="caspDataWrapper" data-bind="with:$root.addItem()">
            <fieldset data-role="fieldcontain">
                <label for="title">Title</label>
                <input type="text" name="title" id="title" data-bind="value:name"
                />
            </fieldset>
            <fieldset data-role="fieldcontain">
                <label for="shortDescription">Overview</label>
                <textarea class="caspTextarea" type="text" name="shortDescription"
                id="shortDescription" data-bind="value:shortDescription" />
            </fieldset>
            <fieldset data-role="fieldcontain">
                <label for="mission">Mission</label>
                <textarea class="caspTextarea" type="text" name="mission"
                id="mission" data-bind="value:description" />
            </fieldset>
            <fieldset data-role="fieldcontain">
                <label for="period">Period</label>
                <input type="text" placeholder="  Set date and Time" name="period"
                id="period" data-bind="value:periodName" />
            </fieldset>
            <fieldset data-role="fieldcontain">
                <label for="ownedBy">Owned By</label>
                <input placeholder= "Select" type="text" name="ownedBy" id="ownedBy" data-bind="value:ownedBy,cafeAutoComplete: {source: 'users'}">
            </fieldset>
            <fieldset data-role="fieldcontain">
                <label for="assignedTo">Assigned to</label>
                 <input placeholder= "Select" type="text" name="assignedTo" id="assignedTo" data-bind="value:assignedTo,cafeAutoComplete: {source: 'users'}">
            </fieldset>
        </div>
        <!-- end .caspDataWrapper -->
    </div>
    <!-- end #caspPopupAddEntities -->



</div>
<!-- end content -->
</div>
<!-- end page -->

视图模型:

  /**
 * The module for the common Entities ViewModel
 */
define(['ko', 'komap', 'kopost', 'ca', 'sp/utils', 'sp/db'], function (ko, komap, kopost, ca, util, db) {

    /**
     * The Entities ViewModel.  This VM just exposes a collection of entities in a single property.
     * The model to retrieve is obtained from the last portion of the URL path.
     */

    function EntitiesViewModel(ctx, data) {
        this.init(ctx,data);

    }

    // EntitiesViewModel.prototype = new ca.ViewModel({});

    // EntitiesViewModel.prototype.constructor = EntitiesViewModel;

    ko.utils.extend(EntitiesViewModel.prototype,(function(){



        init = function(ctx,data){
            var self = this;
            strategyId = ctx.param.st;
            entitySet = db.getEntitySetFromElementType(ctx.param.entity);
                parentEntitySet = _getParentEntitySet(entitySet);                      
                childPropName = util.getChildEntityPropertyName(parentEntitySet);

            self.editMode = ko.observable(false);
            self.entities = ko.observableArray([]);
            self.parentChildArr = ko.observableArray([]);   
            self.users = ko.observableArray([]);

            self.parentPropName = util.getParentEntityPropertyName(entitySet);
            self.parentTypeName = util.getParentTypeName(entitySet);    
            self.parentTypeNamePlural = util.getPluralName(self.parentTypeName);

            self.title = ko.computed(function () {
                // temporary method to get the plural name.
                return util.getPluralName(entitySet.collectionName);
            });

            self.addItem = ko.observable(entitySet.addNew());
            self.addItem().name = ko.observable("");
            self.addItem().shortDescription = ko.observable("");
            self.addItem().mission = ko.observable("");
            self.addItem().period = ko.observable("");
            self.addItem().ownedBy = ko.observable("");
            self.addItem().assignedTo = ko.observable("");

            _loadData(self);
        },



        bindPopup = function (o, e) {
            openPopup(o, e);
            selectedEntity = o;
            var popupId = $(e.target).attr('href');
            ko.applyBindings(self, $('#overlay').find(popupId).get(0));
            db.User.toArray( this.users );
        },



        startEdit = function (o, e) {
            self.editMode(true);
            e.stopPropagation();
        },

        cancel = function (o, e) {  
            closePopup(o, e);
            this.addItem (entitySet.addNew());
        },




        saveEntity = function (o, e) {
            var self = this;
            var parent = parentEntitySet.addNew({ id: strategyId });
            parentEntitySet.attachOrGet(parent);

            var entity = {
                name: self.addItem().name,
                shortDescription: self.addItem().shortDescription,
                description: self.addItem().description
            }

            entity[self.parentPropName] = parent;

            var newEntity = entitySet.addNew(entity);
            entitySet.attachOrGet(newEntity);
            entitySet.add(newEntity);

            db.saveChanges().done(function (i) {
                closePopup(o, e);                               
                _loadData(self);
                self.addItem (entitySet.addNew());
                kopost.publish("ca.sp.entitiesChanged", "Add new Entity");

            }).fail(function (error) {
                self.addItem (entitySet.addNew());
                console.log('Error = ' + error);

            });

            //detach the entities after save to avoid having them saved again
            entitySet.detach(newEntity);
            parentEntitySet.detach(parent);

            e.stopPropagation();
        };


        return {
            init: init,
            setEditMode: setEditMode,
            bindPopup: bindPopup,
            cancelDelete: cancelDelete,
            startEdit: startEdit,
            cancel: cancel,
            deleteEntity: deleteEntity,
            saveEntity: saveEntity
        }

    }()));
    return EntitiesViewModel;
});

【问题讨论】:

  • 你能展示你的 ViewModel 以及你调用 ko.applyBindings 的位置吗?
  • @namkha87 - 这是大型应用程序的一部分,applyBindings 发生在外部控制器元素中。我会发布视图和虚拟机,但它们很大,所以我会尝试修剪不相关的部分
  • 可以用最新的KO v2.2.1试试吗?
  • @nemesv - 抱歉,我输入了错误的版本。我正在使用最新的更新问题。
  • 你能做一个小提琴吗?

标签: javascript knockout.js requirejs knockout-2.0


【解决方案1】:

$data 指上下文中的当前项目。一个简单的ko.toJSON($data) 应该会显示结果。

【讨论】:

  • 在您的视图模型的bindPopup 方法中,有对#overlay (ko.applyBindings(self, $('#overlay').find(popupId).get(0));) 的引用确保您的DOM 中存在具有该ID 的元素。如果它是由框架放置的,那么您将需要一个自定义绑定以使其与淘汰赛一起使用。以下是 jQuery UI 对话框的示例:stackoverflow.com/a/8611892/182875
猜你喜欢
  • 1970-01-01
  • 2015-08-25
  • 2014-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-14
  • 2019-06-12
  • 2021-01-28
相关资源
最近更新 更多