Simple rails integration with backbone.js - backbone.js

Having trouble rendering first page using rails and backbone. Please assume that I have all the gems properly installed and running. Most of the coffeescript files are generated using 'rails g backbone:scaffold Student', but I changed some files and directory structure. This is just to try to understand the process flow than anything else. I also loaded some student data in db. Finally, when this rails application is deployed (development) and I visit localhost:3000, I don't get the alert that is in initialize function.
Here are the files.
app/models/students.rb
class Student < ActiveRecord::Base
attr_accessible :dob, :email, :name, :phone_number
end
app/controllers/students_controller.rb
class StudentsController < ApplicationController
respond_to :html, :json
def index
respond_with (#students = Student.all)
end
end
config/routes.rb
School::Application.routes.draw do
resources :students
root :to => 'students#index'
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>School</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<tbody>
<div id="students">
<%= yield %>
</div>
</tbody>
</body>
</html>
app/views/students/index.html.erb
<%= content_for :javascript do %>
<%= javascript_tag do %>
window.School.initialize({ students: <%= #students.to_json %> });
<% end %>
<% end %>
app/assets/javascripts/application.js
//
//= require jquery
//= require jquery_ujs
//= require jquery-ui-1.8.18.custom.min
//
//= require underscore
//= require json2
//= require backbone
//= require backbone_rails_sync
//= require backbone_datalink
//= require backbone-forms
//= require school
//= require_tree ./models
//= require_tree ./collections
//= require_tree ./views
//= require_tree ./routers
//= require_tree ../templates
//= require_tree .
app/assets/javascripts/school.js.coffee
#= require_self
#= require_tree ../templates
#= require_tree ./models
#= require_tree ./collections
#= require_tree ./views
#= require_tree ./routers
window.School =
Models: {}
Collections: {}
Routers: {}
Views: {}
initialize: (data) -> alert 'Hello for rails'
app/assets/javascripts/collections/students.js.coffee
class School.Collections.StudentsCollection extends Backbone.Collection
model: School.Models.Student
url: '/students'
app/assets/javascripts/models/student.js.coffee
class School.Models.Student extends Backbone.Model
paramRoot: 'student'
app/assets/javascripts/routers/students_router.js.coffee
class School.Routers.StudentsRouter extends Backbone.Router
initialize: (options) ->
#students = new School.Collections.StudentsCollection()
#students.reset options.students
routes:
"index" : "index"
".*" : "index"
index: ->
#view = new School.Views.Students.IndexView(students: #students)
$("#students").html(#view.render().el)
app/assets/javascripts/views/students/index_view.js.coffee
School.Views.Students ||= {}
class School.Views.Students.IndexView extends Backbone.View
template: JST["templates/students/index"]
initialize: () ->
#options.students.bind('reset', #addAll)
addAll: () =>
#options.students.each(#addOne)
addOne: (student) =>
view = new School.Views.Students.StudentView({model : student})
#$("tbody").append(view.render().el)
render: =>
#$el.html(#template(students: #options.students.toJSON() ))
#addAll()
return this
app/assets/templates/students/index.jst.ejs
<h1>Listing students</h1>
<table id="students-table">
<tr>
<th>Name</th>
<th>DOB</th>
<th>Email</th>
</tr>
</table>
html output
<!DOCTYPE html>
<html>
<head>
<title>School</title>
<link href="/assets/application.css?body=1" media="all" rel="stylesheet" type="text/css" />
<link href="/assets/students.css?body=1" media="all" rel="stylesheet" type="text/css" />
<script src="/assets/jquery.js?body=1" type="text/javascript"></script>
<script src="/assets/jquery_ujs.js?body=1" type="text/javascript"></script>
<script src="/assets/jquery-ui-1.8.18.custom.min.js?body=1" type="text/javascript"></script>
<script src="/assets/underscore.js?body=1" type="text/javascript"></script>
<script src="/assets/json2.js?body=1" type="text/javascript"></script>
<script src="/assets/backbone.js?body=1" type="text/javascript"></script>
<script src="/assets/backbone_rails_sync.js?body=1" type="text/javascript"></script>
<script src="/assets/backbone_datalink.js?body=1" type="text/javascript"></script>
<script src="/assets/backbone-forms.js?body=1" type="text/javascript"></script>
<script src="/assets/school.js?body=1" type="text/javascript"></script>
<script src="/assets/students/edit.js?body=1" type="text/javascript"></script>
<script src="/assets/students/index.js?body=1" type="text/javascript"></script>
<script src="/assets/students/new.js?body=1" type="text/javascript"></script>
<script src="/assets/students/show.js?body=1" type="text/javascript"></script>
<script src="/assets/students/student.js?body=1" type="text/javascript"></script>
<script src="/assets/models/student.js?body=1" type="text/javascript"></script>
<script src="/assets/collections/students.js?body=1" type="text/javascript"></script>
<script src="/assets/views/students/edit_view.js?body=1" type="text/javascript"></script>
<script src="/assets/views/students/index_view.js?body=1" type="text/javascript"></script>
<script src="/assets/views/students/new_view.js?body=1" type="text/javascript"></script>
<script src="/assets/views/students/show_view.js?body=1" type="text/javascript"></script>
<script src="/assets/views/students/student_view.js?body=1" type="text/javascript"></script>
<script src="/assets/routers/students_router.js?body=1" type="text/javascript"></script>
<script src="/assets/application.js?body=1" type="text/javascript"></script>
<meta content="authenticity_token" name="csrf-param" />
<meta content="46vcYK8H3HIUfZh9wfu+AtzCKs+/2TnESA2ILxhFx0E=" name="csrf-token" />
</head>
<body>
<tbody>
<div id="students">
</div>
</tbody>
</body>
</html>

You have a couple of problems that are seemingly related and unrelated at the same time.
The reason your index doesn't render correctly is because you have a content block for a a named yield that doesn't exist.
To get <%= content_for :javascript do %> to work, add the following to application.html.erb:
<%= yield :javascript %>
However, this will get your code to display, it most likely will not get it to run correctly.
Since you are using the rails-backbone gem and leveraging the use of templates, you simply need to have the following in your index.html.erb:
<div id="students"></div>
And then instantiate your backbone router in your index.html.erb by using:
<script type="text/javascript">
$(function(){
try {
window.SchoolRouter = new School.Routers.StudentsRouter({ students: <%= #students.to_json %> });
backbone.history.start();
}catch(e){
alert(e); // alert so that you see it.
}
});
</script>
When it comes to JavaScript, make sure you're using FireBug or the Dev panels in your browser. console.log() is your best friend.

Related

Grails Asset Pipeline not giving proper Javascript order

I'm creating an Angular app on Grails 3.1.5 and asset pipeline is not giving me the Javascript file ordering I need. I have the following Javascript files:
angello.js
//= require /angular/angular
//= require /angular-route/angular-route
//= require /angello/core/angello.core
//= require /angello/index/angello.index
//= require /angello/common/angello.common
//= require /angello/storyboard/angello.storyboard
var myModule = angular.module("Angello", [
"angello.core",
"angello.index",
'ngRoute',
'Angello.Common',
'Angello.Storyboard'
]);
myModule.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'assets/angello/storyboard/tmpl/storyboard.html',
controller: 'StoryboardCtrl',
controllerAs: 'storyboard'
})
});
myModule.controller('MainCtrl', function() { });
angello.storyboard.js
//= require_tree services
//= require_tree controllers
//= require_tree directives
//= require_tree templates
//= require_self
angular.module('Angello.Storyboard', ['Angello.Common']);
storyboardController.js
//= require /angular/angular
//= require /angello/storyboard/angello.storyboard
//= require_self
angular.module('Angello.Storyboard')
.controller('StoryboardCtrl', function() {
var storyboard = this;
});
I include all of this in my main GSP with
<asset:javascript src="angello.js" /> When the HTML is rendered, the order of the JS files are not what I expect:
<script type="text/javascript" src="/assets/angular/angular.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angular-route/angular-route.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angular/angular-resource.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/core/angello.core.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/core/services/DomainServiceFactory.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/index/angello.index.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/index/services/applicationDataFactory.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/index/controllers/indexController.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angular/ui-bootstrap-tpls.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/common/angello.common.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/storyboard/controllers/storyboardController.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello/storyboard/angello.storyboard.js?compile=false" ></script>
<script type="text/javascript" src="/assets/angello.js?compile=false" ></script>
The problem is that storyboard JS files are included in the order opposite of what I need, resulting in angular complaining
Error: [$injector:nomod] Module 'Angello.Storyboard' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
I think this is a problem in the way I have structured the dependency directives. I have tried many different things, but nothing seems to affect the order.
The module which is used to create the artifacts like controller, service, etc has to be loaded first before the dependents are loaded. In the above case controllers are required before the module itself.
So, when the controller (styoryBoardController.js) is required it complains about the module not being present.
Moving //= require_self to the top in angello.storyboard.js will ensure that the module itself is required first then the dependencies.

Argument 'ClockOnController' is not a function, got undefined

Hi I've been having some problems refactoring my controllers into their own snippets
I want the controllers to inherit the dependencies from my initial app declaration.
"use strict";
angular.module('clockOn', ['angular-contextual-date','logon','milli','mobile','ClockOnController','Auth','ngStorage'])
I need these dependencies to flow through my controllers.
angular.module('clockOn').controller('LogonController', ['$rootScope','$scope','$location','$localStorage','Auth',
function($rootScope, $scope, $location, $localStorage,Auth){
creates unknown provider errors --I'm assuming the dependencies aren't flowing down--
angular.module('clockOn',[]).controller()
creates undefined function 'controllerName' errors -In this scenario I'm assuming I'm redefining the app and hence loosing the other controllers-
Here's two of the controllers
(function (){
angular.module('clockOn',['Auth','angular-contextual-date'])
.controller('ClockOnController', ['$http','Auth','contextualDateService' ,function ($http,Auth,contextualDateService){
this.user = Auth.getTokenClaims().user; //authorised is a property of the controller
contextualDateService.config.fullDateFormats.thisMonth = "MMM d 'at' h:mm a ";
this.shifts = getShifts(this);
function getShifts(clockOnCtrl){
var date = new Date();
var curr_date = Date.now();
var week_from_now = Date.now()+"7";
$http({
method: 'GET',
url: '/shifts',
params: {"user_id":clockOnCtrl.user._id,
"start_at":curr_date,
"finish_at":week_from_now}
}).
then(function(res){
if (typeof res !== 'undefined'){
console.log(res.data);
clockOnCtrl.shifts = res.data;
}},
function(error){
console.log(error)
});
}
}]);
})();
My index file
<!DOCTYPE html>
<html class="container" ng-app="clockOn"> <!-- ng-app tells the html page which app/module it belongs too runs the store module on load-->
<head>
<meta name="viewport" content="width=device-width , initial-scale=1">
<link rel="stylesheet" type="text/css" href="../resources/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="../resources/custom.css"/>
</head>
<body>
<script type="text/javascript" src="../resources/jquery.min.js"></script>
<script type="text/javascript" src="../resources/angular.min.js"></script>
<script type="text/javascript" src="../resources/bower_components/angular-contextual-date/dist/angular-contextual-date.js"></script>
<script type="text/javascript" src="../modules/app.js"></script>
<script type="text/javascript" src="../modules/logon.js"></script>
<script type="text/javascript" src="../modules/tasks.js"></script>
<script type="text/javascript" src="../services/milli.js"></script>
<script type="text/javascript" src="../services/auth.js"></script>
<script type="text/javascript" src="../modules/mobile.js"></script>
<script type="text/javascript" src="../modules/shifts.js"></script>
<script type="text/javascript" src="../modules/layout-components.js"></script>
<script type="text/javascript" src="../resources/bower_components/ngstorage/ngStorage.min.js"></script>
<script type="text/javascript" src="../controllers/controller-clockOn.js"></script>
<script type="text/javascript" src="../controllers/controller-logon.js"></script>
<script type="text/javascript" src="../controllers/controller-tasks.js"></script>
<div class="container" ng-controller="ClockOnController as clockOnCtrl">
<div class= "" ng-controller="LogonController as logonCtrl">
<logon-form></logon-form>
<top-menu></top-menu>
<div class="page-header" ng-show="token">
<h2 class="">Welcome {{clockOnCtrl.user.name | uppercase}}
<small>You currently have {{clockOnCtrl.shifts.length}} shifts</small>
<h2>
</div>
<shifts-list></shifts-list>
<custom-footer></custom-footer>
</div>
</div>
</body>
</html>
The error Argument 'ClockOnController' is not a function, got undefined

backbone router Implementation not working

Below is my HTML file RouterExample.html. I am trying to create a router. But it is not working.
Have i imported all necessaries?
When i try to run the code i get the html page as designed. When i click on any of the HREF objects, the object's name is getting appended to the URL but getting JBOSS, which is my server home page.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script
src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.1/underscore-min.js"></script>
<script
src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.1/backbone-min.js"></script>
<script src="scripts/jquery-1.7.2.js" type="text/javascript"></script>
<script src="scripts/underscore.js" type="text/javascript"></script>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="backbone.js"></script>
<script type="text/javascript" src="router.js"></script>
</head>
<body>
One
Two
Three
One
Two
Three
<table>
<tr>
<td id="one">1</td>
<td id="two">2</td>
</tr>
<tr>
<td id="three">3</td>
<td id="four">4</td>
</tr>
</table>
<script>
$(function(){
var AppRouter = Backbone.Router.extend({
routes: {
'RouterExample.html': 'home',
'one' : 'oneFun'
},
home : function()
{
alert("Home");
},
oneFun: function()
{
alert("One Function");
}
});
var fovView = new AppRouter();
Backbone.history.start();
});
</script>
</body>
</html>
Your anchor tags are linking to another document because the href values start with /. Try this:
One
Two
Three
One
Two
Three

Angular JS template now showing

I am having issues trying to show a partial html on my index.html file (Nothing is displayed).
Please see my index.html code:
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8">
<title>My AngularJS App</title>
<link rel="stylesheet" href="css/app.css"/>
<link rel="stylesheet" href="css/animations.css"/>
<link rel="stylesheet" href="css/bootstrap.css"/>
<script src="js/jquery-1.11.0.min.js"></script>
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-animate.js"></script>
<script src="lib/angular/angular-route.js"></script>
<script src="lib/angular/angular-resource.js"></script>
<script src="js/app.js"></script>
<script src="js/animations.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
<script src="js/directives.js"></script>
</head>
<body>
<li>
Show People
</li>
<div ng-view></div>
</body>
</html>
Then I try to load people.html that is on partials directory, using routing on app.js:
'use strict';
// Declare app level module which depends on filters, and services
var myApp = angular.module('myApp', ['ngRoute', 'filters', 'services', 'directives', 'controllers']);
myApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.when('/people', {
templateUrl : 'patials/people.html',
controller : 'PeopleController'
}).otherwise({
redirectTo : '/people'
});
}]);
If I replace the ng-view part on my index.html with my template file content, everything displays fine, so I dont think I have an issue on my controller declarations.
Can you take a look and help me figuring out what's wrong?
Thanks!
You are using var myApp = angular.module('myApp', []); inside your controller. If you add an array as a second parameter in angular.module, the module is automatically created as a new one and overrides the previous one with the same name, so the config is not working anymore, because in your code it is defined on a different module.
Just change the code in the PeopleController definition from
var myApp = angular.module('myApp', []);
to
var myApp = angular.module('myApp');
and it should work
edited plunk:
http://plnkr.co/edit/bK9vHSPxKmijhlLPS5C5?p=preview

Backbone.js: Router callback not reached

I'm having trouble getting a simple App example to route. I'm using the backbone-on-rails gem.
Here's my App.js.coffee:
window.App =
Models: {}
Collections: {}
Views: {}
Routers: {}
$(document).ready ->
MyRouter = Backbone.Router.extend(
routes:
'' : 'index'
index: ->
console.log("Inside router")
new App.Views.HomeIndex()
)
router = new MyRouter
Backbone.history.start
console.log(router.routes[Backbone.history.fragment])
The router never reaches the index callback and the View is never rendered.
Here's the HTML Page that is rendered by Rails:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<link href="/assets/application.css?body=1" media="screen" rel="stylesheet" />
<script src="/assets/jquery.js?body=1"></script>
<script src="/assets/jquery_ujs.js?body=1"></script>
<script src="/assets/underscore.js?body=1"></script>
<script src="/assets/backbone.js?body=1"></script>
<script src="/assets/app.js?body=1"></script>
<script src="/assets/homes/index.js?body=1"></script>
<script src="/assets/models/home.js?body=1"></script>
<script src="/assets/collections/homes.js?body=1"></script>
<script src="/assets/views/homes/homes_index.js?body=1"></script>
<script src="/assets/routers/homes_router.js?body=1"></script>
<script src="/assets/routers/homes_routers.js?body=1"></script>
<script src="/assets/application.js?body=1"></script>
<meta content="authenticity_token" name="csrf-param" />
<meta content="sA25aKKc/j2EJL6k8J0gm8SxGU2mHRhH8Sb6Sye81Ac=" name="csrf-token" />
</head>
<body>
<div id="app"></div>
</body>
</html>
What do I need to do to properly instantiate a Backbone Router and get it to route to my Views?
Looks like you just need to call Backbone.history.start rather than simply reference it. This just references the function:
Backbone.history.start
This calls it:
Backbone.history.start()
The function-calling parentheses are only optional when you supply some arguments.
Demo: http://jsfiddle.net/ambiguous/hUZUV/

Resources