0

我正在开发一个Backbone带有库的应用程序RequireJSlo-dash一切正常,但在为我的对象设置json数据时遇到问题。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到它的CollectioninModel语句中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);
}

可能我错过了应该如何使用的东西,我不敢相信在使用方法之前Collection我必须将数组的每个元素设置为Model实例。Collectionset

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

4

1 回答 1

3

您只是误解了modelBackbone Collections 的关键。它应该是Model而不是 Model 的实例。所以:

this.model = new CatalogModel.Asset();

应该

this.model = CatalogModel.Asset;

(因此没有理由将其放入initialize方法中)。

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

于 2013-06-19T09:03:51.780 回答