Backbone Collection.fetch给了我Uncaught TypeError:object不是一个函数

时间:2013-06-19 05:58:20

标签: backbone.js collections

我正在使用BackboneRequireJS个库的lo-dash应用,一切正常,但我遇到了将json数据设置为{{{}的问题1}}对象。

Collection配置:

RequireJS

我的require.config({ baseUrl: 'js', paths: { // Aliases for libraries, so that we can change versions from here jquery: 'libs/jquery-1.10.min', // Lo-Dash is a better drop-in replacement for Underscore: http://lodash.com/ lodash: 'libs/lodash-1.2.0.min', requireLib: 'libs/require-2.1.6-min', almondLib: 'libs/almond-0.2.5', backbone: 'libs/backbone-1.0.0.min', less:'libs/less-1.4.0.min' }, shim: { 'backbone': { //These script dependencies should be loaded before loading //backbone.js deps: ['lodash', 'jquery'], //Once loaded, use the global 'Backbone' as the //module value. exports: 'Backbone' } }, // This is appended to every module loading request, for cache invalidation purposes urlArgs: "bust=" + (new Date()).getTime() });

page.html

这是我的<script type="text/javascript"> require(["app/views/catalog"], function (Catalog) { var app = new Catalog.App(); }); //require(['libraries', 'cs!auth-main']); </script>

Model

这是我的define([ 'jquery', 'lodash', 'backbone' ], function ($, _, Backbone) { var CatalogModel = {}; CatalogModel.App = Backbone.Model.extend({ defaults: { name: "Catalog without name", userdata: false, documents: false }, initialize:function () { console.log("Model - App.initialize"); this.on("change", function () { console.log("Model - App.change"); }); }, url:"json/logged_data.json" }); CatalogModel.User = Backbone.Model.extend({ defaults: { username: "Default username" }, initialize: function () { console.log("Model - User.initialize"); this.on("change", function () { console.log("Model - User.change"); }); } }); CatalogModel.Document = Backbone.Model.extend({ defaults: { name: "Default catalog name", status: { url: "#", ready: false, downloadableProductUrl: "#" } }, initialize: function () { //console.log("CatalogModel.DocumentBrowse.initialize"); this.on("change", function () { console.log("Model - Document.change"); }); } }); CatalogModel.Asset = Backbone.Model.extend({ defaults: { nodeType:"folder", name:"Default folder name", url:false, treeId:"0", collection:false }, initialize: function () { console.log("Model - Asset.initialize"); this.on("change", function () { console.log("Model - Asset.change"); }); } }); return CatalogModel; } );

Collection

这是我的define([ 'jquery', 'lodash', 'backbone', 'app/models/catalog' ], function ($, _, Backbone, CatalogModel) { var CatalogCollection = {}; CatalogCollection.DocumentsList = Backbone.Collection.extend({ initialize: function () { console.log("Collection - DocumentsList.initialize"); this.model = new CatalogModel.Document(); this.on("add", function () { console.log("Collection - DocumentsList.add"); }); } }); CatalogCollection.AssetsList = Backbone.Collection.extend({ initialize: function () { console.log("Collection - AssetsList.initialize"); this.model = new CatalogModel.Asset(); this.on("add", function () { console.log("Collection - AssetsList.change"); }); }, parse: function(response) { console.log("Collection - AssetsList.parse"); //console.log(response); return response; }, url:"json/assets_nodes.json" }); return CatalogCollection; } );

Views

这是我的控制台日志:

define([
'jquery',
'lodash',
'backbone',
'app/models/catalog',
'app/collections/catalog',
'libs/text!app/templates/account_bar.html',
'libs/text!app/templates/document_browser.html',
'libs/text!app/templates/document_editor.html',
'libs/text!app/templates/document_name.html',
'libs/text!app/templates/assets_nodes.html',
'libs/text!app/templates/assets_children.html'
// ,'libs/text!app/templates/assets_items.html'
],
function ($, _, Backbone, CatalogModel, CatalogCollection, tmplAccountBar, tmplDocumentsBrowser, tmplDocumentEditor, tmplDocumentName, tmplAssetsNodes, tmplAssetsChildren) {

    var Catalog = {};

    Catalog.App = Backbone.View.extend({
        el: $("#catalog"),
        initialize: function() {
            console.log("View - App.inizialize");

            this.tmplDocumentEditor = tmplDocumentEditor;

            // here i'll set subviews for user bar, doc browser, assets list and book editor
            this.UserBarSubView = new Catalog.UserBarView();
            this.DocumentsBrowserSubView = new Catalog.DocumentsBrowserView();
            this.AssetsBrowserSubView = new Catalog.AssetsBrowserView();

            this.UserBarSubView.parent = this;
            this.DocumentsBrowserSubView.parent = this;
            this.AssetsBrowserSubView.parent = this;

            this.model = new CatalogModel.App();
            this.listenTo(this.model, "change", this.updateMainRequest);
            this.model.fetch(null);
        },
        updateMainRequest: function(data){
            var data = this.model.toJSON();

            console.log("View - App.updateMainRequest");
            //console.log(data.documents);

            this.UserBarSubView.model.set(data.userdata);

            var documents = [];
            for (var i = data.documents.length - 1; i >= 0; i--) {
                documents.push(new CatalogModel.Document(data.documents[i]));
            };
            this.DocumentsBrowserSubView.collection.set(documents);
        },
        createDocument: function() {
            console.log("View - App.createDocument");
            var name = this.model.get("name");
            //console.log(name);
            this.renderDocumentEditor(name);
        },
        editDocument: function(index) {
            console.log("View - App.editDocument");
            console.log(index);
        },
        renderDocumentEditor: function(name) {
            console.log("View - App.renderDocumentEditor");
            this.$el.find("#docs-browser").remove();
            this.$el.append(this.tmplDocumentEditor);

            this.AssetsBrowserSubView.renderDocumentName({name:name});
            this.AssetsBrowserSubView.collection.fetch();
            /*
            this.$el.find("#assets").html("assets creato dinamicamente");
            this.$el.find("#document-opened").html("doc opened creato dinamicamente");
            */
        }
    });

    Catalog.UserBarView = Backbone.View.extend({
        initialize: function() {
            console.log("View - UserBar.inizialize");
            this.template = tmplAccountBar;
            this.model = new CatalogModel.User();

            // data updates will be managed from Catalog.App
            this.listenTo(this.model, "change", this.render);
        },
        render: function() {
            console.log("View - UserBar.render");
            var accountBar = _.template(this.template, this.model.toJSON());
            this.parent.$el.append(accountBar);
            return;
        }
    });

    Catalog.DocumentsBrowserView = Backbone.View.extend({
        el: $("#catalog"),
        events: {
            "click #new-document": "createDocument",
            "click .open-document": "editDocument"
        },
        initialize: function () {
            //_.bindAll(this, 'createDocument editDocument');
            console.log("View - BrowseDocuments.initialize");

            // template shoud be in the page wrapped inside this tag:
            // <script id="template-test" type="text/template">...</script>

            this.template = tmplDocumentsBrowser;

            this.collection = new CatalogCollection.DocumentsList();

            console.log(this.collection);

            // data updates will be managed from Catalog.App
            this.listenTo(this.collection, "add", this.render);
        },
        createDocument: function() {
            console.log("View - BrowseDocuments.createDocument")
            this.parent.createDocument();
        },
        editDocument: function() {
            //var model = this.collection.get(1);
            //console.log(model.name);
            this.parent.editDocument(-1);
        },
        render: function() {
            console.log("View - BrowseDocuments.render");
            //console.log(this.collection.toJSON());
            var documentsList = _.template(this.template, {documents:this.collection.toJSON()})
            this.parent.$el.append(documentsList);
            this.delegateEvents();
            return;
        }
    });

    // View for assets to place in the catalog will be managed by something like DocumentEditor
    Catalog.AssetsBrowserView = Backbone.View.extend({
        el: $("#catalog"),
        events: {
            "click .folder-closed > div": "openFolder",
            "click .folder-opened > div": "statusClosedFolder"
        },
        initialize: function() {
            console.log("View - AssetsBrowser.initialize");
            //console.log(data);

            this.collection = new CatalogCollection.AssetsList();

            // set in openFolder to get where to place renderChildren
            this.$currentTarget = null;
            this.parentTreeId = false;

            this.tmplAssetsNodes = tmplAssetsNodes;
            this.tmplAssetsChildren = tmplAssetsChildren;
            this.tmplDocumentName = tmplDocumentName;

            // data updates will be managed from Catalog.App
            this.listenToOnce(this.collection, "add", this.renderNodes);
            this.listenTo(this.collection, "add", this.appendList);
        },
        openFolder: function(e) {
            this.$currentTarget = $(e.currentTarget).parent();

            //console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ");
            //console.log($(e.currentTarget).html());
            if (this.$currentTarget.find(" > ul").length === 0) {
                console.log("View - AssetsBrowser.openFolder currentTarget DOESN'T have children");
                //console.log(this.$currentTarget.html());
                this.parentTreeId = this.$currentTarget.data("id");

                console.log(this.collection);

                var item = this.collection.where({treeId: this.parentTreeId});
                this.collection.url = item.url;
                this.collection.fetch({success: function(){
                    console.log("got the data"); // => 2 (collection have been populated)
                }});
                this.statusLoadingFolder();
            } else {
                console.log("View - AssetsBrowser.openFolder currentTarget ALLREADY have children");
                //console.log(this.$currentTarget.html());
                this.statusOpenedFolder();
            }
        },
        appendList: function (data) {
            //this.fullCollection = this.fullCollection.push(data);
            console.log("View - AssetsBrowser.appendList");
            //console.log("data.length: " + data[0])

            //var list = $.parseJSON();
            //this.fullItemList = this.fullItemList.concat(this.collection.attributes);

        },
        statusLoadingFolder: function () {
            console.log("View - AssetsBrowser.statusLoadingFolder");
            // change it with a loader
            this.$currentTarget.removeClass("folder-closed").addClass("folder-opened");
            this.$currentTarget.find(".assets-sprite").removeClass("sprite-folder-closed").addClass("sprite-folder-opened");
        },
        statusOpenedFolder: function () {
            // change the css selectors from closed tab to opened tab
            console.log("View - AssetsBrowser.statusOpenedFolder");
            this.$currentTarget.removeClass("folder-closed").addClass("folder-opened");
            this.$currentTarget.find(".assets-sprite").removeClass("sprite-folder-closed").addClass("sprite-folder-opened");
        },
        statusClosedFolder: function (e) {
            var $target = $(e.currentTarget).parent();
            console.log("View - AssetsBrowser.statusClosedFolder");
            //this.$currentTarget.find("ul").remove();
            //console.log(this.$currentTarget);
            $target.removeClass("folder-opened").addClass("folder-closed");
            $target.find(".assets-sprite").removeClass("sprite-folder-opened").addClass("sprite-folder-closed");
        },
        renderDocumentName: function(data) {
            var documentName = _.template(this.tmplDocumentName, data);
            if (this.parent.$el.find("#catalog-name").length === 0) {
                this.parent.$el.find("#assets").prepend(documentName);
            } else {
                this.parent.$el.find("#catalog-name").html(documentName);
            }
        },
        renderNodes: function(data) {
            console.log("View - AssetsBrowser.renderNodes");
            //console.log(this.collection.attributes);
            //this.appendList(this.collection.attributes);
            this.listenTo(this.collection, "add", this.renderChildren);
            //console.log("Catalog.AssetsBrowserView.renderNodes");

            var assetsNodes = _.template(this.tmplAssetsNodes, {nodes:this.collection.toJSON()});
            if (this.parent.$el.find("#assets-browser").length === 0) {
                this.parent.$el.find("#assets").append(assetsNodes);
            } else {
                this.parent.$el.find("#assets-browser").html(assetsNodes);
            }
            this.delegateEvents();
            return;
        },
        renderChildren: function() {
            this.statusOpenedFolder();

            var parentTreeId = this.parentTreeId;

            _.each(this.collection.toJSON(), function (model) {
                model.treeId = parentTreeId;
                console.log(model);
            });

            //this.appendList(this.collection.attributes);
            console.log("View - AssetsBrowser.renderChildren");

            var assetsChildren = _.template(this.tmplAssetsChildren, {items:this.collection.toJSON()});
            this.$currentTarget.find("ul").remove();
            this.$currentTarget.append(assetsChildren);
            this.delegateEvents();

            //console.log(this.collection.toJSON());

            return;
        }
    });

    return Catalog;
}
);

我的View - BrowseDocuments.render catalog.js:126 View - BrowseDocuments.createDocument catalog.js:117 View - App.createDocument catalog.js:54 View - App.renderDocumentEditor catalog.js:64 Collection - AssetsList.parse catalog.js:30 Uncaught TypeError: object is not a function 查看方法中的Collection似乎存在问题。

App.renderDocumentEditor

我在这里遇到了同样的问题,我通过将renderDocumentEditor: function(name) { console.log("View - App.renderDocumentEditor"); this.$el.find("#docs-browser").remove(); this.$el.append(this.tmplDocumentEditor); this.AssetsBrowserSubView.renderDocumentName({name:name}); // collection.fetch() throws Uncaught TypeError: object is not a function this.AssetsBrowserSubView.collection.fetch(); } json的每个元素设置为Array的{​​{1}} Collection来解决它1}}声明:

Model

可能我错过了for应该如何使用的东西,我不敢相信我必须在使用{{updateMainRequest: function(data){ var data = this.model.toJSON(); console.log("View - App.updateMainRequest"); //console.log(data.documents); this.UserBarSubView.model.set(data.userdata); var documents = []; for (var i = data.documents.length - 1; i >= 0; i--) { documents.push(new CatalogModel.Document(data.documents[i])); }; this.DocumentsBrowserSubView.collection.set(documents); } 实例之前设置数组的每个元素。 1}}方法Collection

如果是,我该如何处理Model请求对服务器的响应?

1 个答案:

答案 0 :(得分:3)

您只是误解了Backbone Collections的model密钥。它应该是模型的模型不是实例。所以:

this.model = new CatalogModel.Asset();

应该是

this.model = CatalogModel.Asset;

(因此没有理由将它放在initialize方法中)。

现在,关于为什么。目标是为他们的模型提供Backbone Collections(构造函数),以便他们可以执行您不允许他们执行的操作:将对象转换为模型。
您肯定已经意识到Uncaught TypeError: object is not a function现在来自哪里:当您使用modelset时,Backbone会尝试使用fetch密钥的值:var model = new this.model(attrs, options); 。在您的情况下,this.model只是一个对象,因此new运算符自然会抛出一个错误,告诉您正在尝试将其与对象一起使用,而不是函数。