contact-picker icon indicating copy to clipboard operation
contact-picker copied to clipboard

Closer HTML alignment

Open marcoscaceres opened this issue 6 years ago • 16 comments

Random thought... I wonder if ContactProperty should actually reflect the list of HTML autocomplete names... and, instead of returning a ContactInfo dictionary, the API just returned FormData?

That might be nice, because then you can just POST contacts directly (or use the FormData API to query what you got back). That also works nicely if the API is not available, because then the developer would just fall back to a HTML form.

marcoscaceres avatar Aug 05 '19 02:08 marcoscaceres

I like this idea. How would you see it working with selecting multiple contacts, for instance? Would you see it being a repeated fieldset (containing those autocomplete fields) that would be supplanted by this API, if available?

aarongustafson avatar Aug 05 '19 16:08 aarongustafson

I like the idea of re-using autocomplete names, we might have to do something about icons though.

@marcoscaceres, I'm assuming you mean returning a list of FormData (one per contact), instead of a list of ContactInfo. I think that's a bit awkward with multiple contacts, since you'd have to combine them to create a ContactInfo-like object to serialize them if your goal is just uploading/storing the contacts.

On the other hand, if you goal is to display them in a form before uploading it would be pretty easy to create a form with repeated fieldsets from the ContactInfos (like @aarongustafson suggested).

rayankans avatar Aug 05 '19 18:08 rayankans

@marcoscaceres, I'm assuming you mean returning a list of FormData (one per contact), instead of a list of ContactInfo.

No, was thinking just one FormData object... but...

I think that's a bit awkward with multiple contacts, since you'd have to combine them to create a ContactInfo-like object to serialize them if your goal is just uploading/storing the contacts.

Perhaps. I wonder how clunky would it be to use a single FormData object, given that it supports multiple keys?

marcoscaceres avatar Aug 05 '19 23:08 marcoscaceres

Perhaps. I wonder how clunky would it be to use a single FormData object, given that it supports multiple keys?

I'd imagine the FormData would look something like this, since we'd have to namespace which contact that field belongs to, and the value has to be a string or a blob:

const formData = await navigator.contacts.select(['name', 'email'], {multiple: true});
print(formData);
// c1.name => 'Rayan'
// c1.name => 'rayankans'
// c2.name => 'marcoscaceres'
// c2.email => '[email protected]'

Getting field values would work nicely, even for missing / unshared fields:

formData.getAll('c1.name');  // ['Rayan', 'rayankans']
formData.getAll('c1.email');  // []

But getting the number of contacts is a bit awkward (unless explicitly passed over as well).

new Set([...formData.keys()].map(k => k.split('.')[0])).size;  // 2

I personally find the data in this format hard to interact with, specifically the contact namespacing. One entry per contact in a list is easier to reason about, and easier to transform into any other format.

rayankans avatar Aug 06 '19 15:08 rayankans

Without going down a rathole (that I started, sorry! :)), I don't think you need the namespace:

  1. the caller is the one that requested the contact fields (["name", "email"]), so the API always gives you back the fields, even if they contain no data.
  2. the number of returned contacts is always keys' length/2 (with empties being the empty string).

I guess ultimately what I'm trying to get to with the FormData and HTML autocomplete names is that this information is closely related to HTML Forms... the Credential Management API is another spec that used HTML autocomplete names in a really nice way to create its own objects.

I know I'm telling you things you all already know, but the primary use cases would appear to be:

  1. sending the contacts to a server: the dictionary is simple nice enough that it can just be stringified into JSON. However, for legacy sites that are posting, it means mapping the structure into form fields, and then likely POSTing those (so we are back at FormData).
  2. display - for which either FormData or a dictionary may be suitable.

I think I saw you opted to use a dictionary instead of an interface, but I'm imagining something cute like:

interface ContactInfo extends FormData {
};

Or:

interface ContactInfo {
   ... stuff... 
  FormData toFormData();
  [default] object toJSON();  
}

anyway, these are all half-baked ideas... but wanted to plant a few seeds.

marcoscaceres avatar Aug 07 '19 03:08 marcoscaceres

  1. the number of returned contacts is always keys' length/2 (with empties being the empty string)

I don't think that's true, in the example I constructed c1 has multiple names. Since the FormData entry value has to be a string (or blob, but not applicable in this case), we would need one entry per a contact's property.

I really like switching the ContactInfo to an interface though. It would also solve the feature detection issue #19 I've been considering (thanks for the seed :) ). It's not clear to me though if in your proposed example ContactInfo is per contact, or for all contacts. If it's for all contacts it has the same pitfalls previously discussed. If it's one per contact toFormData wouldn't add much value.

rayankans avatar Aug 07 '19 13:08 rayankans

I was thinking one ContactInfo per contact too, and then we could maybe have a static method:

ContactInfo.toFormData(...contacts);

Which merges them into a single FormData that one could later POST.

marcoscaceres avatar Aug 07 '19 13:08 marcoscaceres

Alright, so putting everything together, this is the new proposed structure:

interface ContactInfo {
    sequence<DOMString> name;
    sequence<DOMString> email;
    sequence<DOMString> tel;
    [default] object toJSON();
    static FormData toFormData(sequence<ContactInfo> contacts);
};

The chosen field names happen to already match the autocomplete names.

I still have a few concerns regarding toFormData, mainly being that we would still need to apply some form of per-contact namespacing, which will be inflexible. @marcoscaceres, how would you feel about letting legacy sites that need to post through a form create their own FormData object? It's simple enough that it's a few lines of code and they will probably prefer matching their server-side implementation from the client rather than changing their server-side implementation to match the weird FormData structure we will need to come up with.

rayankans avatar Aug 07 '19 19:08 rayankans

It's simple enough that it's a few lines of code and they will probably prefer matching their server-side implementation from the client rather than changing their server-side implementation to match the weird FormData structure we will need to come up with.

Re: FormData, I'm ok with the above.

I'm not sure about the sequences:

sequence<DOMString> name;
sequence<DOMString> email;
sequence<DOMString> tel;

I'd suggest just a single value for each. Otherwise it can get a bit crazy because it will inconsistent across UAs what returned order means.... also, from our experience with Payment Request, mapping to NSPersonComponent is hard. If we want alternative names or whatever, then we should add fields for that (again matching what autocomplete in HTML does).

And geessss... I eventually want:

[Constructor(ContactInfo)]
interface ContactInfo extends PaymentAddress {};

But getting ahead of myself :)

marcoscaceres avatar Aug 08 '19 02:08 marcoscaceres

From the peanut gallery: most address books support multiple values for most fields, and looking at my own contact list this applies to many individuals. How would we represent that data w/o sequences?

beverloo avatar Aug 08 '19 13:08 beverloo

I was thinking about the same thing today while looking at both Contacts.app and the HTML spec. Let’s take phone number as a case: in iOS’s contacts, you can have home, work, mobile, main, iPhone, and so on. The current tel sequence obviously can’t distinguish between them.

I think this why we need something MapLike that works similarly to HTML autocomplete.... and why I instinctively reached for FormData (even though it was admittedly the wrong choice!).... but I still think we need something that can capture and distinguish between “home tel” and “work tel”.

Again, take a look at how elegantly HTML autocomplete is able to declaratively extract the right information. We need something similar, and as fine grained.

marcoscaceres avatar Aug 08 '19 14:08 marcoscaceres

Again, take a look at how elegantly HTML autocomplete is able to declaratively extract the right information. We need something similar, and as fine grained.

In https://github.com/WICG/contact-api/issues/12#issuecomment-480186692 I pointed to the vCard standard.

tomayac avatar Aug 08 '19 14:08 tomayac

Just noting the case in #12 is covered by payment request api (heh, I’m totally not biased! 😂)... but Tom’s right about the scope of the problem - and I imagine none of us want to parse vCard or give developers back vCard data 🤢.

I feel like the right solution is within our grasp tho.

marcoscaceres avatar Aug 08 '19 14:08 marcoscaceres

It’s an agreed-on standard and parsing seems like a solved problem, but I see your point…

tomayac avatar Aug 08 '19 15:08 tomayac

I can see why the API should be closely aligned to the HTML standard but not sure if FormData is the right API for this to follow. Is there any reason why the assumption is for these contacts to be only interoperable with HTML forms? I would imagine implementors may want to do something with the data other than submit it through a form.

markcellus avatar Aug 08 '19 15:08 markcellus

I would imagine implementors may want to do something with the data other than submit it through a form.

Apart from displaying it and POSTing it, what else are you envisioning?

I guess “sharing” using web share would be pretty useful. Anything else?

marcoscaceres avatar Aug 08 '19 15:08 marcoscaceres