Backbone.js 基于url片段的状态管理/视图初始化

发布于 2024-11-09 16:18:31 字数 1523 浏览 0 评论 0原文

我正在尝试使用 Backbone.js 跟踪此应用程序中的状态:

在此处输入图像描述

我有一个“ ChartAppModel”具有一组默认值:

ChartAppModel = Backbone.Model.extend({

defaults: { 
    countries : [], 
    selectedCountries : [],
    year : 1970,
},

initialize: function() { 
    loadAbunchOfData();
    checkStartState();
}

});

如果给定一个开始片段,则应覆盖此默认状态:

var startState = $.deparam.fragment(); //using Ben Alman's BBQ plugin
this.set({selectedCountries: startState.s, year: startState.y});

现在,例如 SidebarView 已准备好更新:

ChartAppViewSidebar = Backbone.View.extend({

initialize: function(){
      this.model.bind("change:selectedCountries", this.render);
},

render : function(){
      [... render new sidebar with check boxes ...]
},

问题是我在侧边栏上还有一个更新模型的事件处理程序:

events: {
"change input[name=country]": "menuChangeHandler",
},

menuChangeHandler : function(){
      [... set selectedCountries on model ...]
},

所以就会有一个反馈循环...... 然后,我还想要一种推动新状态的方法 - 所以我会听取模型的变化:

ChartAppModel = Backbone.Model.extend({

initialize: function() { 
    this.bind("change", this.setState);
}

});

......并且很快这个状态管理器就会崩溃......

问题:

1)如何我是否根据片段初始化我的视图(例如“应检查哪些复选框”)? (任何关于不是典型“路线”的状态/开始状态最佳实践的提示都值得赞赏)

2)如何避免我的视图在它们自己监听的模型上设置属性?

3)如何根据模型的一部分推送新状态?

额外奖励 :)

4) 您将如何为所描述的应用程序编写代码?

谢谢!

I'm trying to keep track of the state in this app using Backbone.js:

enter image description here

I have a "ChartAppModel" with a set of defaults:

ChartAppModel = Backbone.Model.extend({

defaults: { 
    countries : [], 
    selectedCountries : [],
    year : 1970,
},

initialize: function() { 
    loadAbunchOfData();
    checkStartState();
}

});

If given a start fragment, this default state should however be overwritten:

var startState = $.deparam.fragment(); //using Ben Alman's BBQ plugin
this.set({selectedCountries: startState.s, year: startState.y});

Now, for example the SidebarView is ready to be updated:

ChartAppViewSidebar = Backbone.View.extend({

initialize: function(){
      this.model.bind("change:selectedCountries", this.render);
},

render : function(){
      [... render new sidebar with check boxes ...]
},

Problem is I also have an event handler on the sidebar that updates the model:

events: {
"change input[name=country]": "menuChangeHandler",
},

menuChangeHandler : function(){
      [... set selectedCountries on model ...]
},

So there will be a feedback loop ...
And then, I'd also like a way of pushing a new state - so I listen to model changes:

ChartAppModel = Backbone.Model.extend({

initialize: function() { 
    this.bind("change", this.setState);
}

});

... and relatively soon this state-manager will collapse ...

Questions:

1) How do I init my views (for example "which checkboxes should be checked") based on the fragment? (any hints on best practices for state / start state that is not a typical "route" are appreciated)

2) How can I avoid my views setting an attribute on the model which they themselves listen for?

3) How can I push a new state based on a part of the model?

Bonus :)

4) How would you lay out the code for the app described?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

等你爱我 2024-11-16 16:18:31

这是一个定义明确的问题!

这里有一个问题,什么是模型。我相信关于骨干世界中模型的构成存在一个定义,但我不确定您的策略是否符合该定义。此外,您还将状态存储在 url 和模型中。您可以将状态存储在 url 中,我将对此进行解释。

如果我这样做,就会有两种观点。一个用于您的应用程序控件,并嵌套在该控件内用于您的图形:GraphView 和 AppView。该模型将是您要绘制的数据,而不是界面的状态。

使用控制器启动应用程序视图并处理 url 中定义的任何界面状态。

Backbone 中存在一个关于状态杠杆的问题。传统的 Web 应用程序使用链接/url 作为状态的主要杠杆,但现在这一切都在改变。这是一种可能的策略:

Checkbox Change Event -> Update location fragment -> trigger route in controller -> update the view
Slider Change Event -> Update location fragment -> trigger route in controller -> update the view

这种策略的优点在于它可以处理 url 传递或添加书签的情况,

Url specified in address bar -> trigger route in controller -> update the view

我将尝试一个伪代码示例。为此,我将对数据做一些假设:
数据是随时间变化的狗的数量(以年份为粒度),其中滑块应具有下限和上限,并且数据量太大而无法一次将其全部加载到客户端。

首先让我们看一下表示统计数据的模型。对于图表上的每个点,我们需要类似 { Population: 27000, Year: 2003 }
让我们将其表示为该

DogStatModel extends Backbone.Model ->

数据的集合

DogStatCollection extends Backbone.Collection ->
    model: DogStatModel
    query: null // query sent to server to limit results
    url: function() {
        return "/dogStats?"+this.query
    }

现在让我们看看控制器。在我提出的这个策略中,控制器名副其实。

AppController extends Backbone.Controller ->
    dogStatCollection: null,
    appView: null,

    routes: {
         "/:query" : "showChart"
    },

    chart: function(query){
        // 2dani, you described a nice way in your question
        // but will be more complicated if selections are not mutually exclusive
        // countries you could have as countries=sweden;france&fullscreen=true
        queryMap = parse(query) //  
        if (!this.dogStatCollection) dogStatCollection = new DogStatCollection
        dogStatCollection.query = queryMap.serverQuery
        if (!this.appView) {
           appView = new AppView()
           appView.collection = dogStatCollection
        }
        appView.fullScreen = queryMap.fullScreen
        dogStatCollection.fetch(success:function(){
          appView.render()
        })            
    }

That is one well defined question!

There is a question over what is a model. I believe there is a definition floating around as to what constitutes a model in the backbone world, and I'm not sure your strategy is in keeping with that definition. Also you are storing the state in both the url, and the model. You can just store the state in the url, as I will explain.

If I was doing this, there would be 2 views. One for your app controls, and nested inside that one for your graph: GraphView, and AppView. The model will be the data your going to plot, not the state of the interface.

Use a controller to kick start the app view and also to process any interface state defined in the url.

There is a question about levers of state in Backbone. Traditional web applications used a link/url as the primary lever of state but all that is now changing. Here is one possible strategy:

Checkbox Change Event -> Update location fragment -> trigger route in controller -> update the view
Slider Change Event -> Update location fragment -> trigger route in controller -> update the view

The great thing about such a strategy is that it takes care of the case where urls are passed around or bookmarked

Url specified in address bar -> trigger route in controller -> update the view

I'll take a stab at a pseudo code example. For this, I will make some assumptions on the data:
The data is the dog population over time (with a granularity of year), where the slider should have a lower and upper bound, and there volume data is too large to load it all to the client at once.

First let's look at the Model to represent the statistical data. For each point on the graph we need something like { population: 27000, year: 2003 }
Lets represent this as

DogStatModel extends Backbone.Model ->

and a collection of this data will be

DogStatCollection extends Backbone.Collection ->
    model: DogStatModel
    query: null // query sent to server to limit results
    url: function() {
        return "/dogStats?"+this.query
    }

Now lets look at the controller. In this strategy I propose, the controller lives up to its name.

AppController extends Backbone.Controller ->
    dogStatCollection: null,
    appView: null,

    routes: {
         "/:query" : "showChart"
    },

    chart: function(query){
        // 2dani, you described a nice way in your question
        // but will be more complicated if selections are not mutually exclusive
        // countries you could have as countries=sweden;france&fullscreen=true
        queryMap = parse(query) //  
        if (!this.dogStatCollection) dogStatCollection = new DogStatCollection
        dogStatCollection.query = queryMap.serverQuery
        if (!this.appView) {
           appView = new AppView()
           appView.collection = dogStatCollection
        }
        appView.fullScreen = queryMap.fullScreen
        dogStatCollection.fetch(success:function(){
          appView.render()
        })            
    }
善良天后 2024-11-16 16:18:31

2)如何避免我的视图在它们自己监听的模型上设置属性?

你不知道。您的模型应该对您尝试更新的任何属性进行验证,以便您的视图需要进行侦听,以防您的属性设置失败或验证更改了值。

您的视图所做的是,它尝试在模型上设置一个值,然后模型要么设置它,要么更改数据并设置它,要么拒绝它。您的视图需要相应更新。

3)如何根据模型的一部分推送新状态?

// for each attribute
_.each(["attribute1", "attribute2", "attribute3", ...], _.bind(function(val) {
    // bind the change
    // bind the setState with `this` and the `value` as the first parameter
    this.bind("change:" + value, _.bind(this.setState, this, value));
}, this));

2) How can I avoid my views setting an attribute on the model which they themselves listen for?

You don't. Your model should be doing validation on any attributes you try to update so your view needs to listen in case your setting of the attribute failed or the validation changed the value.

What your view does is, it's tries to set a value on the model, the model then either sets it, changes the data and sets it, or rejects it. Your view needs to be updated accordingly.

3) How can I push a new state based on a part of the model?

// for each attribute
_.each(["attribute1", "attribute2", "attribute3", ...], _.bind(function(val) {
    // bind the change
    // bind the setState with `this` and the `value` as the first parameter
    this.bind("change:" + value, _.bind(this.setState, this, value));
}, this));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文