Why specifying Model in Backbone Collection - collections

What is the aim of specifying a model in a Backbone collection? It seems that the collection need its own url. Why do this:
Backbone.Collection.extend({
url: '/rest/product',
model: Model
});
Instead of:
Backbone.Collection.extend({
url: '/rest/product'
});
With a model like this:
var Model = Backbone.Model.extend({
url: function() {
return '/rest/product/' + this.id;
}
});
Is there a way to group url declaration?

What is the aim of specifying a model in a Backbone collection
Backbone.Collection.extend({
url: '/rest/product',
model: Model
});
Basically your saying every model inside the collection is an instance of Model. It's also useful for doing this
col.add({
prop1: "foo",
...
});
And it will call new Model({prop1: "foo", ... }) for you and add it to the collection.
.model

Related

How to send data to servlet and retrieve data from servlet using backbone.js

I'm trying to send some data to servlet using backbone js and i want to retrieve that data to backbone.js view. Here i mentioned my model and collection code. Please help me.
ContactManager.Models.Contact = Backbone.Model.extend({
defaults: {
name: null,
tel: null,
email: null,
address:null,
avatar: null
},
url: "/servlet1",
initialize: function() {
this.set('avatar','phone.png');
},
});
ContactManager.Collections.Contacts = Backbone.Collection.extend({
model: ContactManager.Models.Contact
});

Meteor access data context in onCreated

I have a list of tasks and I want to load a list of corresponding comments when I click one of the Tasks.
Iron router code:
Router.route('/taskComments/:_id', function () {
var item = Tasks.findOne(this.params._id);
this.render('commentList', {data: item});
},
{
name: 'taskComments',
fastRender: true
}
);
Template helpers:
Template.commentList.helpers({
comments: function(){
return Comments.find({taskID: this._id});
});
I am able to access the task id (this._id) in the above snippet, but it does not seem to work for onCreated:
Template.commentList.onCreated(function(){
this.subscribe("comments",this._id);
});
When I console log this it gives me the following object:
Notice that there is no _id and data is also null.
You can use Template.currentData() inside of this callback to access reactive data context of the template instance. The Computation is automatically stopped when the template is destroyed.
Template.commentList.onCreated(function(){
var self = this;
var dataContext = Template.currentData()
self.subscribe("comments",dataContext._id);
});

Different URLs for Model and Collection in Titanium Alloy

Env: Titanium 3.1.3, Alloy 1.2.2.
I'm using the following adapter for persistence on the models/collections: https://github.com/viezel/napp.alloy.adapter.restapi
I have an API that has a different URL structure for a collection than it does a single model. Consider the following:
To get a single record: [GET] /files/:id
To get all the files for a user: [GET] /users/:id/files
I have the following schema for files.js:
exports.definition = {
config: {
"URL": "https://my.api.here/files",
//"debug": 1,
"adapter": {
"type": "restapi",
"collection_name": "files",
"idAttribute": "id"
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {
initialize: function(){
this.url = "http://my.api.here/users/"+this.user_id+"/files";
}
});
return Collection;
}
}
What I'm trying to do in the above is override the collection initialize method to change the URL structure for the collection. I then call this accordingly:
var currentUserFiles = Alloy.createCollection("files", {user_id:"12345"});
currentUserFiles.fetch({
success: function(files){
console.log("Woo! Got the user's files!");
console.log(JSON.stringify(files.models));
},
error: function(){
console.log("Nope");
}
});
This doesn't work. The fetch() method just continues to try to call /files. I've tried setting url as a property on the collection after it's created, that also don't work.
Ideally, I'd like to do this for both local instances as well as the singleton version of the collection.
So - the question is: can I utilize a different URL for a collection than I do for a model? Obviously, I don't want to just call /files and sort/filter client-side - that'd be a nightmare with a lot of records. What am I missing here?
It's a bit late but for anyone else that comes across this. I problem is where/how the url is specified for model and collection. The model needs a specific id (eg: primary key) passed into it because the model can only be one object. If you need more than one object, then use the collection. Hope this helps :)
extendModel : function(Model) {
_.extend(Model.prototype, {
url : function() {
return "http://my.api.here/users/"+this.user_id+"/files/"+ FILE_ID
},
});
return Model;
},
extendCollection : function(Collection) {
_.extend(Collection.prototype, {
url : function() {
return "http://my.api.here/users/"+this.user_id+"/files"
},
});
},

AJAX promise without Ember Data

I have decided to not use ember-data as it's not production ready and still changing. My app only needs to make a few ajax requests anyway so it shouldn't make too big of a difference. I am having trouble understanding how to handle an ajax promise response.
When my user loads the app they already have an authenticated session. I am trying to ping the server for that users info and display it in my template. It seems my template is rendered before my ajax request returns results and then does not update with the promise.
// route
App.ApplicationRoute = Ember.Route.extend({
setupController: function(){
this.set("currentUser", App.User.getCurrentUser());
}
});
// model
App.User = Ember.Object.extend({
email_address: '',
name_first: '',
name_last: '',
name_full: function() {
return this.get('name_first') + ' ' + this.get('name_last');
}.property('name_first', 'name_last')
});
App.User.reopenClass({
getCurrentUser: function() {
return $.ajax({
url: "/api/get_current_user",
type: "POST",
data: JSON.stringify({})
}).then(function(response) {
return response;
});
}
});
In my template:
<h1> Hey, {{App.currentUser.name_first}}</h1>
How would I update the template when I receive a response or delay rendering until I have a response?
Actually the answer is quite easy: You do not need to use a promise. Instead just return an empty object. Your code could look like this:
App.User.reopenClass({
getCurrentUser: function() {
var user = App.User.create({}); //create an empty object
$.ajax({
url: "/api/get_current_user",
type: "POST",
data: JSON.stringify({})
}).then(function(response) {
user.setProperties(response); //fill the object with your JSON response
});
return user;
}
});
What is happening here?
You create an empty object.
You make an asynchronous call to your API...
... and in your success callback you fill your empty object.
You return your user object.
Note: What is really happening? The flow mentioned above is not the sequence in which those actions are happening. In reality the points 1,2 and 4 are performed first. Then some time later, when the response returns from your server, 3 is executed. So the real flow of actions is: 1 -> 2 -> 4 -> 3.
So the general rule is to always return an object that enables Ember to do its logic. No values will be displayed first in your case and once your object is filled Ember will start do its magic and auto update your templates. No hard work needs to be done on your side!
Going beyond the initial question: How would one do this with an array?
Following this general rule, you would return an empty array. Here a little example, which assumes, that you might like to get all users from your backend:
App.User.reopenClass({
getAllUsers: function() {
var users = []; //create an empty array
$.ajax({
url: "/api/get_users",
}).then(function(response) {
response.forEach(function(user){
var model = App.User.create(user);
users.addObject(model); //fill your array step by step
});
});
return users;
}
});
I'd use Ember.Deferred instead of returning an empty array as mentioned before.
App.User.reopenClass({
getAllUsers: function() {
var dfd = Ember.Deferred.create();
var users = [];
$.ajax({
url: "/api/get_users",
}).then(function(response) {
response.forEach(function(user){
var model = App.User.create(user);
users.addObject(model);
});
dfd.resolve(users);
});
return dfd;
}
});
In your model hook all you have to do is this
model: function(){
return App.User.getAllUsers();
}
Ember is smart enought and knows how to handle the promise you return, once it's resolved the model will be correctly set, you can also return a jQuery promise but it will give you some weird behavior.
You can as well set the current user as the model for your ApplicationRoute like so:
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return App.User.getCurrentUser();
}
});
Since getCurrentUser() returns a promise, the transition will suspend until the promise either fulfills or rejects.
This is handy because by the time transition is finished your model is initialized and you will see it rendered in the template.
You can read up more about async routing in Ember guides.

How to get jQuery.Ajax to perform a normal POST with a redirect using ASP.NET MVC

I currently have a JSON object on my page which gets built up as users add items to it. This is all done in JavaScript/jQuery.
When the user is done adding items, I want to POST this object to a controller action and have the action return a strongly typed view using this data.
Currently, I have the jQuery.ajax POST sending this JSON object to an Action Method which then binds this object to my strongly typed Model. Problem is, I actually want this jQuery.ajax POST to redirect as if the JSON object were in a FORM and simply being submitted.
I also can't use the jQuery.post() method, which would redirect as required, as I need to be able to set the contentType to "application/json" so my binding works correctly. Unfortunately, the jQuery.post() method doesn't allow you to set this parameter.
I've read that the jQuery.post() method basically uses the jQuery.ajax() method, so I've been battling to get the jQuery.ajax() method to redirect.
I've also read that I can set the default contentType for all jQuery.ajax() methods which would then allow me to use the jQuery.post() method but want to try avoid this if possible.
Thanks
Edit: Updated with Saedeas suggestion:
My JavaScript on the 'Index' View:
<script language="javascript" type="text/javascript">
// Initialize the Shopping Cart object
var m_ShoppingCart = {
UserId: 10,
DeliveryInstructions: "Leave at front desk",
CartItems: []
};
$(document).ready(function () {
$.extend({
postJSON: function (url, data, callback) {
return $.ajax({
type: "POST",
url: url,
data: JSON.stringify(data),
success: callback,
dataType: "json",
contentType: "application/json",
processData: false
});
}
});
});
function PostDataWithRedirect() {
var url = '#Url.Action("ConfirmOrder", "Store")';
$.postJSON(url, m_ShoppingCart, function () { });
}
function AddToCart(id, itemName, price, quantity) {
// Add the item to the shopping cart object
m_ShoppingCart.CartItems.push({
"Id": id,
"ItemName": itemName,
"Price": price.toFixed(2), // Issue here if you don't specify the decimal place
"Quantity": quantity
});
// Render the shopping cart object
RenderShoppingCart();
}
function RenderShoppingCart() {
$("#CartItemList").html("");
var totalAmount = 0;
$.each(m_ShoppingCart.CartItems, function (index, cartItem) {
var itemTotal = Number(cartItem.Price) * Number(cartItem.Quantity);
totalAmount += itemTotal;
$("#CartItemList").append("<li>" + cartItem.ItemName + " - $" + itemTotal.toFixed(2) + "</li>");
});
$("#TotalAmount").html("$" + totalAmount.toFixed(2));
}
</script>
And then the Controller Action 'ConfirmOrder'
[HttpPost]
public ActionResult ConfirmOrder(ShoppingCartModel model)
{
return View(model);
}
So when the PostDataWithRedirect() JavaScript method is called it must hit the ConfirmOrder Controller Action and be redirected to the ConfirmOrder View. The Shopping Cart object on my Index view is built up entirely in JavaScript and the user then clicks a 'Proceed to Checkout' button and is redirected etc.
PS: My full working example can be found in an the article [ How to POST a JSON object in MVC ], I just need to update this code so that it can do the post and redirect as explained above
In the success method, do a location.href = "TARGET LOCATION" to cause the page to go to TARGET LOCATION.
$.ajax({
url: myurl,data,
data: myData,
// processData: false, // you may need this option depending on service setup
success: function(){
location.href = "TARGET LOCATION";
},
type: "POST",
contentType: "application/json"
});
Return a view that redirects:
controller
return View("redirectionView");
view
RedirectionView.cshtml
#{
Layout = null;
}
<script type="text/javascript">
alert("Success! Redirecting...");
window.location = "./";
</script>
EDIT
To accommodate data retention use tempdata.
controller
TempData["collectedUserData"] = collectedData;
return View("redirectionView");
RedirectionView.cshtml
#{
Layout = null;
}
<script type="text/javascript">
alert("Success! Redirecting...");
window.location = "./Rebuilder/ActionMethod";
</script>
Controller Rebuilder
public ActionResult ActionMethod()
{
if( TempData.ContainsKey("collectedUserData") )
{
var collectedData = TempData["collectedUserData"];
}
//todo: use else clause to catch data not present
use collectedData to build new view
return View();
}
Maybe I'm not following the question, but why does the classic post, redirect, get pattern not work?
[HttpGet]
public ActionResult WhateverActionName()
{
YourViewModel yvm = new YourViewModel();
//Initalize viewmodel here
Return view(yvm);
}
[HttpPost]
public ActionResult WhateverActionName(YourViewModel yvm)
{
if (ModelState.IsValid) {
RedirectToAction("OtherAction", "OtherController")
}
return View(yvm);
}
Do you mean you want to do a post, have it bind to the viewmodel for validation purposes in one controller, and then have that controller post to another controller that verifies everything? If so, I suggest taking a look at this code to post in c# http://geekswithblogs.net/rakker/archive/2006/04/21/76044.aspx.
Edit: Or you could just place the data in a tempdata object if the other controller action doesn't truly require a post.
Edit 2: Wait, is the question how to do the post with jquery? If so,
$("#YourForm").submit(function () {
$.post('#Url.Action("WhateverActionName", "YourController")';
});
});
Note: may be small syntax errors, but close to that. The #Url.Action is the important part.
Edit 3: This should finally work.
jQuery.extend({
postJSON: function(url, data, callback) {
return jQuery.ajax({
type: "POST",
url: url,
data: JSON.stringify(data),
success: callback,
dataType: "json",
contentType: "application/json",
processData: false
});
}
});
Call it in your view as
$.postJSON('#URL.Action("Action", "Controller")', yourJson, callback)
And then redirect inside the controller.

Resources