嵌入多对多关系-如果一个新对象还不存在,则添加一个新的对象

Ember many to many relationship - add a new object if one does not already exist

本文关键字:对象 一个 不存在 添加 如果 新对象 关系      更新时间:2023-11-11

我有两个彼此有多对多关系的模型-第一个是"配方",第二个是"标签":

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:中调用"AddTags"

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,输出

在中进行演示

现在来解释一下。。。

您在jsbin中使用DS.FixtureAdapter,如果要像按名称查询一样查询fixture(请参见此处),则需要实现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() 进入

如果你什么都没找到,你可以继续做你以前的事情。。。

如果您确实找到了一个现有的标签,您可以将其添加到其他标签中,然后保存标签和配方记录,因为这是一种多对多的关系。

更新

此处更新解决方案

你的for循环变得很混乱,尤其是在使用promise时,这通常不是你想要的。相反,Ember有一种更典型/功能性的forEach()方法。我还修剪了标签末尾的空白,因为这可能是您使用map()所想要的。请参阅此处了解有关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

标记未正确删除。因为这是一个双向映射,显然你需要从食谱中删除标签(你正在做),也需要从标签中删除食谱,你没有做。更新后的代码如下:

removeTag: function(tag) {
  var recipe = this.get('model');
  recipe.get('tags').removeObject(tag);
  tag.get('recipes').removeObject(recipe.get('id'));
  tag.save();
  recipe.save();
},

工作(希望这次是真的;)这里的解决方案

您可以如下搜索现有标签:

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);
    }
}

我现在还不能对此进行测试,所以它可能需要一些更改来解释承诺等——但这应该或多或少能满足你的需求。