List editor and events of its items editors - backbone-views

I have a very simple model:
var ListItem = Backbone.Model.extend({
schema: {
name: 'Text',
}
});
and another simple model which has a list inside:
var Configuration = Backbone.Model.extend({
schema: {
list: {
type: 'List',
itemType: 'NestedModel',
model: ListItem
}
}
});
and a form:
var form = new Backbone.Form({ model: configuration }).render();
I need to listen to the events on the ListItem's "name" editor.
When I use this:
form.on('all', function() { console.log('print something') });
I did not get anything from the "name" editor.
I've also tried a lot of other events names but non of them was working in that case.
How can I listen to the change events on the ListItem's "name" editor?

Related

Emberjs - Custom Adapter

I'm quit new into the world of the Adapter in Ember, and I would like to create a custom one to save some data into the webSQL database for the compatible browser.
It might look very simple but I'm stuck at the beginning of this process.
I have this in a separate file :
DS.WebSQLAdapter = DS.Adapter.extend({
dbName: 'testDb',
dbVersion: '1.0',
dbDisplayName: 'Test Db',
dbSize: (2 * 1024 * 1024),
init: function() {
this.db = cont.openDatabase( this.dbName, this.dbVersion, this.dbDisplayName, this.dbSize );
},
createRecord: function( store, type, query, recordArray ) {
console.log(data);
}
})
In my app.js file :
window.App = Ember.Application.create({});
App.ApplicationAdapter = DS.WebSQLAdapter;
And when I do this in my controller :
App.ApplicationController = Ember.ArrayController.extend({
actions: {
myAction: function() {
this.store.createRecord('someDB', {key: 'test', title: 'myTitle'});
}
}
})
It says that it couldn't found the model someDB.. Do I need to create a model as well for my adapter even though I'm using websql to fetch the data ?
It's telling you that SomeDB doesn't exist. Ember is expecting the following to be in your code somewhere:
App.SomeDB = DS.Model.extend({});
If you don't declare a SomeDB model, you can't create a new record of that type. (At least not with the Ember-Data store.)

Force ember route to request additional data before rendering

I'm trying to get a nested route to make a request for additional data, update the record, and then render the view. See below:
// models
var attr = DS.attr,
hasMany = DS.hasMany,
belongsTo = DS.belongsTo
App.List = DS.Model.extend({
title: attr('string'),
links: hasMany('link')
})
App.Link = DS.Model.extend({
list: belongsTo('list'),
subtitle: attr('string'),
})
// JSON for index route
{
"list": [
{
"id": 532,
"title": "first list"
},
{
"id": 991,
"title": "second list"
},
{
"id": 382,
"title": "third list"
}
]
}
// JSON for list route - /user/532
{
"list":
{
"id": 532,
"title": "list numero uno",
"links" : [1, 2]
},
"link": [
{
"id": 1,
"subtitle": "this is a subtitle of the firsto listo!"
},
{
"id": 2,
"subtitle": "this is a subtitle of a second part in the list"
}
]
}
// routing
this.resource('user', function(){
this.route('list', {path: ':id'})
})
App.UserRoute = Ember.Route.extend({
model: function(){
return this.store.find('list')
}
})
App.UserListRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('list', params.id)
}
})
I want the index route to display a basic list with just the {{title}}, and clicking on one links it to UserListRoute which then makes another ajax call to update the record with the additional link data. I've tried adding:
afterModel: function(modal){
model.reload()
}
to the UserListRoute but it initially uses the index route model, and then it reloads with the new data. I'm trying to avoid this, and make it send an ajax request immediately and then render the content - so I don't want it to depend on the parent model/data.
create a different record type, and extend from the original, or just use a completely different model.
App.BasicList = DS.Model.extend({
foo: DS.attr()
});
App.FullList = App.BasicList.extend({
//foo
bar: DS.attr()
});
App.UserListRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('fullList', params.id)
}
})
I tried with kingpin2k's answer, and it worked on a page refresh but navigating from the user index to the nested still caused it to use the parent model. I figured out why it wasn't used the correct model. My links on the user index template were:
{{#link-to 'user.list' this}} {{title}} {{/link-to}}
So clicking on link correctly redirects me to /users/:id, but it passes on the data of the item selected. To remedy this I did:
{{#link-to `user.list` id}} {{title}} {{/link-to}}
So by changing this to id, when it transitions to the route, it uses the appropriate model specified in the route.

ember-data: Updating a record with a many-to-many relationship?

I have a File and a Tag model, which are in a many-to-many relationship:
App.File = DS.Model.extend
name: DS.attr('string')
tags: DS.hasMany('tag')
App.Tag = DS.Model.extend
name: DS.attr('string')
files: DS.hasMany('file')
I'm reading the data as JSON generated via Rails backend, and so far everything works fine. I'm trying to write a tagFile function in my Ember route that tags a file with a specific tag. This works fine on the ember side but of course it doesn't persist, and I can't figure out how to send the proper HTTP request to the Rails backend. So I have
App.FilesRoute = Ember.Route.extend
...
actions:
tagFile: (file, tag) ->
file.get('tags').pushObject(tag)
tag.get('files').pushObject(file)
# file.save() ? or something similar?
I've tried file.save(), which sends a PUT request, but the sent params hash in Rails does not include the Tag record at all. I set a breakpoint in the updateRecord() method inside ember-data, and examined the data variable before it gets sent via AJAX, and this variable does not include the Tag record either.
What is the correct way to send an HTTP request (PUT or otherwise) where I can pass along my child record into the params hash? Is there a way to pass arbitrary data using ember-data methods? I could write my own AJAX call but then it seems like I'm not taking advantage of ember-data. Any insights?
Using: Ruby 2/Rails 4 backend, Ember 1.3.0-beta.1+canary.48513b24, Ember-data 1.0.0-beta.4+canary.c15b8f80
file.get('tags').pushObject(tag);
tag.save();
file.save();
Dual hasMany will connect them together http://emberjs.jsbin.com/OxIDiVU/94/edit
If you want to create a custom serializer for one of the types to include the other. Here's a slightly modified one from ED
App.FileSerializer = DS.RESTSerializer.extend({
serialize: function(record, options) {
var json = {};
if (options && options.includeId) {
var id = get(record, 'id');
if (id) {
json[get(this, 'primaryKey')] = get(record, 'id');
}
}
record.eachAttribute(function(key, attribute) {
this.serializeAttribute(record, json, key, attribute);
}, this);
var tags = [];
record.eachRelationship(function(key, relationship) {
if (relationship.kind === 'belongsTo') {
this.serializeBelongsTo(record, json, relationship);
} else if (relationship.kind === 'hasMany') {
record.get(relationship.key).forEach(function(tag){
tags.push(tag.toJSON());
});
//this.serializeHasMany(record, json, relationship);
}
}, this);
json.tags = tags;
return json;
}
});
http://emberjs.jsbin.com/OxIDiVU/95/edit
Or a more specific serializer
App.FileSerializer = DS.RESTSerializer.extend({
serialize: function(record, options) {
var json = {},
tags=[];
json.id = record.get('id');
json.name = record.get('name');
record.get('tags').forEach(function(tag){
var tagJson = {};
tagJson.id = tag.get('id');
tagJson.name = tag.get('name');
tags.push(tagJson);
});
json.tags = tags;
return json;
}
});
http://emberjs.jsbin.com/OxIDiVU/96/edit

Get belongsTo ID without fetching record

I'm trying to fetch the belongsTo ID without fetching the actual record. My JSON API returns the ID for the belongsTo relation.
I have the following models
App.Recipe = DS.Model.extend(
title: DS.attr()
ingredients: DS.hasMany('ingredient', async: true)
)
App.Ingredient = DS.Model.extend(
recipe: DS.belongsTo('recipe')
product: DS.belongsTo('product', async: true)
)
App.Product = DS.Model.extend(
title: DS.attr()
)
This is my route:
App.RecipeIndexRoute = Ember.Route.extend(
model: (args) ->
#store.find('recipe', args.recipe_id)
)
This is my controller:
I'm trying to find the product id within this controller.
App.RecipeIndexController = Ember.ObjectController.extend(
hasRecipeInCart: null
actions:
toggleCart: ->
#content.get('ingredients').then((ingredients) =>
# how do I get product id here, without lookup up the product relation?
# this 'get' makes Ember call: /api/v1/products/1
# I simply want the product ID (in this case 1), without having to call the server again.
ingredient.get('product').then((product) =>
product.id # => 1
)
My JSON looks like this:
HTTP GET: /api/v1/recipes/1
{
"recipe": {
"id":1,
"title":"Recipe 1",
"ingredients":[2,1]
}
}
HTTP GET: /api/v1/ingredients?ids[]=2&ids[]=1
{
"ingredients": [
{
"id":2,
"recipe":1,
"product":1
},
{
"id":1,
"recipe":1,
"product":2
}
]
}
This is now much easier with the ds-reference feature that was added to ember data. You can now do:
var authorId = post.belongsTo("author").id();
See http://emberjs.com/blog/2016/05/03/ember-data-2-5-released.html#toc_code-ds-references-code
A ton of work is going into redoing the relationships, you can pull it out of the underlying properties from the data attribute model.get('data.product.id')
Example: http://emberjs.jsbin.com/OxIDiVU/16/edit
For ED 2.x, relationships have been reworked and were broken for getting underlying data until the ds-references feature landed.
To do this in ED 2.4+, you need to use the new belongsTo method to work with underlying data.
To get an id for a belongsTo ref:
var id = this.get('model').belongsTo('myBelongsToKey').value();

Accessing controller properties within Ember Data REST Adapter

I need to access a controller property to build custom URLs in my RESTAdapter instances, but I can't find a way to access the controller within the context of an adapter. Here's what I have:
I have a simple model that looks like this:
App.Customer = DS.Model.extend(
{
first_name: DS.attr('string'),
last_name: DS.attr('string'),
date_of_birth: DS.attr('string'),
created_at: DS.attr('string'),
updated_at: DS.attr('string')
});
The resource REST URL for this model looks something like this:
https://api.server.com/v1/accounts/:account_id/customers/:customer_id
I'm extending the RESTAdapter in Ember Data for most of my models so I can customize resource URLs individually. Like this:
App.CustomerAdapter = DS.RESTAdapter.extend(
{
buildURL: function(type, id)
{
// I need access to an account_id here:
return "new_url";
}
});
As you can see, in this example I need an account ID in the URL to be able to query a customer object. The account ID is something that the user would have had to supply by logging-in and is stored in an AccountController which is an instance of Ember.Controller.
My question is, how can I access a property from my AccountController within my CustomerAdapter? Here are the things I've tried, none have worked:
App.CustomerAdapter = DS.RESTAdapter.extend(
{
buildURL: function(type, id)
{
var account_id = this.controllerFor('account').get('activeAccount').get('id');
return "new_url";
}
});
,
App.CustomerAdapter = DS.RESTAdapter.extend(
{
needs: ['account'],
accountController: Ember.computed.alias("controllers.account"),
buildURL: function(type, id)
{
var account_id = this.get('accountController').get('activeAccount').get('id');
return "new_url";
}
});
,
App.CustomerAdapter = DS.RESTAdapter.extend(
{
activeAccountBinding = Ember.Binding.oneWay('App.AccountController.activeAccount');
buildURL: function(type, id)
{
var account_id = this.get('activeAccount').get('id');
return "new_url";
}
});
At this point, the only hack I can think of, is to put the account ID in a global variable outside of Ember and access it from there within the Adapter.
Other suggestions?
We have a similar problem, and essentially we do a global variable, and feel guilty about it. Ours is in Ember Model, but the same concept and problem exists. Another solution is to use findQuery, but this returns a collection, so then you have to pull the item out of the collection.
App.CustomerAdapter = DS.RESTAdapter.extend(
{
buildURL: function(type, id)
{
var params = type.params;
return "new_url" + params.account_id;
}
});
In Some Route:
App.BlahRoute = Em.Route.extend({
model: function(params){
App.Customer.params = {account_id:123};
this.get('store').find('customer', 3);
}
});
I know that you can access controller's properties in context of another controller.
I see that you tried somewhat similar, but anyway maybe this would work for adapter:
App.YourController = Ember.ObjectController.extend({
needs: ['theOtherController'],
someFunction: function () {
var con = this.get('controllers.theOtherController');
return con.get('propertyYouNeed');
},
});
Also, have you thought about adding AccountId property to your Customer model?
Maybe automatic URL can be achieved with proper routing?