+im playing arround with backbone and coffeescript, trying to get the router up and running. executing the following code, the init function works, but when browsing localhost/#world/3 nothing happens, although it should log something....
App =
start: ->
new App.TestRouter
Backbone.history.start
App.TestRouter = Backbone.Router.extend
routes:
"world/:id": "testView"
initialize: ->
new App.TestView
console.log "Router init"
testView: (id) ->
console.log "testing! #{id}"
any advice here? am i blind?
Backbone.history.start() is a function, so you need the () to execute it. Otherwise, you're just getting a reference to the function itself.
App =
start: ->
new App.TestRouter
Backbone.history.start()
See this live jsFiddle:
http://jsfiddle.net/edwardmsmith/6pNLv/8/
Related
So my route filter is working as expected and I was writing some tests around it. I have several passing tests but for some reason I can't get this one test to pass. My route filter looks like this:
stripUs: ->
resolve: ->
resolution: ($location) ->
urlParts = $location.$$path.split("/")
if urlParts.indexOf('us') is 1
$location.path(urlParts.slice(2,urlParts.length).join("/"))
The idea is to redirect /us/foo/bar urls to /foo/bar.
the tests I currently have passing for this filter are:
ddescribe 'stripUs', ->
location = rootScope = null
beforeEach inject ($location, $rootScope, initialDataService, ignoreHttpBackend) ->
ignoreHttpBackend()
location = $location
rootScope = $rootScope
it 'removes /us from /us/programming', ->
location.path("/us/programming")
rootScope.$digest()
expect(location.path()).toEqual('/programming')
it 'removes /us from /us/programming/**', ->
location.path("/us/programming/sports")
rootScope.$digest()
expect(location.path()).toEqual('/programming/sports')
it 'preserves route params', ->
location.path("/us/programming/sports?affiliate=foo&&process=foobarred")
rootScope.$digest()
expect(location.path()).toEqual('/programming/sports?affiliate=foo&&process=foobarred')
The test I can't get to pass is:
it 'preserves route params', ->
location.path("/us/programming?affiliate=foo")
rootScope.$digest()
expect(location.path()).toEqual('/programming?affiliate=foo')
the error message is:
Expected '/us/programming?affiliate=foo' to equal '/programming?affiliate=foo'
which would lead me to believe the code isn't working but it is if I actually try to visit the page. Additionally when I try to put a console log at the very top of the route filter, the log is never hit. I am new to testing in Jasmine and could use any help possible. Thanks in advance.
I solved this issue by changing the expectation. I think I have a better test as a result but I never figured out why I couldn't get the test to run. here is what I changed the test to.
it 'preserves route params', ->
location.path("/us/programming/sports?affiliate=bestbuy&process=foobarred")
rootScope.$digest()
expect(location.path()).toContain('?affiliate=bestbuy&process=foobarred')
it 'preserves route params', ->
location.path("/us/programming?affiliate=bestbuy")
rootScope.$digest()
expect(location.path()).toContain('?affiliate=bestbuy')
I was following the backbonerails.com screencast episode 6. But I can't get the routing to work as it was explained.
Here is my code that is similar to what the screencast suggest:
#Report.module "UsersApp", (UsersApp, App, Backbone, Marionette, $, _) ->
class UsersApp.Router extends Marionette.AppRouter
initialize: ->
console.log "Happy days"
appRoutes:
"users" : "listUsers"
API =
listUsers: ->
console.log "hallo"
App.addInitializer ->
console.log "cheers"
new UsersApp.Router
controller: API
As you can see I have tried to add console.log in a few places to make sure the addInitializer is working and that the Router is started... but still the routing to #users does not do the corresponding console.log
I have this where I define the app:
App.on "initialize:after", ->
if Backbone.history
Backbone.history.start()
So that should run after router has started, if I understand it all.
Turns out that it was the Backbone history was not running. I found that out by running:
Backbone.History.started
in my console. For some reason
App.on "initialize:after", ->
if Backbone.history
Backbone.history.start()
did not start the history.
EDIT: turns about in v2 and above of Marionette you should use:
App.on "start", ->
I try to study and use Backbone/Marionette in my project. Now I stuck with Router navigation which work not as I though it should.
class MyApp.Router extends Marionette.AppRouter
appRoutes :
'info/:place/(:what)' : 'places_page'
MyApp.Controller = ->
places_page: (place,what)->
console.log 'Triggered places_page'
MyApp.addInitializer( ->
controller = new MyApp.Controller()
new MyApp.Router
controller: controller
Backbone.history.start( pushState: false )
)
MyApp.vent.on('do:search', ->
console.log 'triggered do:search'
place = 'Moscow'
what = 'Пицца'
info_model.set place: place, item:what
new_url = 'info/'+where+'/'+what
if new_url != decodeURIComponent(Backbone.history.fragment)
Backbone.history.navigate(new_url, {trigger: false})
On initial load of site.com/#info/Budapest/Vine page or reload it, I get Triggered places_page message as I expect.
But when I fire do:search event which update url to site.com/#info/Moscow/Пицца, I get Triggered places_page again! So it reload all my views from scratch instead of just change url and re-render one model.
What I can do wrong here?
Update 2:
Found strange thing. If I use latin letters in new url, everything work like it should.
But if I use cyrillic in new url path, it will trigger route function.
Backbone: 1.0, Marionette:v1.0.3, jquery: 1.9.1
Mystery solved!
That happens because of non-latin symbols in url.
Correct code:
new_url = 'info/'+encodeURIComponent(where)+'/'+encodeURIComponent(what)
if new_url != Backbone.history.fragment
Backbone.history.navigate(new_url, {trigger: false})
Because Backboune.navigate don't execute navigate if url didn't change and trigger is false by default, I can write it simple like that:
new_url = 'info/'+encodeURIComponent(where)+'/'+encodeURIComponent(what)
Backbone.history.navigate(new_url)
Backbone.history takes an object when starting. Try this syntax in CoffeeScript:
Backbone.history.start
pushState: false
In addition, pushState is false by default, so you can just have Backbone.history.start()
Does this solve your issue?
Proper URL encoding is required. I couldn't find this in the docs of Backbone related to the router functionality.
I had the same issue, alas with spaces in the query part, i.e.:
#app/terms?filter=java ee
Together with the encodeURIComponent solution as described in your answer, I also found the following lines of comments in backbone.js (1.0.0), pertaining to the navigate function:
// Save a fragment into the hash history, or replace the URL state if the
// 'replace' option is passed. You are responsible for properly URL-encoding
// the fragment in advance.
This is driving me crazy right now. I cannot get a simple router to work...
jQuery ->
class MyRouter extends Backbone.Router
routes:
"" :"index"
"/list" :"showList"
"/item/:id" :"showItem"
index: =>
alert "index"
showList: =>
alert "get the lists"
showItem: (id)=>
alert "the item #{id}"
#app = window ? {}
#app = window.app ? {}
#app.myRouter = MyRouter
Backbone.history.start()
I always get this error:
index.js:50Uncaught TypeError: Cannot call method 'start' of undefined
and I saw this: Cannot call 'start' of undefined when starting backbone.js history.
but it did not help =(...
I am sure this is an easy one but I am some sort of stuck here ...
please help...
You didn't create an instance of a Backbone.Router, so Backbone.history.start() will fail.
#app.myRouter = new MyRouter()
The link you posted tells you exactly what the problem is:
TypeError: Cannot call method 'start' of undefined**
Hmm, for some reason Backbone.history is undefined, and so there is no start method on it. It turns out that Backbone.js creates an
instance of Backbone.History (upper case ‘H’) called Backbone.history
(lower case ‘h’) once a controller has been created that has at
least one route specified on it. This makes sense, as history
management is only required if there are routes to respond to.
I have a success callback for a model fetch, and everything works fine on chrome, but on firefox the event does not fire. The request gets completed though, according to the console.
Code Sample:
Parent Class Function:
DownloadUserPromotions: (callback) ->
self = #
#model = new app.models.client({ id: JSON.parse($.cookie('jsondata')).id })
lm = ->
console.log "4"
window.USER = self.model
if typeof callback == 'function' then callback.call()
#model.fetch
success: lm
data:
relationships: 'client_promotions'
console.log "3"
View Function:
render: ->
self = #
self.ReadUserInfo()
console.log "1"
renderTemplate = ->
console.log "5"
#Below Issue is wierd.......#TODO
#USER = JSON.parse(JSON.stringify(#USER))
$(self.el).html clientsPromotionsTemplate
promos: USER.client_promotions
$('.spinner#load').hide()
self.FadeIn()
$('.spinner#load').show()
console.log "2"
#DownloadUserPromotions renderTemplate
#
Side Note: The marked TODO is a different issue. Bonus thank yous for helping me figure out why JSON works only in that convoluted manner.
First of all you need to get your head the difference between => and -> for defining functions in coffeescript.
=> binds this inside the function to what this was when the function was defined.
-> binds this inside the function to what this was when the function is called
self = this
is code smell sign in coffeescript that you don't understand how to use the above correctly as you are trying to capture this in order to solve the problem that => solves.
You render function re-written could be
render: ->
#ReadUserInfo()
console.log "1"
renderTemplate = =>
console.log "5"
#Below Issue is wierd.......#TODO
#USER = JSON.parse(JSON.stringify(#USER))
$(#.el).html clientsPromotionsTemplate
promos: USER.client_promotions
$('.spinner#load').hide()
#.FadeIn()
$('.spinner#load').show()
console.log "2"
#DownloadUserPromotions renderTemplate
#
And probably will fix some of your wierd issues. Previously I'm pretty sure
that the line you had
#USER = JSON.parse(JSON.stringify(#USER))
would never have worked as you expected as #USER would be expanded to this.USER and
whatever this might be when the callback is invoked can be pretty random depending
on your framework and browser.
Since my success callback was part of a JSON object, firefox couldn't find whatever default it was looking for and therefore didn't fire anything. Specifying dataType:'json' when fetching solves this problem, because firefox knows where to look for the success call back.
Chrome is apparently reads my mind...