铁轨 + Backbone.js:访问视图中的对象时遇到问题
几天来遇到了backbone的问题,无法找到解决方法或在stackoverflow上找到解决方案。
我使用 Rails 3.1 + 最新的主干(+ Coffeescript):
这是我的一个视图作为示例(所有这些都存在相同的问题):
Blog.Views.Payment ||= {}
class Blog.Views.Payment.PaymentView extends Backbone.View
className: 'payment_method'
tagName: 'td'
events:
'click #renderPayment': 'renderPayment'
initialize: ->
# CAN'T access @options.payment_methods here
@options.payment_methods.bind(###stuff###)
render: ->
# CAN'T access @options.payment_methods here either...
$(@el).html ("### something with #{@options.payment_methods or @options.payment_methods.model}")
return @
updateView: ()->
# updating view stuff...
renderPayment: ->
# ACCESSING @options.payment_methods fine here!!!
if ($("#payment_details").length == 0)
$(@el).append("<ul id='payment_details'>
<li id='payment_type'>#{@options.payment_methods.get(1).get('payment_type')}</li>
</ul>
").effect("highlight", 700)
在前两种情况下,当我运行示例时,浏览器告诉我 @options. payment_methods 是未定义,第三种情况工作正常。
第二件事是我无法访问任何已经“硬编码”到页面中且不是由 Javascript 创建的 DOM 元素。我知道其中的原因,并且一直在 Stackoverflow 上阅读大量有关此问题的帖子,但我无法找到任何可行的解决方案。任何提示都非常感激。
此致, 菲尔
编辑: 看起来它与页面上对象的访问时间有关,类似于页面的硬编码 DOM 元素的访问。如果我按如下方式编辑我的视图,即使我之前可以在代码中访问@options. payment_methods,我也无法再访问它。
# changed "renderPayment" to "$(document).ready" or just "$" in coffeescript
$ ->
# ACCESS NOT possible anymore
if ($("#payment_details").length == 0)
$(@el).append("<ul id='payment_details'>
<li id='payment_type'>#{@options.payment_methods.get(1).get('payment_type')}</li>
</ul>
").effect("highlight", 700)
EDIT2:添加了我相应的路由器文件:(这只是backbone-rails gem示例“博客”的修改版本)
class Blog.Routers.PostsRouter extends Backbone.Router
initialize: (options) ->
@posts = new Blog.Collections.PostsCollection()
@posts.reset options.posts
# ... other collections
# fetch payment_methods collection
@payment_methods = new Blog.Collections.PaymentMethodsCollection()
@payment_methods.reset options.payment_methods
@payment_methods.fetch()
@model = ({posts: @posts, mails: @mails, addresses: @addresses, purchases: @purchases, payment_methods: @payment_methods})
routes:
"/new" : "newPost"
"/index" : "index"
"/:id/edit" : "edit"
"/:id" : "show"
".*" : "index"
# main view
index: ->
# render Product Info View
@view = new Blog.Views.Product.ProductView(purchases: @purchases)
$("#product_1").html(@view.render().el)
##### view etc.
# render Payment View
@view5 = new Blog.Views.Payment.PaymentView(payment_methods: @payment_methods)
$("#customer_1").append(@view5.render().el)
### other views...
和我的支付模型:
class Blog.Models.PaymentMethod extends Backbone.Model
paramRoot: 'payment_method'
defaults:
payment_type: null
# ...
class Blog.Collections.PaymentMethodsCollection extends Backbone.Collection
model: Blog.Models.PaymentMethod
url: '/payment_methods'
got a problem for a couple of days with backbone and can't figure out a way to solve it or find a solution on stackoverflow.
I use Rails 3.1 + latest backbone (+ coffeescript):
Here is one of my views as an example (same problem in all of them):
Blog.Views.Payment ||= {}
class Blog.Views.Payment.PaymentView extends Backbone.View
className: 'payment_method'
tagName: 'td'
events:
'click #renderPayment': 'renderPayment'
initialize: ->
# CAN'T access @options.payment_methods here
@options.payment_methods.bind(###stuff###)
render: ->
# CAN'T access @options.payment_methods here either...
$(@el).html ("### something with #{@options.payment_methods or @options.payment_methods.model}")
return @
updateView: ()->
# updating view stuff...
renderPayment: ->
# ACCESSING @options.payment_methods fine here!!!
if ($("#payment_details").length == 0)
$(@el).append("<ul id='payment_details'>
<li id='payment_type'>#{@options.payment_methods.get(1).get('payment_type')}</li>
</ul>
").effect("highlight", 700)
In the first two cases when I run the example the browser tells me that @options.payment_methods is not defined, third case working fine.
Second thing is that I can't access any DOM elements that are already "hardcoded" into the page and are not created by the Javascript. I know the reason for that and have been reading a loooot of posts here on Stackoverflow about it but I couldn't get any solution to work. Any hints greatly appreciated.
Best regards,
Phil
EDIT:
It seems that it has something to do with the timing of access of the objects on the page, similiar to the access of the hardcoded DOM elements of the page. If I edit my view as follows I can't access @options.payment_methods anymore even if I was able to before at that point in the code.
# changed "renderPayment" to "$(document).ready" or just "$" in coffeescript
$ ->
# ACCESS NOT possible anymore
if ($("#payment_details").length == 0)
$(@el).append("<ul id='payment_details'>
<li id='payment_type'>#{@options.payment_methods.get(1).get('payment_type')}</li>
</ul>
").effect("highlight", 700)
EDIT2: added my corresponding router file: (this is simply a modified version of the backbone-rails gem example "Blog")
class Blog.Routers.PostsRouter extends Backbone.Router
initialize: (options) ->
@posts = new Blog.Collections.PostsCollection()
@posts.reset options.posts
# ... other collections
# fetch payment_methods collection
@payment_methods = new Blog.Collections.PaymentMethodsCollection()
@payment_methods.reset options.payment_methods
@payment_methods.fetch()
@model = ({posts: @posts, mails: @mails, addresses: @addresses, purchases: @purchases, payment_methods: @payment_methods})
routes:
"/new" : "newPost"
"/index" : "index"
"/:id/edit" : "edit"
"/:id" : "show"
".*" : "index"
# main view
index: ->
# render Product Info View
@view = new Blog.Views.Product.ProductView(purchases: @purchases)
$("#product_1").html(@view.render().el)
##### view etc.
# render Payment View
@view5 = new Blog.Views.Payment.PaymentView(payment_methods: @payment_methods)
$("#customer_1").append(@view5.render().el)
### other views...
And my Payment model:
class Blog.Models.PaymentMethod extends Backbone.Model
paramRoot: 'payment_method'
defaults:
payment_type: null
# ...
class Blog.Collections.PaymentMethodsCollection extends Backbone.Collection
model: Blog.Models.PaymentMethod
url: '/payment_methods'
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您确实需要查找并理解
->
和=>
之间的区别。看起来类中的大多数方法都在使用->
,而它们应该使用=>
。无论您在何处使用@something
,它实际上都是this.something
的快捷方式,并且=>
确保this
> 确实是您所期望的那样。使用->
时,this
将绑定到进行调用的函数中的任何内容,而不是您的类实例。You really need to look up and understand the difference between
->
and=>
. It looks like most methods in your classes are using->
, when they should be using=>
. Whereever you use@something
, it's really a shortcut tothis.something
, and=>
makes sure thatthis
really is what you expect it to be. With a->
,this
will be bound to whatever it is in the function that makes the call, not your class instance.选项被传递给视图的初始化方法。因此您可以通过这种方式直接访问它们。
在
render()
中调用@options
应该没问题,除非在视图上下文中(即从其他回调中)没有调用 render。要解决此问题,请使用粗箭头定义render
,它将始终在视图的上下文中调用。如果您想访问页面上已有的元素,那么您需要执行一些操作。最重要的是,将
el
中的 DOM 元素传递给视图构造函数,您的视图将“接管”并拥有该元素。例如......然后在该视图中,您希望将 jQuery 查找范围限制为视图的元素。例如:
coffeescript 中的主干快捷方式是
Good lucky
Options are passed to a view's initialize method. So you can access them directly that way.
Calling
@options
inrender()
should be fine, except in the event that render is not being called in the context of your view, ie from some other callback. To fix this, definerender
with the fat arrow, and it will always be called in the context of the view.If you want to access elements that are already on the page, then there are a few things you need to do. Most importantly, pass the DOM element in
el
to the view constructor, and your view will "take over" and own that element. For example..Then in that view, you want to scope your jQuery finds to the view's element. For example:
The backbone shortcut for this in coffeescript is
Good luck