I am trying to pass a model as parameter in a view.
I am getting my object in the view, but no way to access its attributes...
Here is the code :
From the router :
var Product = new ProductModel({id: id});
Product.fetch();
var product_view = new ProductView({el: $("#main-content"), model: Product});
From the model :
var ProductModel = Backbone.Model.extend({
urlRoot: 'http://192.168.1.200:8080/store/rest/product/'
});
From the view :
ProductView = Backbone.View.extend({
initialize: function(){
console.log(this.model);
this.render();
},
render: function(){
var options = {
id: this.model.id,
name: this.model.get('name'),
publication_start_date: this.model.get('publication_start_date'),
publication_end_date: this.model.get('publication_end_date'),
description: this.model.get('description'),
applis_more: this.model.get('applis_more')
}
var element = this.$el;
var that = this;
$.get('templates/product.html', function(data){
var template = _.template(data, options);
element.html(template);
});
}
});
Here is the result of the "console.log":
child {attributes: Object, _escapedAttributes: Object, cid: "c1", changed: Object, _silent: Object…}
Competences: child
Editor: child
Hobbies: child
Opinions: child
_changing: false
_escapedAttributes: Object
_pending: Object
_previousAttributes: Object
_silent: Object
attributes: Object
createdDate: null
deletedDate: null
descriptionId: 0
galleryImage: null
id: 13
image: null
manufacturerId: 0
name: "sdf"
owner: 0
status: 0
thumbnail: null
titleId: 0
type: 1
uid: "fdsf"
updatedDate: null
__proto__: Object
changed: Object
cid: "c1"
id: 13
__proto__: ctor
In my view, all my options are "undefined" (name, dates,...)
Any idea on what I am doing wrong ?
After creating the initial model, you're immediately creating the view using
var product_view = new ProductView({..., model: Product});
In the initialize method of ProductView, you're calling this.render(), which in turn reads and renders values from the model - most of these values are undefined (because the server did not have sufficient time to send back the model's values).
Don't call this.render() directly, but bind an event, eg:
// in ProductView::initialize
this.model.on('sync', function() {
this.render();
}, this);
You might also want to bind the change event, so that local (not synchronizsed yet) changes to the model are also reflected in the view. (An overview of Backbone events can be found here.)
Because Product.fetch() happens asynchronously, you'll want to create the view once the data has been retrieved from the server:
var Product = new ProductModel({id: id});
var product_view;
Product.fetch().done(function() {
product_view = new ProductView({el: $("#main-content"), model: Product});
});
Product.fetch() is an asynchronous call, so my guess is that the fetch has not completed yet when you initialize the view. What you probably want to do is use fetch's success + error callbacks, to assure the model has data in it before rendering anything
http://backbonejs.org/#Model-fetch
Related
I'm fairly new to ember and I'd like to know whats the fastest way to extract the data out of ember objects. I've loaded my model with a very large amount of records using this.store.find('modelName);` in my route.
I created a component on my view using {{kendo-ui.kendo-table descriptor=tableDescriptor data=model}}. My controller defined other arguments to be passed to my component (descriptor).
In my components.js I'm' getting the data passed over by using
export default Ember.Component.extend({
didInsertElement: function() {
var columns = this.get('descriptor.columns'); // this is right
var model = this.get('data')['content']; // this returns the objects of the model
var height = this.get('descriptor.height'); // this is ok too
Ember.$('#kendo-table').kendoGrid({
dataSource: {
data: model,
pageSize: 100
},
height: height,
scrollable: {
virtual: true
},
groupable: true,
sortable: true,
columns: columns
});
}
});
On the line var model = this.get('data')['content'];, this gives me an Array of Ember Classes. Inside each class, there is a _data object that holds the value of the actual class.
The easiest solutions is to just loop through and extract the _data but that is no good for larger model array. Is there a quick way to extract all the _data from my array of ember objects?
You could use getProperties method. http://emberjs.com/api/classes/Ember.Object.html#method_getProperties
To get the values of multiple properties at once, call getProperties with a list of strings or an array:
record.getProperties('firstName', 'lastName', 'zipCode');
// { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
You could define computed property dataArray:
dataArray: function() {
return this.get('data').map( function(item) {
return item.getProperties('id', ... ); // your list of properties
});
}.property('data.[]'),
didInsertElement: function() {
//...
Ember.$('#kendo-table').kendoGrid({
dataSource: {
data: this.get('dataArray'),
//...
},
// ...
});
}
UPDATE:
for records (DS.Model) you could use toJSON method. Use DS.JSONSerializer to get the JSON representation of a record.
toJSON takes an optional hash as a parameter, currently supported options are:
includeId: true if the record's ID should be included in the JSON representation.
http://emberjs.com/api/data/classes/DS.Model.html#method_toJSON
I have a backbone model and collection. In the model, the default attribute values are defined:
var Person = Backbone.Model.extend({
defaults: {
name: "mark",
middle: "-"
}
});
var People = Backbone.Collection.extend({
model: Person
});
var collection = new People();
collection.add({name: "paul", middle: null});
console.log('collection is ');
console.log(collection);
I want the default value for "middle", which is "-", to be taken if "null" is passed in for the attribute "middle". However, "null" overrides the default instead. How do I do this? The jsfiddle is here
The cleanest way probably is to add a parse method and normalize the data:
var Person = Backbone.Model.extend({
defaults: {
name: 'mark',
middle: '-'
},
parse: function (payload) {
return {
name: payload.name || undefined,
middle: payload.middle || undefined
};
}
});
collection.add({name: "paul", middle: null}, {parse: true});
Note that when the data is returning from the server via fetch it will automatically go through parse and there's no need to call pass the option flag.
You could do it either on the model level or at the collection level.
check for value when initialize
initialize: function() {
if (!this.get("middle") || $.trim(this.get("middle") || '') === '') {
this.set({"middle": this.defaults.middle});
}
},
What I mean by this is I want to create it artificially.
This is for testing purposes.
But for models, it is quite simple. I just set defaults I instantiate the model object and from there I can use this.model.toJSON() to grab the created data.
I want to use this same trick with collections. Is there a similar way to do this with collections? What I would want to do is have the collection create x ( 8 in this case ) copies of Model defaults.
Basically what I was doing before for models but a little bit more complex as it applies to Collections.
Here is the actual use case. It should be simple.
/**Model
**/
// name, picture, time, tweet, h_file
var FeedRow = Backbone.Model.extend({
Name: 'FeedRow',
defaults: {
name: "default",
picture: 0,
time: "0",
tweet: "default",
h_file: "default"
}
});
/**Collection
**/
var FeedTable = Backbone.Collection.extend({
Name: 'FeedTable',
model: FeedRow
});
When your FeedTable collection is constructed you could set the model on it multiple times in the initialize method.
var FeedTable = Backbone.Collection.extend(
{
Name: 'FeedTable',
model: FeedRow,
initialize: function()
{
model = this.model;
models = [];
_.times(8, function(n)
{
models.push(new model({id: (n + 1)}));
});
this.set(models);
}
});
I am working with a Playlist object which has some properties defining itself as well as a PlaylistItem collection.
When I receive data from my server, I get its JSON response in my client-side success method:
success: function (data) {
console.log("JSON data:", data);
playlists = _.map(data, function (playlistConfig) {
return new Playlist(playlistConfig);
});
...
}
Here, I convert my JSON data into Playlist objects. Each Playlist object is a Backbone.Model.
Here's how my data looks:
And here's what the Playlist constructor looks like:
return function(config) {
var playlist = new Playlist(config);
return playlist;
};
var Playlist = Backbone.Model.extend({
defaults: function() {
return {
id: null,
userId: null,
title: 'New Playlist',
selected: false,
position: 0,
shuffledItems: [],
history: [],
items: Backbone.Collection.extend({
model: PlaylistItem
})
};
},
...
}
My problem:
If I create a Playlist object with defaults, it initializes with an empty Backbone.Collection for PlaylistItem. However, if I create a Playlist object with an already-defined collection, I get a basic array and not a Backbone.Collection. This is because I am working with JSON data from the server which has not been converted to Backbone entities yet. That data is extended over the Playlist's defaults and overwrites the Backbone.Collection entity.
What is a proper way to initialize with a populated Backbone.Collection? I could write code in Initializes which checks the type of my items array and if it is not a Backbone.Collection I could create a new Backbone.Collection and add the items to it and then replace the old array with the new one, but that seems really hoakey.
Don't define your PlalistItems Collection inside defaults, but beforehand.
Then, create an initialize method on your Playlist Model like so:
var PlaylistItems = Backbone.Collection.extend({
...
});
var Playlist = Backbone.Model.extend({
initialize: function() {
this.set('items', new PlaylistItems(this.items));
},
defaults: function() {
return {
id: null,
userId: null,
title: 'New Playlist',
selected: false,
position: 0,
shuffledItems: [],
history: [],
items: [] // don't define your PlaylistItems Collection here
};
}
});
Check out the fiddle here: http://jsfiddle.net/georgedyer/r2XKb/
(you'll need to open the console to see the collection)
Another issue I ran into was after you save your model to the server you will get back a response that will change your embedded collection into a regular javascript array. To remedy this I had to override the parse function on my model class like so:
var model = backbone.Model.extend({
urlRoot : "/rest/model",
initialize: function(){
this.set("myCollection", new MyCollection(this.myArray));
},
defaults: {
myArray: []
},
parse: function(response){
this.set(response);
this.set("myArray", new MyCollection(response.myArray));
}
});
I have the next data coming from the server and I want to map this data to my model by calling ko.mapping.fromJS(data, AcquisitionDetailsModel);
By inspecting the AcquisitionDetailsModel, after calling the specified method, I see that the model contains acquisitions: Object[0]. Why? I was expecting to find the array of acquisitions inside my model. What I'm doing wrong?
data: Object
acquisitions: Array[2]
0: Object
acquisition: Object
date: "2012-06-20"
__proto__: Object
provider: Object
id: "1"
name: "Some name"
__proto__: Object
truck: Object
mark: "DAF"
model: "95FX"
__proto__: Object
__proto__: Object
1: Object
length: 2
The models are looking like this:
function TruckModel() {
this.mark = ko.observable("");
this.model = ko.observable("");
}
function AcquisitionModel() {
this.date = ko.observable("acquisition_date");
}
function ProviderModel() {
this.id = null;
this.name = ko.observable("name");
}
var AcquisitionDetailsModel = {
acquisitions: ko.observableArray([{
acquisition: new AcquisitionModel(),
provider: new ProviderModel(),
truck: new TruckModel()
}])
}
Actually the mapping was done right but it was me who was doing debugging in the wrong way :)
After ko.mapping.fromJS(data, AcquisitionDetailsModel); if I call AcquisitionDetailsModel.acquisitions() I can see my data.
Also, by calling AcquisitionDetailsModel.acquisitions()[0].truck.model() I still can see the right data.
Stupid me :)