我有两个模型彼此有多对多的关系 - 第一个是' recipe',第二个是'标签':
App.ApplicationAdapter = DS.FixtureAdapter.extend({});
App.Recipe = DS.Model.extend({
title: attr('string'),
source: attr('string'),
notes: attr('string'),
isFavourite: attr('boolean', {defaultValue: false}),
tags: hasMany('tag', { async: true })
});
App.Tag = DS.Model.extend({
name: attr('string'),
recipes: hasMany('recipe', { async: true })
});
在我的模板中,我有一个用于向配方添加标签的输入。 用户可以通过用逗号分隔每个标记来添加一个标记或多个标记。
{{input type="text" enter="AddTags" placeholder="add a tag (or two!)"}}
这称为“添加标签”'在我的RecipeController中:
App.RecipeController = Ember.ObjectController.extend({
actions: {
AddTags: function(tags){
var store = this.store;
var thisRecipe = this.get('model');
var thisRecipeTags = thisRecipe.get('tags');
var addedTags = tags.split(',');
for (i = 0; i < addedTags.length; i++) {
tag = store.createRecord('tag', {
name: addedTags[i]
});
thisRecipeTags.addObject(tag);
}
}
}
});
这非常有效 - 然而 - 我想重构该函数,以便只创建一个新标记如果已经具有相同名称的存在:
AddTags: function(tags){
var store = this.store;
var thisRecipe = this.get('model');
var thisRecipeTags = thisRecipe.get('tags');
var addedTags = tags.split(',');
for (i = 0; i < addedTags.length; i++) {
// If exisiting tag where name == addedTags[i]
tag = existing tag object here
// Else create a new tag
tag = store.createRecord('tag', {
name: addedTags[i]
});
thisRecipeTags.addObject(tag);
}
}
我该怎么做?
更新:我在这里设置了一个带有相关代码的JS bin:http://jsbin.com/kixexe/1/edit?js,output
答案 0 :(得分:2)
工作演示here
现在有一些解释......
您在jsbin中使用DS.FixtureAdapter
,如果您要查询灯具(请参阅here),则要求您实施queryFixtures
方法,就像您在按名称查询时所做的那样。快速实现这一点可以如下:
MyApp.TagAdapter = DS.FixtureAdapter.extend({
queryFixtures: function(fixtures, query){
var result = [];
var tag = fixtures.findBy('name', query.name);
if(tag){
result.push(tag);
}
return result;
}
});
当您查询商店时,您会收到使用then()
如果你没有找到任何东西 - 你可以继续前所未有的......
如果 找到现有标记 - 您可以将其添加到其他标记,然后保存标记和配方记录,因为这是多对多关系。
<强>更新强>
更新了解决方案here
你使用for
循环时会感到困惑,尤其是在使用promises时,这通常不是你想要的。相反,Ember有一个更典型/功能性的forEach()
方法我也修剪了标签末端的空白,因为这可能是你想要的map()
。请参阅here,详细了解map()
和forEach()
// trim whitespace
var addedTags = tags.split(',').map(function(str){
return str.replace(/^\s+|\s+$/gm,'');
});
// loop through tags
addedTags.forEach(function(tagName){
store.find('tag', { name: tagName }).then(function(results){
if(results.content.length){
thisRecipeTags.addObject(results.content[0]);
thisRecipeTags.save();
thisRecipe.save();
}
else {
var tag = store.createRecord('tag', {
name: tagName
});
thisRecipeTags.addObject(tag);
thisRecipeTags.save();
thisRecipe.save();
}
});
});
更新#2
标签未正确删除。因为这是一个双向映射,显然你需要从配方中删除标签(你正在做的)和标签中的ALSO配方,你没有这样做。更新后的代码如下所示:
removeTag: function(tag) {
var recipe = this.get('model');
recipe.get('tags').removeObject(tag);
tag.get('recipes').removeObject(recipe.get('id'));
tag.save();
recipe.save();
},
工作(希望这次真实;)解决方案here
答案 1 :(得分:1)
您可以按如下方式搜索现有标签:
var existing = store.find('tag', { name: addedTags[i] });
所以,你可以有以下逻辑:
AddTags: function(tags){
var store = this.store;
var thisRecipe = this.get('model');
var thisRecipeTags = thisRecipe.get('tags');
var addedTags = tags.split(',');
for (i = 0; i < addedTags.length; i++) {
var existing = store.find('tag', { name: addedTags[i] });
if(existing){
tag = existing
} else {
tag = store.createRecord('tag', {
name: addedTags[i]
});
}
thisRecipeTags.addObject(tag);
}
}
我目前无法对此进行测试,因此可能需要进行一些更改才能解释承诺等等 - 但这应该会让您或多或少地得到所需的信息。