单一型号不显示路由器

Single model doesn't show with router

我看不懂怎么展示单品。当我想显示产品页面(模型视图 - app.ProductItemView in productPageShow)时,我得到 "Uncaught TypeError: Cannot read property 'get' of undefined at child.productPageShow (some.js:58)" >> this.prod = this.prodList.get(id);

这是我的代码:

// Models
var app = app || {};
app.Product = Backbone.Model.extend({
    defaults: {
        coverImage: 'img/placeholder.png',
        id: '1',
        name: 'Unknown',
        price: '100'
    }
});

app.ProductList = Backbone.Collection.extend({
    model: app.Product,
    url: 'php/listProducts.php'
});

// Views
app.ProductListView = Backbone.View.extend({
    el: '#product-list',
    initialize: function() {
        this.collection = new app.ProductList();
        this.collection.fetch({ reset: true });
        this.render();
        this.listenTo(this.collection, 'reset', this.render);
    },

    render: function() {
        this.collection.each(function(item) {
            this.renderProduct(item);
        }, this);
    },

    renderProduct: function(item) {
        app.productView = new app.ProductView({
            model: item
        });
        this.$el.append(app.productView.render().el);
    }
});

app.ProductItemView = Backbone.View.extend({
    tagName: 'div',
    template: _.template($('#productPage').html()),

    render: function(eventName) {
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    }
});

app.ProductView = Backbone.View.extend({
    tagName: 'div',
    template: _.template($('#productTemplate').html()),

    render: function() {
        this.$el.html(this.template(this.model.attributes));
        return this;
    }
});

// Router
app.Router = Backbone.Router.extend({
    routes: {
        "list": 'list',
        "product/:id": "productPageShow"
    },

    initialize: function() {
        this.$content = $("#product-list");
    },

    list: function() {
        this.prodList = new app.ProductList();
        this.productListView = new app.ProductListView({ model: this.prodList });
        this.prodList.fetch();
        this.$content.html(app.productListView.el);
    },

    productPageShow: function(id) {
        this.prod = this.prodList.get(id);
        this.prodItView = new app.ProductItemView({ model: this.prod });
        this.$content.html(this.prodItView.el);
    }
});

$(function() {
    new app.Router();
    Backbone.history.start();
});

代码存在一些概念性问题,没有深入细节,路由器中发生的很多事情不属于那里,但对于一个(当前)非复杂的应用程序来说是可管理的.

我将重点关注 app.Router 文件,因为这很可能是您遇到问题的罪魁祸首。

routes: {
    "list": 'list',
    "product/:id": "productPageShow"
}

让我们从基础开始,当您在 Backbone 路由器(或其他框架中的任何其他路由器)中定义路由列表时,您为路由提供了一个键,该键将对应于 [=76] 中的某些内容=] 路由器将识别并调用回调方法。

如果您将浏览器导航至:

http://your-url#list

Backbone 将调用 list 回调

类似地:

http://your-url#product/1

Backbone 将调用 productPageShow 回调

须知:只能调用一个路由回调! Backbone 路由器第一次找到匹配的路由时,它将调用该回调并跳过所有其他

在您的代码中,您依赖的事实是 this.prodList 将存在于 productPageShow 方法中,但这只会发生在您首先转到 list 路线然后到 product/{id}路线。

另一件事 .. 在路由器的 list 回调中,您在 ProductListView 实例上设置了 model .. 但是 model 既不是用户,也不是 model 因为 this.productListBackbone.Collection

此外,您需要知道 fetch 是一个异步操作,并且您没有使用任何回调来保证在需要时获得数据(除了依赖 'reset' 事件)。

所以这将是我尝试使其可行的方法:

// Models
var app = app || {};
app.Product = Backbone.Model.extend({
    defaults: {
        coverImage: 'img/placeholder.png',
        id: '1',
        name: 'Unknown',
        price: '100'
    }
});

app.ProductList = Backbone.Collection.extend({
    model: app.Product,
    url: 'php/listProducts.php'
});

// Views
app.ProductListView = Backbone.View.extend({
    el: '#product-list',
    initialize: function() {
        this.render();
        this.listenTo(this.collection, 'reset', this.render);
    },

    render: function() {
        this.collection.each(function(item) {
            this.renderProduct(item);
        }, this);
    },

    renderProduct: function(item) {
        app.productView = new app.ProductView({
            model: item
        });
        this.$el.append(app.productView.render().el);
    }
});

app.ProductItemView = Backbone.View.extend({
    tagName: 'div',
    template: _.template($('#productPage').html()),

    render: function(eventName) {
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    }
});

app.ProductView = Backbone.View.extend({
    tagName: 'div',
    template: _.template($('#productTemplate').html()),

    render: function() {
        this.$el.html(this.template(this.model.attributes));
        return this;
    }
});

// Router
app.Router = Backbone.Router.extend({
    routes: {
        "": "list",
        "product/:id": "productPageShow"
    },

    initialize: function() {
        this.$content = $("#product-list");
    },

    list: function() {
        this.prodList = new app.ProductList();
        this.productListView = new app.ProductListView({ collection: this.prodList });
        this.prodList.fetch({reset:true});
        this.$content.html(app.productListView.el);
    },

    productPageShow: function(id) {
        try {
            this.prod = this.prodList.get(id);
            this.prodItView = new app.ProductItemView({ model: this.prod });
            this.$content.html(this.prodItView.el);
        } catch (e) {
            // Navigate back to '' route that will show the list
            app.Router.navigate("", {trigger:'true'})
        }

    }
});

$(function() {
    app.Router = new app.Router();
    Backbone.history.start();
});

所以在没有完整图片的情况下在黑暗中拍摄了一点,这就是变化:

  • ProductListView 不再实例化在 Router
  • list 回调中完成的 ProductList 集合
  • 将路由从 'list' 更改为 '',这将保证列表立即显示
  • 如果 productPageShow 中没有可用的产品数据,请导航回 list