0

I am trying to setup my index.html.erb (root page) so that I can see two elements. A "new post" form, and a "new user" form. I am trying to get the forms' submit button to go to the show page after a user (or post) is created. It doesn't work on the root page - it simply changes the url to "localhost:3000/#/x", where "x" is the id of the user (or post), but the page doesn't change. However, when I go to "localhost:3000/users" and then try to create a user, it changes to show the users show page. This makes sense to me in a way (I can't put my finger on why...something to do with routing and being "inside" the app?). I just want the submit button to make the change to the show page when being used from the root page (again...it works fine once I am "inside" the app). I am only posting the "posts" code, the "users" code is identical except that anywhere "post" or "posts" appears, it would be "user" or "users", respectively. Here is some code:

new_view.js.coffee

Example.Views.Posts ||= {}

class Example.Views.Posts.NewView extends Backbone.View
  template: JST["backbone/templates/posts/new"]

  events:
    "submit #new-post": "save"

  constructor: (options) ->
    super(options)
    @model = new @collection.model()

    @model.bind("change:errors", () =>
      this.render()
    )

  save: (e) ->
    e.preventDefault()
    e.stopPropagation()

    @model.unset("errors")

    @collection.create(@model.toJSON(),
      success: (post) =>
        @model = post
        window.location.hash = "/#{@model.id}"

      error: (post, jqXHR) =>
        @model.set({errors: $.parseJSON(jqXHR.responseText)})
    )

  render: ->
    $(@el).html(@template(@model.toJSON() ))

    this.$("form").backboneLink(@model)

    return this

I've tried messing around with the "save" function - I played around with "window.location.hash". I also tried creating a method called "display" in the view, and had it use "router.navigate" to make the switch. I then added "this.display()" to the "save" function (right after "window.location.hash" line). It changed the url to what I wanted it to be...but still no page switch (from the root page).

posts_router.js.coffee

class Example.Routers.PostsRouter extends Backbone.Router
  initialize: (options) ->
    @posts = new Example.Collections.PostsCollection()
    @posts.reset options.posts

  routes:
    "new"      : "newPost"
    "index"    : "index"
    ":id/edit" : "edit"
    ":id"      : "show"
    ".*"        : "index"

  newPost: ->
    @view = new Example.Views.Posts.NewView(collection: @posts)
    $("#posts").html(@view.render().el)

  index: ->
    @view = new Example.Views.Posts.IndexView(posts: @posts)
    $("#posts").html(@view.render().el)

  show: (id) ->
    post = @posts.get(id)

    @view = new Example.Views.Posts.ShowView(model: post)
    $("#posts").html(@view.render().el)

  edit: (id) ->
    post = @posts.get(id)

    @view = new Example.Views.Posts.EditView(model: post)
    $("#posts").html(@view.render().el)

post.js.coffee

class Example.Models.Post extends Backbone.Model
  paramRoot: 'post'

  defaults:
    title: null
    content: null

class Example.Collections.PostsCollection extends Backbone.Collection
  model: Example.Models.Post
  url: '/posts'

index.html.erb (root page)

<div id="container">Loading...</div>

<script type="text/javascript">
  $(function() {
    window.newView = new Example.Views.Users.NewView({model: <%= @users.to_json.html_safe -%>,collection: new Example.Collections.UsersCollection()});
    window.router = new Example.Routers.UsersRouter({users: <%= @users.to_json.html_safe -%>});
    var postView = new Example.Views.Posts.NewView({model: <%= @posts.to_json.html_safe -%>,collection: new Example.Collections.PostsCollection()});
    $('body').html(newView.render().$el);
    $('body').append(postView.render().$el);
    Backbone.history.start({pushState: true});
  });
</script>

Do I need a posts router? I am under the impression you can only have one "active" router.

Thanks in advance for any help, I will be paying attention to the post - I'll be responding within a few minutes of a comment.

UPDATE

Does example.js.coffee have anything to do with it?

#= require_self
#= require_tree ./templates
#= require_tree ./models
#= require_tree ./views
#= require_tree ./routers

window.Example =
  Models: {}
  Collections: {}
  Routers: {}
  Views: {}
ewizard
  • 2,801
  • 4
  • 52
  • 110
  • do you have `Example.Views.Posts` correctly initialised? I mean you have `Example = {}` , `Example.Views = {}` and `Example.Views.Posts = {}` – sites May 24 '13 at 14:01
  • The same for your other namespaces – sites May 24 '13 at 14:02
  • I'm not sure I follow...I'm not exactly sure what those lines do... – ewizard May 24 '13 at 14:06
  • if your question is whether or not i have `Example = {}`, `Example.Views = {}` i dont...I only have `Example.Views.Posts = {}` shown above. – ewizard May 24 '13 at 14:10

1 Answers1

0

Seems you have not correctly initialised your namespaces, you usually do:

window.Example =
  Views: {}
  Models: {}
  Routers: {}

And then you could have more namespaces, in your case, for Posts, in new_view.js.coffee:

Example.Views.Posts ||= {}

class Example.Views.Posts.NewView ...

You could also define deeper namespaces in the first object I wrote:

window.Example =
  Views:
    Posts: {}
    Users: {}
  Models: {}
  Routers: {}

In this case you won't have to write

Example.Views.Posts ||= {}

In your view.

If you are in Rails you could write this initialisation in your manifest application.js, although I have read is not recommended to write code there, in case you opt for this, remember to include first application.js

//= require_self
//= require_tree ./views
...

require_self should be first.

sites
  • 21,417
  • 17
  • 87
  • 146
  • thanks...I have a question...how does all of this tie back into the fact that I want the submit button to render the show view from the root page? I understand I may be doing something wrong...but how does changing that stuff help me do what I want to do? – ewizard May 24 '13 at 15:55
  • good question, you should be having error in your console, something like `Cannot read property 'blahblah' of undefined`, please tell me if not. If you are having this is because you have not defined `Some` before calling `Some.More` – sites May 24 '13 at 21:07
  • I don't get any errors in the console when I click the submit button. It just shows that I submitted a POST request: `POST http://localhost:3000/users 201 Created 111ms`. When I click submit again i get `PUT http://localhost:3000/users/86 500 Internal Server Error 91ms jquery.js?body=1 (line 8527) "NetworkError: 500 Internal Server Error - http://localhost:3000/users/86" 86 SyntaxError: JSON.parse: unexpected character [Break On This Error] return window.JSON.parse( data );` – ewizard May 24 '13 at 21:14
  • what about the line `$("#posts").html(@view.render().el)` in show method, in the router. should it be #posts? I tried #container (the div on my root page) and it didnt work. – ewizard May 24 '13 at 21:25