Backbone:在View中使用Model的数据和功能

时间:2015-06-24 09:47:50

标签: javascript backbone.js parse-platform model coffeescript

我对Backbone相当陌生,并且想知道如何从将模型注入依赖关系的视图中访问模型的数据和函数。

我的模型看起来像这样:

countries.coffee

define [
  'underscore'
  'backbone'
  'parse'
], (_, Backbone, Parse) ->
  'use strict';

  class CountriesModel extends Parse.Object

    countries: ['GB','US','FR','JP','WL','ZM','NG']

    returnCode = (code) ->
      return code

我的观点如下:

country.coffee

define [
  'jquery'
  'underscore'
  'backbone'
  'templates'
  'models/projects'
  'models/countries'
], ($, _, Backbone, JST, CountriesModel, ProjectModel) ->
  class CountryView extends Backbone.View

    ...

    console.log countries

    returnCode(4)

我将CountriesModel作为依赖项注入,但是当我调用该函数或记录countries时,我收到以下错误:

Uncaught ReferenceError: returnCode is not defined

我无法弄清楚我做错了什么。任何帮助表示赞赏。提前谢谢!

更新

我已更新上面的代码以提供更多上下文。

我正在尝试创建一个可重复使用的模型(CountriesModel),因此我可以在我的应用中的不同视图上访问countries数组和returnCode函数。但我无法弄清楚如何在CountryView上访问它们。

我的CountryView已经需要一个模型ProjectModel,我可以像这样调用ProjectModel中的函数和数组:

this.model.exampleArray
 this.model.exampleFunction()

我无法理解我如何从CountriesModel调用函数或数组。

任何人都知道我做错了什么?

3 个答案:

答案 0 :(得分:4)

我认为在这种特殊情况下,您可以创建一个模型" countryModel"和骨干收藏" countriesCollection"。但这可能不是您问题的本质(您的更新表明您在模型的可重用性方面存在困难)所以我在答案中不会考虑到这一点。
我不知道coffeescript,但我会详细说明使用Javascript 答案实际上是技术上在实例化期间通过options参数将模型传递给视图。

我认为使用presenter对象来管理特定的视图组总体上是一个好主意。此对象将实例化相关的视图,并且如您所述,允许将countriesModel的实例注入此演示者。
想象一下,假设您有一个webapp,它会呈现一个地图和列表,其中包含需要您出于某种原因描述的模型的地方。您可以使用如下代码:

var countriesModel = new CountriesModel(); 

var headerPresenter = new HeaderPresenter(); 
var mapPresenter = new MapPresenter(countriesModel); 
var listPresenter = new ListPresenter(countriesModel); 

只会将模型实例化一次,并将实例注入需要它的演示者。 在presenter对象中,您可以立即访问传递的模型上设置的属性/方法。

此方法可让您快速识别哪些演示者需要可重复使用的模型 如果您需要新演示者中的组件,也很容易将其传入。
然后,在演示者中,您仍然可以选择具体要发送模型的视图。

EG。列出主持人:

function listPresenter(countriesModel){ 
    this.listView = new ListView({ "model": countriesModel); 
    //More views can be added with the same model instance 
}; 

无论是在视图还是演示者中,您都可以在模型上侦听事件,执行其方法并重新渲染视图。
我个人从演示者那里管理这个逻辑,因为这是我使用其他注入的服务和组件来执行的地方,例如。服务器调用或可能对不同视图通用的特定计算。通过将事件聚合器传递给每个视图实例,可以轻松地为不同视图处理此公共逻辑。视图会触发自定义事件以执行所需操作,演示者将侦听自定义事件,执行所需逻辑并(重新)呈现视图。
我更喜欢保持视图干净并专注于DOM交互/ DOM事件绑定。

Sidenote :Backbone Marionette提供了一个应用级事件聚合器,可以节省将事件聚合器单独传递到每个视图的痛苦。
通过使用以下语法从演示者呈现视图也是一个非常方便的库:

var someView = new SomeView(); 
var region = new Marionette.Region({ el: "#some-region" }); 
region.show(someView); 

使用Marionette区域重新显示视图是内存安全的。

希望这有任何帮助。

答案 1 :(得分:3)

TBH我真的不明白为什么你要把你的模特用作代表。一个好的视图应该从模型中抽象出来,模型应该从路径附加到视图中。

// this goes in your view file
var CountryView = Backbone.view.extend({
    // here goes all the view logic to display the model data
    // you can refer to your model using this.model
})

...
// in the router file
var myModel = new CountriesModel();

var router = Backbone.router.extend({
    routes: {
        "": home,
        "home": home
    },
    home: function (){
       var view = new CountryView({ model: myModel});
       view.render(); //if you didn't rendered the view in the initialize method
    }
})

您可以在视图中访问另一个在运行时在路由器中附加它的模型

...
// in the router file
var myModel = new CountriesModel();
var anotherModel = new ProjectModel();


var router = Backbone.router.extend({
    routes: {
        "": home,
        "home": home
    },
    home: function (){
       var view = new CountryView({
                               model: myModel
                               anotherModel: anotherModel
                               });
       view.render(); //if you didn't rendered the view in the initialize method
    }
})

并在CountryView中将其附加到初始化函数

initialize: function (options){
    this = _.extend(options, this)
    // or
    // this.anotherModel = options.anotherModel
    // this.model = options.model
}

但是你不应该在视图中混合模型,只需为projectModel创建另一个视图并在需要时使用它们

// something like
var countryView = new CountryView({model: myModel});
var projectView = new ProjectView({model: anotherModel});

并从路由器中将它们一起渲染

答案 2 :(得分:3)

在您的视图中,您可以实例化除this.model处引用的模型之外的模型。 E.g:

var SomeView = Backbone.View.extend({

    initialize: function() {
        this.countriesModel = new CountriesModel();

        // Anywhere in your view do stuff with `this.countriesModel`. E.g:
        // this.listenTo(this.countriesModel, ...)
        // this.countriesModel.fetch()
        // etc
    }

});