我似乎经常遇到这样的情况:我正在渲染一个 View ,但该 View 所依赖的模型尚未加载。大多数情况下,我只有从 URL 中获取的模型 ID,例如对于假设的市场应用程序,用户使用该 URL 登陆该应用程序:http://example.org/#/products/product0
在我的 ProductView , 我创建了一个 ProductModel并设置其 ID,product0然后我 fetch() .我用占位符渲染一次,当获取完成时,我重新渲染。但我希望有更好的方法。
在渲染任何东西之前等待模型加载感觉没有响应。重新渲染会导致闪烁,并且在各处添加“正在加载...请稍候”或微调器会使 View 模板变得非常复杂(特别是如果由于模型不存在而导致模型获取失败,或者用户无权查看这一页)。
那么,当您还没有模型时,渲染 View 的正确方法是什么?
我需要离开吗
来自标签 View 并使用 pushState ?服务器可以给我推一下吗?我都是耳朵。
从已经加载的页面加载:
我觉得当已经加载了一个页面而不是直接登陆 Product 时,您可以做更多的事情。页。
如果应用程序呈现指向产品页面的链接,例如呈现 ProductOrder收藏,还有什么可以做的吗?
<ul id="product-order-list">
<li>Ordered 5 days ago. Product 0 <a href="#/products/product0">(see details)</a></li>
<li>Ordered 1 month ago. Product 1 <a href="#/products/product1">(see details)</a></li>
</ul>
routes: {
'products/:productid': 'showProduct'
...
}
showProduct: function (productid) {
var model = new Product({_id: productid});
var view = new ProductView({model: model});
//just jam it in there -- for brevity
$("#main").html(view.render().el);
}
fetch() View 内部 initialize函数,并调用 this.render()来自 this.listenTo('change', ...)事件监听器。这会导致复杂的 render()案例,以及从视野中出现和消失的物体。例如,我的 View 模板 Product可能会为用户评论保留一些屏幕空间,但当且仅当产品上存在/启用评论时——并且在完全从服务器获取模型之前通常是不知道的。ProductView 中加载模型的 initialize , 与 this.model.fetch()并监听模型事件,我被迫渲染两次, - 一次之前使用空占位符(因为否则您必须盯着白页),一次之后。如果在加载过程中发生错误,那么我必须删除 View (出现闪烁/故障)并显示一些错误。 render() 是一个好习惯。显示一些微调器/加载指示器?collection.fetch() 加载collection.fetch() .如果该集合确实是 Product 的集合,那么渲染产品 View 就很容易了。Collection用于生成列表的可能不是 ProductCollection然而。可能是 ProductOrderCollection或其他仅包含对产品 ID 的引用(或足够数量的产品信息以呈现指向它的链接)的其他内容。Product通过 collection.fetch()如果 Product 也可能被禁止模型很大,尤其是。万一产品链接之一被点击。collection.fetch()对于直接导航到产品页面的用户来说,这种方法也没有真正解决问题......在这种情况下,我们仍然需要渲染 ProductView需要 Product 的页面仅从 id(或产品页面 URL 中的任何内容)获取的模型。
最佳答案
好的,所以在我看来,有很多方法可以解决这个问题。我将列出我想到的所有内容,希望有人能与您合作,或者至少会激发您找到最佳解决方案。
我并不完全反对 T J 的回答。如果您在网站加载时继续对所有产品执行 collection.fetch() 操作(用户通常希望涉及一些加载时间),那么您就拥有了所有数据,您可以像这样传递这些数据他提到。他的建议与我通常所做的唯一区别是,我通常在所有 View 中都引用了 app。所以,例如在我的 中初始化 函数在 app.js 我会做这样的事情。
initialize: function() {
var options = {app: this}
var views = {
productsView: new ProductsView(options)
};
this.collections = {
products: new Products()
}
// This session model is just a sandbox object that I use
// to store information about the user's session. I would
// typically store things like currentlySelectedProductId
// or lastViewedProduct or things like that. Then, I just
// hang it off the app for ease of access.
this.models = {
session: new Session()
}
}
initialize: function(options) {
this.app = options.app;
this.views = {
headerView: new HeaderView(options),
productsListView: new ProductsListView(options),
footerView: new FooterView(options)
};
}
render: function(everythingLoaded) {
var _this = this;
if(!!everythingLoaded) {
this.$el.html(_.template(this.template(this)));
}
else {
// load a spinner template here if you want a spinner
this.app.collection.products.fetch()
.done(function(data) {
_this.render(true);
})
.fail(function(data) {
console.warn('Error: ' + data.status);
});
}
return this;
}
render: function(everythingLoaded) {
var _this = this;
if(!!everythingLoaded) {
this.$el.html(_.template(this.template(this)));
}
else {
// load a spinner template here if you want a spinner
this.app.collection.products.fetch()
.done(function(data) {
_this.render(true).postRender(true);
})
.fail(function(data) {
console.warn('Error: ' + data.status);
});
}
return this;
},
postRender: function(everythingLoaded) {
if(!!everythingLoaded) {
// do any DOM manipulation to the products list after
// it's loaded and rendered
}
else {
// put code to start spinner
}
return this;
}
initialize: function(options) {
this.app = options.app;
this.productId = options.productId;
this.views = {
headerView: new HeaderView(options),
productsListView: new ProductsListView(options),
footerView: new FooterView(options)
};
}
render: function(everythingLoaded) {
var _this = this;
if(!!everythingLoaded) {
this.$el.html(_.template(this.template(this)));
}
else {
// load a spinner template here if you want a spinner
this.app.collection.products.get(this.productId).fetch()
.done(function(data) {
_this.render(true).postRender(true);
})
.fail(function(data) {
console.warn('Error: ' + data.status);
});
}
return this;
},
postRender: function(everythingLoaded) {
if(!!everythingLoaded) {
// do any DOM manipulation to the product after it's
// loaded and rendered
}
else {
// put code to start spinner
}
return this;
}
关于javascript - 在哪一点上获取 View 所依赖的主干模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33748907/
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("