Skip to content
This repository has been archived by the owner on Nov 22, 2021. It is now read-only.

Support for array of objects as a list of tags #46

Closed
mbenford opened this issue Dec 16, 2013 · 28 comments
Closed

Support for array of objects as a list of tags #46

mbenford opened this issue Dec 16, 2013 · 28 comments

Comments

@mbenford
Copy link
Owner

Currently the directive only supports arrays of strings as a list of tags. Although that probably covers most use cases, it could also support an array of objects so applications that have a list like this

[
    { id: 1, name: 'Tag 1' },
    { id: 2, name: 'Tag 2' },
    { id: 3, name: 'Tag 3' }
]

wouldn't need to convert it to an array of strings in order to use ngTagsInput. That introduces a new problem, though. Since a tag now carries more information than just its "name", a user won't be able to create a new tag by simply typing a string. Adding a tag will only be possible by selecting an autocomplete suggestion.

@benheymink
Copy link

This would be a great addition!

@VaclavObornik
Copy link

"Since a tag now carries more information than just its "name", a user won't be able to create a new tag by simply typing a string. "

what about create new type by inheriting String prototype? Then you can pass such objects and everything could work well. Or just add some metadata of tags as simple properties of String object...

But it's not tested, and it could work only if these strings are not copied in the ngTagsInput.

@benheymink
Copy link

Thanks, will give it a try. To be honest, in my scenario I'm not bothered about preventing the user from being able to type free form tags, I'm using mine more as a 'search results accumulator', if that makes sense.

@mbenford
Copy link
Owner Author

@ufon The problem with a list of objects is that the user won't be able to provide enough information to create a new object by simply entering a string. For instance, say we have an array like the following:

[
    { id: 1, name: 'Tag 1' },
    { id: 2, name: 'Tag 2' },
    { id: 3, name: 'Tag 3' }
]

How would the user provide a valid id so a new tag can be created? She couldn't (and perhaps she shouldn't either). In such a case, all she could do is enter some text, wait for the autocomplete to show up and then select a suggestion, which in turn would contain all needed information to create a new tag. Under these circumstances the directive would behave much like a "search results accumulator", as @benheymink has said. Which is, by the way, a perfectly valid use case for the directive.

@VaclavObornik
Copy link

@mbenford I understand what you mean. In case I described, user could write just name of new tag... And when you detect adding String object without metadata, you know that you should create one new tag (send request to server for example, server searches existence of the tag name and returns metadata for new one or existing one). Once that have been done, you can inject metadata to the String object - everything transparently for the user.

@Ciget
Copy link

Ciget commented Jan 27, 2014

Guys, any updates on this issue?

@benheymink
Copy link

@Ciget I managed to hack about with the source and get support for what I wanted. It's messy but it works.

@mbenford
Copy link
Owner Author

@Ciget

This is planned for the next release (1.2 or 2.0, I'm still thinking about it). I'll start working on it at some point in this week.

Regardless of the release itself, the code will be pushed to master as soon as it's done, so you'll be able to use it from there. All you'll have to do is build it yourself (which is a no-brainer. Just run grunt pack and you're done).

Kind regards.

@Ciget
Copy link

Ciget commented Jan 27, 2014

thanks

@mbenford
Copy link
Owner Author

mbenford commented Feb 6, 2014

Hi guys. //cc @KrisBraun, @jrencz, @FoxxMD

I've been thinking about how to best implement this feature and I'd like to share with you what I've got so far:

  • A new configuration option will be provided so the user can define what property should be used as a tag label;
  • New tags will be allowed to be added right from the input box. In this case a new object will be created containing only one property filled with the tag text. (e.g. if one types "tag" and press enter, { text: 'tag' } will be added - assuming text is the configured property name);
  • The autoComplete directive will expect an array of objects just like the tagsInput directive, and the same property will be used in order to render suggestions;
  • Tags added from the autocomplete list will carry with them any property they may have (e.g. if the autocomplete list contains objects like { id: 1, text: 'tag' }, then that very object will be added to the list of tags);

In order to carry out of all of above and keep the current implementation (which relies on an array of strings) working I'll probably have to do several checks throughout the code, and I really want to avoid doing that. So I'm considering dropping support for arrays of strings and making the directive work with arrays of objects only. I reason that arrays of objects cover more use cases and it's easy to convert them back into array of strings, if one ever needs to. I could also implement a one-time conversion from a list of strings to a list of objects, much like Select2 does.

I'd really like to hear your feedback.

@FoxxMD
Copy link
Contributor

FoxxMD commented Feb 6, 2014

To add to your second point: default to a new object with the default configured property but also include an onSuggestionCreate event that

  • passes the default suggestion object in as an argument
  • if it returns anything, the resulting object will then be used in lieu of the default

This way users have the opportunity to transform the new suggestion into whatever they want it to be before passing it into the list of objects.

Optionally instead of creating a new event you could extend the functionality into onTagAdded ?

I also think that implementing a one-time conversion from a list of strings -> list of objects is a reasonable fix to insure compatibility as long as users can accept output of data in autocomplete will be strictly an array of objects.

Overall it sounds like a good plan of attack. If there's anything I can do to help I'd be happy to.

@benheymink
Copy link

One other option that might be nice is to only allow tags to be selected from the autocomplete?

@Ciget
Copy link

Ciget commented Feb 6, 2014

benheymink, Completly agree with you. I`ve raised already this point.

@FoxxMD
Copy link
Contributor

FoxxMD commented Feb 6, 2014

@Ciget @benheymink I agree that would be another nice option to add but I think it should be treated as a separate feature as it's not essential to providing functionality for this one. This issue has also already been brought up ( #60 )

That might also be the case for my suggestion on extending onTagAdded but @mbenford should decide that.

@mbenford
Copy link
Owner Author

mbenford commented Feb 6, 2014

@benheymink @Ciget

Don't worry. I didn't forget about that (as FoxxMD pointed out, there's an issue for that already), but I think it's another feature not directly related to this one.

@FoxxMD

That's probably a nice feature to have, but as you said it yourself, it may be better to be another issue after this one has been released.

@KrisBraun
Copy link

This all sounds good. No issue requiring objects -- that's how I expected things to work.

@FoxxMD
Copy link
Contributor

FoxxMD commented Feb 11, 2014

@mbenford Are you currently working on this? If so could you create a remote branch with the work you've done so far? I'd like to contribute/help out if I can.

@mbenford mbenford modified the milestones: 2.0.0, post-1.1.1 Feb 12, 2014
@mbenford
Copy link
Owner Author

@FoxxMD It's almost done. There are some things that need to be refactored before I can push the code but the major part is almost finished.

It's been a busy week for me and I can't afford to spend much time on this project, but I intend to wrap everything up by the weekend.

I appreciate your interest. :)

@adrianhara
Copy link

Can't wait for it, great work on the directive btw :)

@mbenford
Copy link
Owner Author

@benheymink @Ciget

Today I've realized that it's already possible to make the directive accept tags from the autocomplete list only: it's just a matter of turning off four options: addOnEnter, addOnSpace, addOnComma and addOnBlur.

I still think there could be a single option to turn that behavior on, but nevertheless it's possible to achieve it with the current version.

@JoeChapman
Copy link

I know I'm late to the party, but I wanted to pipe in and describe how I am circumventing this issue.

I am using lo-dash and using pluck when the promise is resolved;

promise.then(function (items) {
    items = _.pluck(items.tags, 'labels');
    ......

I don't need to worry about items possibly already being an array of string, but if it were, some simple conditional logic could suffice.

Using this, albeit, very simple technique, means I can use the data in the format [{}, {}. {}] to create autocomplete suggestions and create my own tags.

@daric81
Copy link

daric81 commented Apr 1, 2014

I like the support for an array of objects, however, I still need ngTagsInput to work with an array of strings and have not yet found a way to get this working. This makes 2.0.0 unusable for me currently. My scenario, I have dynamic field creation based on a schema. I already have a directive which assigns ng-Model to a property on the scope. Is there a way to support an array of string within a directive?

@mbenford
Copy link
Owner Author

mbenford commented Apr 1, 2014

Hi @daric81.

From 2.0 on the directive started to support only array of objects. But it should be easy for you to convert it into an array of strings when needed by doing prop.map(function(item) { return item.text; });. In your case I guess you could use a watch along with an auxiliary array in order to keep a string-only version of the tag list.

Another option is to keep using v1.1.1, assuming that version works for you.

Kind regards.

@daric81
Copy link

daric81 commented Apr 2, 2014

@mbenford being a noob, I think the easieist option for us is to use 1.1.1 and fix the $dirty/$pristine issue removing a tag.
Cheers

@mbenford
Copy link
Owner Author

mbenford commented Apr 2, 2014

@daric81 Take a look at this plunk I've just created. Hopefully it might help you keep using v2.0.

@daric81
Copy link

daric81 commented Apr 3, 2014

@mbenford Thanks, very useful. I'll use this in a directive so that the copied array lives on its isolated scope. Looks like ill be using v2.0 after all :)

@MrSam
Copy link

MrSam commented Dec 9, 2015

Probably late to the party, but whenever I get data from PHP and I don't need any keys I do what's called 'go from assoc to stupid'.

function drop_keys_from_object(items) {
    // go from assoc to stupid
    var filtered = [];
    angular.forEach(items, function(item) {
        filtered.push(item);
    });
    return filtered;
}

This way ngTagsInput is nice with your data. (and anything else that needs repeating in angular)

@pelted
Copy link

pelted commented Dec 14, 2015

Just ran across this thread trying to find a way to unwrap the array of objects this thing is creating from our array of strings. Quickly reading through this I just don't understand why the decision was made to actually change the data structure of the ngModel source. It seems that since this is an input form wrapper it shouldn't be modifying the data format at all.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests