Backbone relational lazy loading - javascript

I'm using Backbone with my RESTful JSON API in order to create an app that works with posts and their comments. I've been trying to get Backbone Relational to work, but run into problems with my Lazy loading.
I load up a list of posts, without the related comments. On click of an post in the list, I open up a view that fetches the full Post, comments included, and renders this.
I've got 2 Backbone.RelationModels, Posts and Comments. The post relation to the comment is setup as folows:`
relations: [{
type: Backbone.HasMany,
key: 'comments',
relatedModel: 'Comment',
includeInJSON: true, // don't include it in the exporting json
collectionType: 'Comments'
}]
Now the problem I'm facing is that the relationships are initialized as soon as I retrieve my list, that do not contain the comments yet. I load up the full data later, by fetching the model by it's URI. However, the relationships don't seem to reinitialise, calling Posts.get(1).get('comments') returns a Comments collection that is empty!
Does anyone know how I could best tackle this problem? The data is there, it just seems the collection of the comments doesn't gets updated.
Edit: I can make the Post model bind it's change:comments to itself, which updates the collection. However, I can't seem to find a solid way to get the original comments' JSON, since this.get('comments') returns the Comments collection.
Note: In my collection, I do parse the JSON to make it work with my API, with the following code:
parse: function(response) {
var response_array = [];
_.each(response, function(item) {
response_array.push(item);
});
return response_array;
}
This is because the JSON returned by my API returns an object with indexed keys (associative array) instead of a native JSON array.
{
"id" : "1",
"title" : "post title",
"comments" : {
"2" : {
"id" : "2",
"description": "this should solve it"
},
"6" : {
"id" : "6",
"description": "this should solve it"
}
}
}
Thanks a bunch! Please ask any questions, I'm sure I've been vague somewhere!

The Backbone Relational model doesn't parse collections other then arrays, the JSON from my question didn't work. I changed the backend to return the comments in a proper array
{
"id" : "1",
"title" : "post title",
"comments" : [
{
"id" : "2",
"description": "this should solve it"
},
{
"id" : "6",
"description": "this should solve it"
}]
}
}
The RelationalModel doesn't respect the parse function that Backbone provides to parse your JSON before it moves on. With the backend returning "proper" JSON, the lazy loading works without any extra code.

You can also use the initialize method on your comment model, to simulate the parse method and define attributes with custom values like this (CoffeeScript):
initialize: (obj) ->
#attributes = obj.customKey

Related

Mongodb: how to pass current date filter in aggregate pipeline from javascript

I'm trying to get a simple date-filtered aggregation working.
I have documents like:
{
"name" : "Article 1",
"expires" : <some date [type:datetime]>
},
{
"name" : "Article 1",
"expires" : <some other date [type:datetime]>
},
...
I'm trying to query them with an aggregate pipeline over a call from javascript, so my pipeline is passing over as JSON.
I want to get all unexpired documents, but I haven't found a way to use the $$NOW variable that works for me.
var pipeline = [
{'$sort' : {[name] : 1}},
{ "$match": {
"expires": {"$gt": "$$NOW"}
}
}
];
await myGetData(collection, pipeline).then(resp => ...
I've also tried variations of $dateFromString without any success. This should be simple, so I assume I'm doing something dumb.
The issue seems to be getting the correct date format into the pipeline JSON. From other stackoverflow questions, it seems that it needs to be a data object for comparison? Not sure how to describe that in the JSON though.
Could someone please point me in the right direction?
Thanks

Convert JSON naming schema in Ember

I have an application where I retrieve JSON data from a server. Unfortunately the JSON data is formatted as such:
"Product_Group" : [
{
"Product_Group_ID" : "396xx",
"Product_Group_SEO_Copy" : "Not Included in JSON",
"Product_Group_Title" : "Some awesome Title",
"Products" : [
{
"On_Sale_Date" : "04\/28\/09 00:00:00.000",
"ISBN" : "97800617737xx",
"Title" : "A Disgraceful Affair",
//rest of the it follows
Ember throws errors when trying to use Capitalized JSON objects in a template. Specifically the Uncaught TypeError: Cannot read property 'unchain' of undefined error. This is related to this issue noted on the Github Ember site.
My question, how can I convert all the titles from the server into camelCase? I don't have access to the server to change things on that end, so it will have to be client side. I've looked into the DS.RESTSerializer but I don't understand it enough to know if that is what I should be using.
DS.RESTSerializer is exactly what you want to use. You can easily transform the keys of your attributes by using the keyForAttribute hook. You may also need to change the attribute name of your root node Product_Group to something like productGroup. You can do this with extractArray.
A serializer such as this might just do the trick:
App.ProductGroupSerializer = DS.RESTSerializer.extend({
extractArray: function(store, type, payload) {
return this._super(store, type, {
productGroup: payload['Product_Group']
});
},
keyForAttribute: function(attr) {
return Ember.String.camelize(attr);
}
});

Backbone fetch and working with the jqXHR object

I'm working on a new application using Backbone and don't have the backend APIs written yet so I am trying work with a JSON data file local to my project. I set its location as the urlRoot and am able to fetch it and receive the jqXHR object back. But, I am not sure how to interact with the responseText (assuming that's what I need based on the console.log output of the object).
This is the closest question I've found to mine but it wasn't closed with a final answer: backbone model is only returning and object, or JSON {readyState : 1}
var JobListings = Backbone.Model.extend({
urlRoot: 'scripts/app/data/listings.json'
});
// Instantiate the model
var jobListings = new JobListings();
console.log(jobListings.fetch()); // Returns jqXHR object
console.log(jobListings.attributes); // Returns empty object
How do I get at my JSON data? Also, it should be in a model and not a collection right? I am a bit fuzzy as to the role of collections based on other developers use of them. I thought models contain data and collections were sets of models.
My goal was to build two models for the data. One takes in the dirty JSON that needs to be cleaned up and the second being my outputted clean data for use by the application. Any help is much appreciated.
EDIT:
A snippet of my JSON... I'm still not having luck on how to get at my data. I'm sure I don't have to get to a view to see my data before hand.
[
{
"jobId": "1",
"applyUrl": "http://google.com",
"title": "President of the World",
"trackingCode": "1",
"jobDescription": "Stuff",
"requiredSkills": "Stuff",
"requiredExperience": [],
"postingDate": "2013-07-12T11:07:50Z",
"jobLocation": {
"countryCode": "US",
"region": "California",
"municipality": "Santa Monica"
},
"category": "Life",
"businessUnit": [],
"positionType": "Full-Time"
}
]
'Backbone.Model' contains data
'Backbone.Collection' were set of models. Like you can define it as in below:
var Library = Backbone.Collection.extend({
model: Book
});
You normally won't work with jqXHR directly.
Once data is fetched, you can access it "field by field" (or attribute-by-attribute) using get operation:
note.get("title")
You can edit the data using the set operation:
note.set({title: "March 20", content: "In his eyes she eclipses..."});
book.set("title", "A Scandal in Bohemia");
You can return a copy of the data (called attributes) using toJSON operation
Also Backbone will track if data is dirty or not by using hasChanged
Looking at your code, JobListing will be a model with job listing data. JobListings would be a collection of all JobListing models:
var JobListing = Backbone.Model.extend();
var JobListings = Backbone.Collection.extend({,
model: JobListing,
url: 'scripts/app/data/listings.json',
parse: function(data) {
// Not sure about your json structure, but you could do the following
// Do your cleanup here
return data.joblistings;
}
});
// Instantiate the collection
var jobListings = new JobListings();
var req = jobListings.fetch();
req.done(function() {
// contains all job listings
console.log(jobListings.models);
});

ui-data contracts: client side extended validation of json data

I am in a few situations where json I am getting from services and database calls, created by another group, are giving me invalid data combinations, and causing many unintended errors downstream.
Given in the small example below, if the "rowContent" field is equal to "1", it's corresponding "row" needs to be a populated javascript object. "rowContent1" and "row1", and "rowContent2" and "row2" are correct. "rowContent3" and "row3" is not.
I concede the structure of this json is not fantastic. Ok it's a little wacky. It's fairly close to what I am dealing with in production. I have little control over it.
Are there data driven ways to describe json data relationships like this, that validate, before I start trying to use non-existent data in "row3"?
Or, what would you recommend I do in this situation?
thanks much,
-Larry
{ "table" : [
{
"aRowContent" : {
"rowContent1" : "1",
"rowContent2" : "0",
"rowContent3" : "1",
},
"row1" : {
"myRowValue" : "red"
},
"row2" : null,
"row3" : null
}
]
}
Not with JSON Schema, certainly. JSON Schema validates the structure of JSON data without cross-referencing to other bits of data.
I think the issue might be the redundancy in your data structure- why do you need /table/0/aRowContent/rowContent1 when you can deduce the same information from a null-check of /table/0/row1?

How do I return arbitrary JSON objects to a jQuery Autocomplete list?

jQuery part:
I have a jQuery UI 1.8 Autocomplete form that fetches remote JSON data from a Rails controller.
$('input#test').autocomplete({
source: function( request, response ) {
$.getJSON(
"<%= find_stuff_url(:format => :json) %>",
request,
function(data){
console.log(data);
function(data) {
$.map(data, function(item) {
return {
"label" : item.control_point.label,
"value" : item.control_point.geonames_uri
}
});
});
},
minLength: 2,
select: function( event, ui ) {
// ...
}
});
… what I get returned:
This Rails controller just returns an array of Objects (actually, ActiveRecord instances), serialized into JSON. I would like to use this data to populate the Autocomplete list. Right now, what I receive is an array of serialized ActiveRecord objects – for example one of these objects could be:
Object
control_point: Object
geonames_uri: "http://sws.geonames.org/5128581/"
label: "New York (US)"
lat: "40.7142691"
lng: "-74.0059729"
map_id: 1
name: "New York City"
What I need:
However, jQuery Autocomplete probably wants a JSON array of objects that carry id and label to populate its list — yet I don't have these. This is what the documentation says:
A response callback, which expects a single argument to contain the data to suggest to the user. This data […] can be in any of the formats described above for simple local data (String-Array or Object-Array with label/value/both properties).
I don't quite understand what's meant by "String-Array or Object-Array with label/value/both" properties.
In this example, my output would be a list of those control_point Objects, shown like:
label: "New York (US)", value: <the geonames_uri>
label: "New York (Somewhere else)", value: <another geonames_uri>
…
I tried to adapt the code from the documentation using $.map, but it doesn't seem to work (i.e. the autocomplete shows nothing).
How do I pass an arbitrary JSON object to jQuery Autocomplete, so it shows a list of results? More explicitly: What do I have to put in function(data){}?
The documentation (at the same link you posted) explains what is meant by the terms String-Array and Object-Array:
The local data can be a simple Array of Strings, or it contains
Objects for each item in the array, with either a label or value
property or both. The label property is displayed in the suggestion
menu. The value will be inserted into the input element after the user
selected something from the menu. If just one property is specified,
it will be used for both, eg. if you provide only value-properties,
the value will also be used as the label.
So at the end of the day, it's either a String-Array: ["value1", "value2", ...] or an Object-Array:
[
{ label:"First Value", value:"value1" },
{ label:"Second Value", value:"value2" },
...
]
You can choose to either make the required server side changes to serialise the data to look appropriate, or map it client side, as in this example. Either way the end result should be one of the above formats.
So, for example, something like this:
function(data) {
response( $.map(data, function(item) {
return {
"label" : item.control_point.label,
"value" : item.control_point.geonames_uri
}
}));
This is something you'll want to do server-side, i.e. in Ruby on Rails. You could to this:
Give your model (ActiveRecord entity, whatever) a method toAutocompleteResult that returns an Object with just the label and value properties.
In your controller (return_stuff_url?), loop through your result set, call toAutocompleteResult() on them and put the results in an Array of sorts.
Convert the Array to JSON and return it.
I'm not a RoR developer, so I can't give you specific code. But this should be pretty easy to do in any OO language.
Edit: by the way, a JSON string array looks like this:
["String 1", "String 2", "String 3"]
And a JSON Object array would look like this:
[
{ "label" : "Label 1", "value": "Value 1" },
{ "label" : "Label 2", "value": "Value 2" }
]
You need something like this on the server
def my_autocomplete_controller_method
q = params[:term]
records = Record.find_by_whatever q
records.map { |record| {label: record.your_label, value: record.your_value} }
end
On the client (coffescript):
$find_field.autocomplete
source: /path_to_controller_method

Categories

Resources