Trying to make an editable array


#1

I have an attribute on one of my models that is an array of string urls. I would like to edit this with a text field for each item in the array, with the ability to add or remove items. Has anyone done this before?

I don’t believe I can edit the array directly, so my guess is I need to map the array to an array of objects, e.g.

[
  { url: 'http://www.example.com', index: 0 },
  { url: 'http://www.example.com', index: 1 },
  { url: 'http://www.example.com', index: 2 }
]

And then map back to an array of strings before saving. However, I am not sure how to implement this. Any input or advice would be much appreciated!


#2

You could use a computed property. Example, assuming your URLs are newline-separated:

Model = DS.Model.extend({
  urls: DS.attr('string'),

  urlObjects: function(key, value, previousValue) {
    // setter
    if (arguments.length > 1) {
      this.set('urls', value.mapBy('url').join("\n"));
    }

    return this.get('urls').split("\n").map(function(url, index) {
      return Ember.Object.create({url: url, index: index});
    });
  }.property('urls')
});

Eventually, the computed property syntax is improving, so the getter and setter portions are clearer.


#3

I can’t seem to get that to work. Here’s a jsbin:

It doesn’t ever seem to call the function as a setter, so the array never gets updated.


#4

Hmm, when I type in one of the fields, the URL in the numbered list updates. That’s not what you’re seeing?


#5

Hmm… that’s showing a later version where I got it to half work. The original version I tried to send just used the same getter/setter computed property like your example shows, but it never calls it as a setter.

The later version works for a single character, but then the input loses focus.

I ended up writing a custom transform to convert arrays into objects, e.g. [1, 2] -> { item: 1, index: 0 }, { item: 2, index: 1 } which seems to be working reasonably well.