How to get ID from URL - backbone.js

I am developing a Backbone Marionette web app.
I this app I got routes that look like this:
projects/:id/tasks
How can I get the ID of that route (URL)?
If I use this I get the whole URL:
Backbone.history.fragment
Update
This is how I define the routes for projects.
#Projectapp.module "ProjectsApp", (ProjectsApp, App, Backbone, Marionette, $, _) ->
class ProjectsApp.Router extends Marionette.AppRouter
appRoutes:
"projects/new" : "newProject"
"projects/:id" : "showProject"
"projects/:id/edit" : "editProject"
"projects" : "listProjects"
API =
listProjects: ->
new ProjectsApp.List.Controller
newProject: ->
new ProjectsApp.New.Controller
showProject: (id, project) ->
new ProjectsApp.Show.Controller
id: id
project: project
editProject: (id, project) ->
new ProjectsApp.Edit.Controller
id: id
project: project
App.Router.on "route:newProject", (project_id) ->
alert project_id
App.commands.setHandler "new:crew:member", (region) ->
API.newCrew region
App.vent.on "project:new:clicked", (project) ->
App.navigate "projects/new", true
App.vent.on "project:tasks:clicked", (project) ->
App.navigate "projects/#{project.id}/tasks", true
App.vent.on "project:created", (project) ->
App.navigate "projects/#{project.id}", true
App.vent.on "project:show:clicked project:back:clicked", (project) ->
App.navigate "projects/#{project.id}"
API.showProject project.id, project
App.vent.on "project:clicked project:edit:clicked", (project) ->
App.navigate "projects/#{project.id}/edit"
API.editProject project.id, project
App.vent.on "project:cancelled project:list:back:clicked", (project) ->
App.navigate "projects"
API.listProjects()
App.addInitializer ->
new ProjectsApp.Router
controller: API

The router will provide your handler function with the attributes parsed fro the URL.
You have a route defined with "projects/:id" : "showProject" but then your handler is
showProject: (id, project) ->
new ProjectsApp.Show.Controller
id: id
project: project
They don't match: your router will send the parsed id from the URL, but that's it. You need to get the project on your own, before passing it to the view, e.g.:
showProject: (id) ->
project = #projects_collection.get id
new ProjectsApp.Show.Controller
id: id
project: project
Of course, this means you need to be able to access the project collection, or fetch the project, etc.

A router should be defined similar to this (example):
var Router = Backbone.Router.extend({
routes:{
"page/:number":"go_to_page",
"show_something":"show_something"
},
});
Then, you can bind route events to a function that accepts the route variables, example:
Router.on("route:go_to_page",function(page) {
// page parameter corresponds to :number in the url hash, so now you can query your models with this string.
});
Hope this example helps...

Related

Integrating cordova plugin paypal with ionic

I'm trying to use the paypal-cordova-plugin to integrate paiement on my mobile app. But the instructions I am following are asking for sandbox id and production id but I have no idea where to find them in paypal. Can someone help me on this ?
This is the place where they are asked
angular.module('app')
.constant("shopSettings", (function () {
return {
payPalSandboxId: "Aar8HZzvc5NztVWodTBpOiOod9wWrBDrJUjyvRr4WsxcCD28xYig7oecfYsqxQUDu5QHptPpSALirxZD",
payPalProductionId : "production id here",
payPalEnv: "PayPalEnvironmentSandbo", // for testing production for production
payPalShopName : "SenPass",
payPalMerchantPrivacyPolicyURL : "url to policy",
payPalMerchantUserAgreementURL : "url to user agreement"
}
})());
This is the link I'm following : http://ionicandroidlearning.blogspot.fr/2015/11/ionic-paypal-integration.html
First you need to create an account on paypal developers.
Then inside the dashboard create a new application (REST API apps).
When you create the new app, Paypal will generate a sandbox account and a client id for you.
Add the code (example):
var configuration=function () {
var configOptions = {
merchantName: "Some name you have specified",
merchantPrivacyPolicyURL: "http://yourserver/privacypolicy",
merchantUserAgreementURL: "http://yourserver/agreement",
languageOrLocale: "en_US"
};
// for more options see paypal-mobile-js-helper.js
var _config = new PayPalConfiguration( configOptions );
return _config;
}
var onPrepareRender = function(){
$log.info(" ======= onPrepareRender ==========");
}
var onPayPalMobileInit = function(){
var payPalConfig = configuration();
PayPalMobile.prepareToRender("PayPalEnvironmentSandbox", payPalConfig, onPrepareRender);
deferred.resolve( payPalConfig );
}
var clientIDs = {
"PayPalEnvironmentProduction": '', //leave it blank
"PayPalEnvironmentSandbox": 'your sandbox id'
};
PayPalMobile.init(clientIDs, onPayPalMobileInit);
to retrive PayPal Sandobx keys try to go here:
https://developer.paypal.com/developer/accounts/
click on your generated account for testing (in the table) and then on Profile ...it open a modal with some tabs .. choose the API Credential tab
Hope it can help you

How to fetch and console json date on Backbone.js

I am trying to pull JSON data and display on my console just to see if its working. I am seeing an error message.
I am trying to fetch a Model with id 1:
var TeamModel = Backbone.Model.extend({
urlRoot: '/json/team.json'
});
//Create Team Model Instance with id of team
var teamModel = new TeamModel({
id: 1
});
//Fetch the json data
teamModel.fetch();
var director = teamModel.get('name');
Here is the JSON file :
{
"id" : 1,
"name" : "Sam",
"img_small" : "images/sam.jpg",
"location" : "NYC",
"role" : "Director, Producer, & Writer",
}
This yields the following error :
GET http://localhost:9000/json/team.json/1 404 (Not Found)
You should use url, not urlRoot:
var TeamModel = Backbone.Model.extend({
url: '/json/team.json'
});
Backbone uses urlRoot to generate resource URLs based on the operation you perform (fetch, save, delete) and Model id. When you fetch a single Model, the URL it generates is urlRoot + '/' + id.
Therefore when you attempt to fetch a Model with id 1, the constructed URL is /json/team.json/1
If you set url, however, Backbone always uses that url. It does not change it based on operation or model attributes. This is the behaviour that you need, because you have a single static resource.

Backbone.js How to retrieve a model in a nested collection?

I have a PizzaType model that has a nested collection of Pizzas. The Pizzas Collection is listed based on the Pizza Type. I would like to be able to click on a pizza in the pizzas collection and display its attributes.
What would be the best way to set the url params dynamically?
The url does not need a route to navigate to for bookmarking and sharing, just to retrieve the specific resource.
I have it so that if someone wants to view the pizza type the url is pizza_type/:id
:id is the id belonging to the Pizza Type (parent model)
I currently have it so if a pizza is clicked on in the Pizzas Collection (that belongs to the Pizza Type Model), the path to the pizza resource is not followed; just a region on the page is updated. The url path is needed so jQuery can get the resource to update that region. The url to the pizza is pizza_types/:pizza_type_id/pizzas/:id Here, the :id is the id belonging to the Pizza Model, and the :pizza_type_id is the foreign key that members of the Pizzas Collection share to group them into the collection, that belong to the Pizzas Type Model.
When I click on the pizza (id = 3), I get "NetworkError: 404 Not Found - http://localhost:3000/pizza_types/3/pizzas"
Here is the Model and Collection Code:
#Pizzeria.module "Entities", (Entities, App, Backbone, Marionette, $, _) ->
class Entities.PizzaType extends Backbone.Model
urlRoot: "pizza_types/"
# creates the nested collection
initialize: ->
#pizzas = new Entities.PizzasCollection
#pizzas.url = #urlRoot + #id + '/pizzas'
#pizzas.fetch
reset: true
parse: (response) ->
response
class Entities.PizzaTypesCollection extends Backbone.Collection
model: Entities.PizzaType
url: 'pizza_types'
parse: (response) ->
response
# Is there a way to pass in a :pizza_type_id and :id params to pass to the url() so
# that the specific pizza model can be retrieved from the collection?
class Entities.Pizza extends Backbone.Model
url: -> "pizza_types/" + 2 + "/pizzas/" + 4 # <-- Hard coded works, but how to set the params dynamically?
parse: (data) ->
data
class Entities.PizzasCollection extends Backbone.Collection
model: Entities.Pizza
url: 'pizzas'
parse: (data) ->
data
Any suggestions? Is this the proper way, I tried to do this as well:
class Entities.Pizza extends Backbone.Model
urlRoot: -> "pizza_types"
# I thought I could pass these params in and fetch the correct pizza model, but not working.
fetch
pizza_type_id: pizza_type_id
id: id
reset: true
parse: (data) ->
data
PizzaType Attributes with example data:
PizzaType: {
id: 2,
name: "Gourmet",
pizzas: [
0: {
id: 4,
pizza_type_id: 2
name: "gourmet pizza 1"
},
1: {
id: 5,
pizza_type_id: 2,
name: "gourmet pizza 2"
}
]
For url in pizza model you can specify an attribute like pizza_type for model in initialize function and change url function like this
class Entities.Pizza extends Backbone.Model
initialize: (options)->
#pizza_type = options.pizza_type if options.pizza_type
url: ->
"pizza_types/" + #pizza_type + "/pizzas/" + #id
parse: (data) ->
data
class Entities.PizzaType extends Backbone.Model
urlRoot: "pizza_types/"
url: ->
#urlRoot+#id+'/pizzas' if #id
initialize: ->
#pizzas = new Entities.PizzasCollection
#pizzas.fetch reset: true
parse: (response) -> response
In PizzasCollection add addOptions so when adding models to collection then backbone add with this default options
class Entities.PizzasCollection extends Backbone.Collection
model: Entities.Pizza
addOptions:
'pizza_type': #id
url: 'pizzas'
parse: (data) -> data
"NetworkError: 404 Not Found -
http://localhost:3000/pizza_types/3/pizzas"
This is a problem with your server, maybe mistyping, or trailing-slash problems or any server problems.
P.S : I recommend using a relational model (with any plugin can do that like BackboneRelationals)

How can I improve the structure and initialization of this controller using Backbone and Marionette

I'm developing a small app with Backbone and Marionette, that displays in a sidebar a list of department and in a main container a list of employee.
User can select a department and filter the employee list by department. Here is the code of the controller and router, but I'm not satisfied of how I have to initialize the app in the controller.
the controller:
Users = require('../collections/users.coffee')
Departments = require('../collections/departments.coffee')
UserListView = require('../views/user-list.coffee')
DepartmentListView = require('../views/department-list.coffee')
module.exports = class Controller extends Marionette.Controller
###
initialize
----------
###
initialize: ->
#users = new Users()
#userListView = new UserListView(collection: #users)
#departments = new Departments()
#departmentListView = new DepartmentListView(collection: #departments)
#app = new Backbone.Marionette.Application()
#app.addRegions(
users: '.js-users-container'
departments: '.js-departments-container'
)
#app.users.show(#userListView)
#app.departments.show(#departmentListView)
#app.on("initialize:after", ->
Backbone.history.start()
)
# App will start when the department list is rendered
#listenTo(#departmentListView, 'composite:collection:rendered', =>
#app.start()
)
# catch filter events
#listenTo(App.events, 'filter-users', (filters) =>
#users.fetch(data: filters)
)
# load the departments collection, will render department list view
#departments.fetch(data: active: 1)
###
index
-----
###
index: ->
App.events.trigger('filter-users', null)
###
getByDepartment
---------------
###
getByDepartment: (id) ->
App.events.trigger('filter-users', department: id)
The router:
Controller = require('./controllers/main.coffee')
module.exports = class Router extends Backbone.Marionette.AppRouter
appRoutes:
"": "index"
"department/:id": "getByDepartment"
initialize: ->
#controller = new Controller()
Initialization of the app:
router = new Router()
How could I improve this code?
Thanks in advance for your help!
You shouldn't be creating a new Application inside your controller. You should create a single Application and then add modules to it containing the various areas of functionality that you need. Here is a basic example below:
var app = new Backbone.Marionette.Application();
app.addRegions({
users: '.js-users-container',
departments: '.js-departments-container'
});
// more app initialisation from the function in your controller
app.module('i-need-a-good-name', function (Module, App, Backbone, Marionette, $, _) {
// controller etc in here
});
app.start();

How to detect invalid route and trigger function in Backbone.Controller

Is there any method to detect invalid (or undefined) route and trigger 404 page in Backbone.Controller?
I've defined routes in my Controller like this, but it didn't work.
class MyController extends Backbone.Controller
routes:
"method_a": "methodA"
"method_b": "methodB"
"*undefined": "show404Error"
# when access to /#method_a
methodA: ->
console.log "this page exists"
# when access to /#method_b
methodB: ->
console.log "this also exists"
# when access to /#some_invalid_hash_fragment_for_malicious_attack
show404Error: ->
console.log "sorry, this page does not exist"
UPDATE:
I used constructor of Backbone.Controller to match current hash fragment and #routes.
class MyController extends Backbone.Controller
constructor: ->
super()
hash = window.location.hash.replace '#', ''
if hash
for k, v of #routes
if k is hash
return
#show404Error()
routes:
"method_a": "methodA"
"method_b": "methodB"
"*undefined": "show404Error"
# when access to /#method_a
methodA: ->
console.log "this page exists"
# when access to /#method_b
methodB: ->
console.log "this also exists"
# when access to /#some_invalid_hash_fragment_for_malicious_attack
show404Error: ->
console.log "sorry, this page does not exist"
The above works, but I'm not sure why you have to do what you do in the constructor. It may be slightly brittle, but we create a separate controller that we include in last. Its last so that the splat route is the last one to match:
NotFound = Backbone.Controller.extend({
routes: {
"*path" : "notFound"
},
notFound: function(path) {
var msg = "Unable to find path: " + path;
alert(msg);
}
});
new NotFound();
Using a more robust version of the above seems a cleaner approach to me.

Resources