I have defined two models that each have a Many-to-Many relationship. I want to show a certain amount of 'people' to be a part a 'department'. How would I insert more people into a department? When I try to insert a 'person' into a 'department', the 'department' does not recognize the person's name as being a part of the 'person' model.
I've stated the relationship in the model
VpcYeoman.Department = DS.Model.extend({
departmentName: DS.attr('string'),
departmentMembers: DS.hasMany('person')
});
&
VpcYeoman.Person = DS.Model.extend({
profileName: DS.attr('string'),
profileDepartment: DS.hasMany('department')
});
And the controllers
VpcYeoman.PeopleController = Ember.ObjectController.extend({
actions: {
createPerson: function () {
// Get the todo title set by the "New Todo" text field
var profileName = this.get('profileName');
if (!profileName.trim()) { return; }
// Create the new Todo model
var person = this.store.createRecord('person', {
profileName: profileName,
isCompleted: false
});
// Clear the "New Todo" text field
this.set('profileName', '');
// Save the new model
todo.save();
}
}
});
VpcYeoman.DepartmentsController = Ember.ArrayController.extend({});
I won't post the HTML (.hbs) templates because they are incorrect.
var person = this.store.createRecord('person', {
profileName: 'joe shmo'
});
var dept = this.store.createRecord('department', {
departmentName: 'admin'
});
dept.get('departmentMembers').pushObject(person);
person.get('profileDepartment').pushObject(dept);
Related
I have a list of product-tag that I fetch for my model.
Route:
model: function() {
return {
product_tags: this.store.find('product-tag', {merchant: merchId})
}
}
I have a component that adds tags to the model, however when after I create the record and push it into the model (as suggested on other posts) my UI still isn't updating.
addTag: function(name) {
tag = this.store.createRecord('product-tag', {
name: name
});
this.model.product_tags.toArray().addObject(tag);
tag.save();
}
//model merchant.js
export default DS.Model.extend({
user_id: DS.attr('number'),
product_tags: DS.hasMany('product-tag', {async: true})
});
//model product-tag.js
export default DS.Model.extend({
merchant: DS.belongsTo('merchant'),
name: DS.attr('string'),
});
What am I doing wrong? Thanks in advance.
You should make it array in the route, so u can use it always afterwards like u want. Your calling toArray() which makes a new Array instance, then your model is not hooked to the array u just made.
model: function() {
return {
product_tags: this.store.query('product-tag', {merchant: merchId}).then(function(pt) {
return pt.toArray();
});
}
}
var x = this.get('model.product_tags') === model's p_t // true
var y = this.get('model.product_tags').toArray() === model's p_t // false
Later on just do
addTag: function(name) {
this.get('store').createRecord('product-tag', {
name: name
}).save().then(function(saved){
this.get('model.product_tags').pushObject(saved);
}.bind(this);
}
I have a store with "row" and "column" models (tr and td in the html), buttons add rows and columns into rows.
I want to save the changes to server only when a "save" button is pressed.
At this time have done this code, it nearly work, but I have some problem with the "save" method :
The "id" of row and columns came from server when they are saved, but when a row is saved it don't know allready the columns id, and visversa. So that the save method is buggy and the code not nice at all.
I beggin with Ember, certainly there is a better way to do that ?, thank you if you can give me some help.
May be also something could be better done in my addRow and addColumn methods ?
Ember 1.11 with restAdapter
App.IndexRoute = Ember.Route.extend({
model: function () {
return this.store.find('row');
},
setupController: function(controller, model) {
controller.set('model', model);
}
});
App.Row = DS.Model.extend({
titre: DS.attr('string'),
columns: DS.hasMany('column', {async: true, embedded: 'always'}),
});
App.Column = DS.Model.extend({
titre: DS.attr('string'),
row: DS.belongsTo('row', {async: true}),
});
App.RowSerializer = DS.RESTSerializer.extend({
serializeHasMany: function(record, json, relationship) {
var hasManyRecords, key;
key = relationship.key;
hasManyRecords = Ember.get(record, key);
if (hasManyRecords && relationship.options.embedded === "always") {
json[key] = [];
hasManyRecords.forEach(function(item, index) {
json[key].push(item.get('id'));
});
}else{
this._super(record, json, relationship);
}
}
});
App.IndexController = Ember.Controller.extend({
selectedColumn: null,
actions: {
save: function(){
var row = this.store.all('row');
row.forEach(function(r, index, self){
r.save().then(function(r2){
r2.get('columns').forEach(function(c){
c.set('row',r2);
c.save().then(function(){
r.save();
})
})
})
})
},
clickCol: function(column){
this.set('selectedColumn', column)
},
addRow: function(){
_this = this;
var newRow = _this.store.createRecord('row',{titre:'Titre row'});
var newColumn = _this.store.createRecord('column', {
titre: 'Titre colonne',
})
newRow.get('columns').addObject(newColumn);
},
addColumn: function(){
_this = this;
this.get('selectedColumn').get('row').then(function(r){
var newColumn = _this.store.createRecord('column', {
titre: 'Titre colonne',
row: r
})
})
}
}
})
EDIT
I did find this :
DS.RESTAdapter: Robust Support for Parent->Child Hierarchies
where there is among other writted : "Allow parent and child records to be saved in the same commit", "[RESTAdapter] Allow new parent, child to be saved at once"...
witch seems to be something like I'm looking for, but can't find anywhere how to make it work ?
also this :
Client-Side IDs with Ember Data
witch say "Consider the case where the user creates a post with several attachments. You’ll need to make sure that the post is saved and has its ID resolved before attempting to save the child models in order to preserve this relationship"...
I stumbled across an issue when I tried to remove a record whose model is in many-to-many relationship to another.
I have Book:
App.Book = DS.Model.extend({
title: DS.attr('string'),
isbn: DS.attr('string'),
category: DS.attr('string'),
publishDate: DS.attr('date'),
authors: DS.hasMany('author', {inverse: 'books'})
});
as well as Author:
App.Author = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
birthDate: DS.attr('date'),
books: DS.hasMany('book', {async: true, inverse: 'authors'})
});
I am removing books like this:
actions: {
delete: function (book) {
var authors = book.get('authors')
authors.forEach(function(author) {
var books = author.get('books')
books.forEach(function(book){
console.log(book.toJSON());
})
books.removeObject(book);
//books.save doesn't work
})
book.destroyRecord();
this.transitionToRoute('books.index');
},
and it correctly removes this book, with DELETE request to backing REST server, but there are no PUT requests for all those authors which had this book in their 'books' collection. When I change view to authors and go back to books one dummy book is created with id of the one I previously removed and 'authors' set to old author as well, other properties are undefined.
How do I correctly remove books so that authors are updated as well?
You have to remember that DS.hasMany returns a promise, so it has to be resolved before you can use it:
actions: {
delete: function (book) {
if (!book.get('isDeleted')) {
book.destroyRecord()
.catch(function(error) {
console.log(error);
book.rollback();
})
.then(function(book) {
book.get('authors').then(function (authors) {
authors.mapBy('books').forEach(function(books) {
if (typeof books.then === "function") {
books.then(function(books) {
books.removeObject(book);
});
} else {
books.removeObject(book);
}
});
});
});
}
this.transitionToRoute('books.index');
}
},
Looks like I've solved it.
First issue was that on the server-side of my project I incorrectly populated data - the ids were wrong and didn't match those from their relation.
Another thing was saving incorrect object. I was trying to save only the array with books, had to save whole author instead (actually that makes sense). Working action is this:
console.log('Removing book: ' + book.get('id') + book.get('title'));
var authors = book.get('authors')
var id = book.get('id');
authors.forEach(function (author) {
var books = author.get('books').removeObject(book);
author.save();
})
book.destroyRecord();
this.transitionToRoute('books.index');
My only doubt was that the delete action is defined in BookController, whose model is the book I am trying to delete, so I shouldn't put the book in a parameter but use controller's model instead. And I've just found that it's easily achievable by just removing the parameter and declaring book as this.get('model'), that's why the final, working solution is this:
delete: function () {
var book = this.get('model')
console.log('Removing book: ' + book.get('id') + book.get('title'));
var authors = book.get('authors')
var id = book.get('id');
authors.forEach(function (author) {
var books = author.get('books').removeObject(book);
author.save();
})
book.destroyRecord();
this.transitionToRoute('books.index');
}
I'm trying to get my head around Ember Data by creating a simple attendance app. The goal is to have a student type in their name and hit submit, creating a new Attendance record that is associated with that student. Here's what I've done to make it work:
App.Student = DS.Model.extend({
name: DS.attr('string'),
attendances: DS.hasMany('attendance', { async: true })
});
App.Attendance = DS.Model.extend({
student: DS.belongsTo('student', { async: true }),
...
});
--
App.NewAttendanceController = Ember.ObjectController.extend({
content: {},
actions: {
createAttendance: function() {
var studentName = this.get('name');
this.store.find('student', { name: studentName })
.then(function(fulfilledPromise) {
var student = fulfilledPromise.get('firstObject');
var attendance = fulfilledPromise.store.createRecord('attendance', {
time: moment(),
student: student
});
attendance.save();
});
}
}
});
In the createAttendance action I first grab the inputted name, find matching student records, wait for the fulfilled promise before grabbing the first student, then create a new attendance record with it's student property set to the grabbed student record and save it.
So this works, but it feels really strange. I'm hoping someone could show me a better way to go about selecting records and making associations in Ember Data.
I have not been able to filter the childrecords of objects in ArrayController.
The structure of my models is like this:
var Shop = DS.Model.extend({
name: DS.attr('string'),
products: DS.hasMany('product')
});
var Product = DS.Model.extend({
name: DS.attr('string'),
shop: DS.belongsTo('shop')
});
Shop has many products, and product belongs to a shop. I would like to filter the childrecords of each parent based on a Ember.TextField. Filtering works if I'm only filtering the parent records based on a property they have, using a regexp.
productSearchResults: function() {
var productSearchTerm = this.get('productSearchTerm');
var regExp = new RegExp(productSearchTerm,'i');
Ember.Logger.log('productSearchTerm', productSearchTerm);
var filteredResults = this.map(function(shop){
var products = shop.get('products');
return products.filter(function(product){
regExp.test(product.get('name'));
});
});
// all items are returned always..
return filteredResults;
}.property('products.#each', 'productSearchTerm')
Edit
I tried to use promises here (source: Filter child-records (hasMany association) with Ember.js ), but it seems like this productSearchResults property is never accessed. I do not get any log output from here. In the template, I'm looping over filteredProducts and there is nothing there. If it's of any relevance, I'm using Ember 1.5.0 and Ember Data 1.0.0-beta.7+canary.b45e23ba .
productSearchResults: function() {
var _that = this;
var productSearchTerm = this.get('productSearchTerm');
var regExp = new RegExp(productSearchTerm,'i');
this.store.find('shop').then(function(shops) {
var promises = shops.map(function (shop) {
return Ember.RSVP.hash({
shop: shop,
products: shop.get('products').then(function (products) {
return products.filter(function (product) {
return regExp.test(product.name);
});
})
});
});
Ember.RSVP.all(promises).then(function (filteredProducts) {
_that.set('filteredProducts', filteredProducts);
});
});
}.property('products.#each', 'productSearchTerm')