Backbone Coffeescript Super Render - javascript

How can I call the super's render function in backbone (coffeescript)?
If not in coffeescript, I've heard
MyModel.__super__.render.call(this);
will work, but MyModel in this case is exports.MyModel, how do I use this function if its an element of exports?
Thanks in advance

Since you're trying to call the super render method from inside the render method you could just something like this:
class TopLevelClass extends Backbone.View
initialize: ->
#render()
render: ->
console.log 'Render TopLevelClass'
# # return this
class SecondaryLevelClass extends TopLevelClass
initialize: ->
#render()
render: ->
super()
console.log 'Render SecondaryLevelClass'
# # return this
t = new TopLevelClass
# el: $("#first_div")
s = new SecondaryLevelClass
# el: $("#second_div")
Source:
http://coffeescript.org/#classes
edit:
#lublushokolad is correct. The Backbone documentation recommends that render returns this

There are some drawbacks to the coffeescript class approach in a Backbone environment:
Using the class SecondaryLevelClass extends TopLevelClass syntax changes the traditional Backbone extension model, which could be confusing.
It generates a lot of JS code, and you've already loaded Backbone/Underscore's extend code.
It may be worth using the regular Backbone extend syntax with the tradeoff of calling super in a more verbose way, like this:
TopLevelClass Backbone.View.extend
initialize: -> #render()
render: ->
console.log 'Render TopLevelClass'
#
SecondaryLevelClass = TopLevelClass.extend
initialize: -> #render()
render: ->
SecondaryLevelClass.__super__.initialize.call(this)
console.log 'Render SecondaryLevelClass'
#
t = new TopLevelClass # el: $("#first_div")
s = new SecondaryLevelClass # el: $("#second_div")
Another option is a mixin like this: http://pivotallabs.com/a-convenient-super-method-for-backbone-js/

Related

Show JSON data in HTML using Backbone

I've got an event in my view which on keyup does a fetch request to the TMDB api,
class Movieseat.Views.Moviesearch extends Backbone.View
template: JST['movieseats/moviesearch']
el: '#moviesearch'
initialize: (opts) ->
#collection.on('reset', #render, this)
{#collection} = opts
#render()
return
render: ->
$(#el).html(#template(collection: #collection))
return
events:
"keyup input": "doSearch"
doSearch: (e) ->
#collection.setQuery $(e.currentTarget).val()
#collection.fetch()
view = new Movieseat.Views.Movie()
$('#movies').append(view.render().el)
This is my collection,
class Movieseat.Collections.Moviesearch extends Backbone.Collection
url: -> "http://api.themoviedb.org/3/search/movie?api_key=a8f7039633f2065942cd8a28d7cadad4&query=#{#query}"
setQuery: (q) ->
#query = q
return
So if my input is inception this is the fetch request,
http://api.themoviedb.org/3/search/movie?api_key=a8f7039633f2065942cd8a28d7cadad4&query=inception
As you can see in my view I'm append a template called movies. I would like to show all of the original_title from the fetch request in that template. And update the template when it changes.
From what I understood, your collection holds elements of type movie or something like that. After you fetched the collection, it's models should contain the original_title and poster_path. Now you can use pluck method to read all those properties. The code should look like that (javascript):
collection.on("sync", function() {
myView.displayTitles(collection.pluck("original_title"));
})
Update
With this code update you posted, I'm wondering why don't you use those properties inside a collection's template. Given that your collection doesn't declare the type of models it contains, you cannot use the #model.get('prop') syntax, as #model is not a Backbone model. Try using
#model.prop
syntax instead.

Backbone: view's model is undefined when passing it a model

Here's the entirety of my simple Backbone app. When I instantiate a new view, I'm passing it a model, but when the view calls attributes on the model, it says model is undefined:
class App.Recipe extends Backbone.Model
class App.RecipeList extends Backbone.Collection
url: '/users/4/recipes'
model: App.Recipe
#recipeList = new App.RecipeList
#recipeList.fetch()
class App.RecipeView extends Backbone.View
template: _.template(#model.attributes)
render: ->
#$el.html(#template)
#
#recipeView = new App.RecipeView(model: recipeList.models[0])
$ ->
$('#featured_recipes').html(window.recipeView.render())
In the console, recipeList.models[0] returns a JSON object that does indeed have an attributes property. So when I instantiate the view and pass it a model, why do I get Uncaught TypeError: Cannot read property 'attributes' of undefined?
My guess is that #model is getting evaluated at runtime, before I pass in the model. Is there a way to defer that? Or am I wrong?
I've also tried the _.bindAll # in the initialize function of the view. No dice.
PS — I'm obviously a noob, so if you see other antipatterns or things I'm going to run into here, feel free to mention them.
Edit
I've tried the answer outlined here of adding the template inline in my initialize method like this:
class #App.RecipeView extends Backbone.View
tagName: 'li'
initialize: ->
_.bindAll #, 'render'
template = _.template $('#featured_recipes').html()
render: ->
#$el.html #model.toJSON()
#
But then I get Cannot call method 'replace' of undefined , which I know is from underscore calling template on something that isn't in the DOM yet, and that's happening because this gets called before my DOM renders. Any thoughts?
Edit 2
Now I've moved the entire app into the footer of my haml layout, so that the $(#featured-_recipes') div is in the DOM. Then I changed the view to this:
class #App.RecipeView extends Backbone.View
tagName: 'li'
initialize: ->
_.bindAll #, 'render'
#template: _.template $('#featured_recipes').html()
render: ->
#$el.html #template(#model.toJSON())
#
But I'm still getting Cannot call method 'replace' of undefined .
Try the following. I added an initialize method to your View, and I used Backbone's Collection get method to get your recipe.
class App.RecipeView extends Backbone.View
initialize: (options) ->
#model = options.recipe
template: _.template(#model.attributes)
render: ->
#$el.html(#template)
#
#view = new App.RecipeView
recipe: recipeList.get(0)

Backbone.Collection has no method toJSON

I'm writing a small app using Backbone. I start creating a SongsView which creates a SongsCollection. I fetch this collection to retrieve the data from an external API I wrote. The next step is to render the fetched data using the toJSON method, however calling toJSON returns [undefined], despite the fact that the collection is an instance of Bakcbone.Collection.
Here is my code (in coffeescript):
App:
songs = new SongsView
songs.render()
SongsView:
SongsCollection = require 'scripts/collections/songs'
class SongsView extends Backbone.View
el: '#songs'
render: ->
songs = new SongsCollection
songs.fetch
success: ( res ) =>
console.log (res instanceof Backbone.Collection) # true
console.log (res instanceof SongsCollection) # true
console.log (res.toJSON()) # [undefined]
SongsCollection:
Song = require 'scripts/models/song'
class SongsCollection extends Backbone.Collection
model: Song
url: 'http://localhost:1337/songs'
Song:
class Song extends Backbone.Model
constructor: ({#name, #path}) ->
console.log 'new'
EDIT: If I look at the prototypes chain, I can find a toJSON() method though :
EDIT²: Same behavior for a single model :
console.log (res.models[0].toJSON()) # undefined
Which is actually interesting. It means that the toJSON method from the SongsCollection works but the toJSON from Song does not. I'll dig deeper there.
Problem solved. I was using constructor instead of initialize which leads to create a model without any attributes, thus, calling toJSON returned undefined as the attributes property was not defined.
class Song extends Backbone.Model
initialize: ({#name, #path}) ->
console.log 'new'

Backbone.js collection fetch 'this._byId' undefined

I'm using coffeescript. My code is pretty simple:
class SomeCollection extends Backbone.Collection
constructor: (#options) ->
url: ->
"#{$SCRIPT_ROOT}/some/data/#{#options.someId}"
model: SomeModel
class SomeView extends Backbone.View
initialize: ->
myCollection = new SomeCollection()
myCollection.fetch
success: (coll, resp) ->
console.log coll
The JSON that's being returned from my collection's url is exactly:
[{"id": 1, "comments": "", "name": "images/exceptions/59.png"}]
However, before anything is printed to the console, I receive a backbone.js error on line 768: Cannot read property 1 of undefined. The undefined object is this._byId within the collection's get function. How can I solve this problem?
You are extending Backbone.Collection and providing your own constructor, so you need to make sure to call the parent constructor.
constructor: (#options) ->
super null, #options
Also, the standard arguments for a Collection are (models, options), so I would stick with that.
constructor: (models, #options) ->
super models, #options
Or better yet, use initialize instead of constructor to avoid that entirely
initialize: (models, #options) ->

Can't iterate through Collection in Backbone.js

Update
It was a stupid typo. I was using Backbone.Model.extend for the collection. facepalm
Trying to iterate through a collection but I think I've populated it incorrectly or something:
RecentContent = Backbone.View.extend
initialize: ->
#collection = new ContentAPI.ContentCollection()
#collection.fetch
success: (collection, response, options) =>
console.log #collection
# d {attributes: Object, _escapedAttributes: Object, cid: "c4", changed: Object, _silent: Object…}
# property `attributes` contains Objects from server
console.log #collection.models # undefined
#render()
#---------------------
render: ->
# ERROR: Object has no method 'each'
#collection.each (model) ->
console.log model
I also noticed that if I tried to bind the reset event to #collection (instead of render from within the success callback), it never seems to get fired.
The collection is very simple:
class ContentAPI
#Content: Backbone.Model.extend {}
#ContentCollection: Backbone.Model.extend
url: "/api/content/"
model: #Content
I'm a little new to Backbone so thank you for helping. :)
The problem is that your collection is inheriting from the wrong base class.
#ContentCollection: Backbone.Model.extend
should be
#ContentCollection: Backbone.Collection.extend
I am no coffeescript expert, but I think your problem is
#ContentCollection: Backbone.Model.extend
It should be
#ContentCollection: Backbone.Collection.extend
Also when iterating over your collection's models, use
_.each(collection.models, function(model) { console.log(model); });

Categories

Resources