{"action":"created","comment":{"url":"https://api.github.com/repos/angular/angular/pulls/comments/58149986","id":58149986,"diff_hunk":"@@ -1,63 +1,107 @@\n import {\n-  Query,\n   Directive,\n   Renderer,\n-  Self,\n   forwardRef,\n   Provider,\n   ElementRef,\n-  QueryList\n+  Input,\n+  Host,\n+  OnDestroy,\n+  Optional\n } from 'angular2/core';\n-\n-import {ObservableWrapper} from 'angular2/src/facade/async';\n import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';\n-import {CONST_EXPR} from 'angular2/src/facade/lang';\n+import {CONST_EXPR, StringWrapper, isPrimitive, isPresent} from 'angular2/src/facade/lang';\n+\n+import {MapWrapper} from 'angular2/src/facade/collection';\n \n const SELECT_VALUE_ACCESSOR = CONST_EXPR(new Provider(\n     NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => SelectControlValueAccessor), multi: true}));\n \n /**\n- * Marks `<option>` as dynamic, so Angular can be notified when options change.\n- *\n- * ### Example\n- *\n- * ```\n- * <select ngControl=\"city\">\n- *   <option *ngFor=\"#c of cities\" [value]=\"c\"></option>\n- * </select>\n- * ```\n- */\n-@Directive({selector: 'option'})\n-export class NgSelectOption {\n-}\n-\n-/**\n  * The accessor for writing a value and listening to changes on a select element.\n  */\n @Directive({\n   selector: 'select[ngControl],select[ngFormControl],select[ngModel]',\n   host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},\n-  bindings: [SELECT_VALUE_ACCESSOR]\n+  providers: [SELECT_VALUE_ACCESSOR]\n })\n export class SelectControlValueAccessor implements ControlValueAccessor {\n-  value: string;\n+  value: any;\n+  _optionMap: Map<string, any> = new Map<string, any>();\n+  _idCounter: number = 0;\n+\n   onChange = (_: any) => {};\n   onTouched = () => {};\n \n-  constructor(private _renderer: Renderer, private _elementRef: ElementRef,\n-              @Query(NgSelectOption, {descendants: true}) query: QueryList<NgSelectOption>) {\n-    this._updateValueWhenListOfOptionsChanges(query);\n-  }\n+  constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}\n \n   writeValue(value: any): void {\n     this.value = value;\n-    this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);\n+    var valueString = this._buildValueString(this._getOptionId(value), value);\n+    this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', valueString);\n   }\n \n-  registerOnChange(fn: () => any): void { this.onChange = fn; }\n+  registerOnChange(fn: (value: any) => any): void {\n+    this.onChange = (valueString: string) => { fn(this._getOptionValue(valueString)); };\n+  }\n   registerOnTouched(fn: () => any): void { this.onTouched = fn; }\n \n-  private _updateValueWhenListOfOptionsChanges(query: QueryList<NgSelectOption>) {\n-    ObservableWrapper.subscribe(query.changes, (_) => this.writeValue(this.value));\n+  _registerOption(): string { return (this._idCounter++).toString(); }\n+\n+  _getOptionId(value: any): string {\n+    for (let id of MapWrapper.keys(this._optionMap)) {\n+      if (this._optionMap.get(id) == value) return id;\n+    }\n+    return null;\n+  }\n+\n+  _getOptionValue(valueString: string): any {\n+    return this._optionMap.get(this._extractId(valueString));\n+  }\n+\n+  _buildValueString(id: string, value: any): string {\n+    if (!isPrimitive(value)) value = \"Object\";\n+    return StringWrapper.slice(`${id}: ${value}`, 0, 50);\n+  }\n+\n+  _extractId(valueString: string): string {\n+    return valueString.split(\":\")[0];\n+  }\n+}\n+\n+/**\n+ * Marks `<option>` as dynamic, so Angular can be notified when options change.\n+ *\n+ * ### Example\n+ *\n+ * ```\n+ * <select ngControl=\"city\">\n+ *   <option *ngFor=\"#c of cities\" [value]=\"c\"></option>\n+ * </select>\n+ * ```\n+ */\n+@Directive({selector: 'option'})\n+export class NgSelectOption implements OnDestroy {\n+  id: string;\n+\n+  constructor(private _element: ElementRef, private _renderer: Renderer,\n+              @Optional() @Host() private _select: SelectControlValueAccessor) {\n+    if (isPresent(this._select)) this.id = this._select._registerOption();\n+  }\n+\n+  @Input()\n+  set value(value: any) {\n+    if (this._select == null) return;\n+    this._select._optionMap.set(this.id, value);\n+    this._setElementValue(this._select._buildValueString(this.id, value));","path":"modules/angular2/src/common/forms/directives/select_control_value_accessor.ts","position":127,"original_position":127,"commit_id":"6a4c316db711312a0d34d09791db71dd1d17fa35","original_commit_id":"6a4c316db711312a0d34d09791db71dd1d17fa35","user":{"login":"vsavkin","id":35996,"avatar_url":"https://avatars.githubusercontent.com/u/35996?v=3","gravatar_id":"","url":"https://api.github.com/users/vsavkin","html_url":"https://github.com/vsavkin","followers_url":"https://api.github.com/users/vsavkin/followers","following_url":"https://api.github.com/users/vsavkin/following{/other_user}","gists_url":"https://api.github.com/users/vsavkin/gists{/gist_id}","starred_url":"https://api.github.com/users/vsavkin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vsavkin/subscriptions","organizations_url":"https://api.github.com/users/vsavkin/orgs","repos_url":"https://api.github.com/users/vsavkin/repos","events_url":"https://api.github.com/users/vsavkin/events{/privacy}","received_events_url":"https://api.github.com/users/vsavkin/received_events","type":"User","site_admin":false},"body":"Totally up to you. But if you find accessing _buildValueString via _select awkward, you can make a standalone function. ","created_at":"2016-04-01T00:50:05Z","updated_at":"2016-04-01T00:50:05Z","html_url":"https://github.com/angular/angular/pull/7842#discussion_r58149986","pull_request_url":"https://api.github.com/repos/angular/angular/pulls/7842","_links":{"self":{"href":"https://api.github.com/repos/angular/angular/pulls/comments/58149986"},"html":{"href":"https://github.com/angular/angular/pull/7842#discussion_r58149986"},"pull_request":{"href":"https://api.github.com/repos/angular/angular/pulls/7842"}}},"pull_request":{"url":"https://api.github.com/repos/angular/angular/pulls/7842","id":64723854,"html_url":"https://github.com/angular/angular/pull/7842","diff_url":"https://github.com/angular/angular/pull/7842.diff","patch_url":"https://github.com/angular/angular/pull/7842.patch","issue_url":"https://api.github.com/repos/angular/angular/issues/7842","number":7842,"state":"open","locked":false,"title":"fix(select): support objects as select values","user":{"login":"kara","id":3871688,"avatar_url":"https://avatars.githubusercontent.com/u/3871688?v=3","gravatar_id":"","url":"https://api.github.com/users/kara","html_url":"https://github.com/kara","followers_url":"https://api.github.com/users/kara/followers","following_url":"https://api.github.com/users/kara/following{/other_user}","gists_url":"https://api.github.com/users/kara/gists{/gist_id}","starred_url":"https://api.github.com/users/kara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kara/subscriptions","organizations_url":"https://api.github.com/users/kara/orgs","repos_url":"https://api.github.com/users/kara/repos","events_url":"https://api.github.com/users/kara/events{/privacy}","received_events_url":"https://api.github.com/users/kara/received_events","type":"User","site_admin":false},"body":"* **Please check if the PR fulfills these requirements**\r\n- [x] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format\r\n- [x] Tests for the changes have been added (for bug fixes / features)\r\n\r\n* **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...)\r\nThis fixes a current bug where objects set as option values and/or `[(ngModel)]` on select tags are converted to `[object Object]` strings.\r\n\r\n* **What is the current behavior?** \r\n\r\nFor the following:\r\n\r\n```javascript\r\n@Component({...})\r\nclass MyComp {\r\n   selected: any;\r\n   options: any[] = [\r\n      {name: 'Pepper'},\r\n      {name: 'Salt'},\r\n      {name: 'Paprika'}\r\n   ];\r\n\r\n   constructor() {  this.selected = this.options[1]; }\r\n}\r\n```\r\n\r\n```html\r\n<select [(ngModel)]=\"selected\">\r\n   <option *ngFor=\"#current of options\" [value]=\"current\">{{current.name}}</option>\r\n</select>\r\n```\r\n\r\nYou might expect the select to display \"Salt\", but it displays \"Pepper\" because all option values are set to `[object Object]`.   When selecting new options using the dropdown, the `selected` property on the component class is set to `[object Object]`.\r\n\r\nThis PR allows you to write the above code and have the selection updated on both ends as expected.\r\n\r\n* **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?)\r\nNo breaking changes. \r\n\r\n","created_at":"2016-03-31T01:50:25Z","updated_at":"2016-04-01T00:50:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"91ead59db2f77bc436e7f4ae4e6e157f7ec266d5","assignee":{"login":"vsavkin","id":35996,"avatar_url":"https://avatars.githubusercontent.com/u/35996?v=3","gravatar_id":"","url":"https://api.github.com/users/vsavkin","html_url":"https://github.com/vsavkin","followers_url":"https://api.github.com/users/vsavkin/followers","following_url":"https://api.github.com/users/vsavkin/following{/other_user}","gists_url":"https://api.github.com/users/vsavkin/gists{/gist_id}","starred_url":"https://api.github.com/users/vsavkin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vsavkin/subscriptions","organizations_url":"https://api.github.com/users/vsavkin/orgs","repos_url":"https://api.github.com/users/vsavkin/repos","events_url":"https://api.github.com/users/vsavkin/events{/privacy}","received_events_url":"https://api.github.com/users/vsavkin/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/angular/angular/pulls/7842/commits","review_comments_url":"https://api.github.com/repos/angular/angular/pulls/7842/comments","review_comment_url":"https://api.github.com/repos/angular/angular/pulls/comments{/number}","comments_url":"https://api.github.com/repos/angular/angular/issues/7842/comments","statuses_url":"https://api.github.com/repos/angular/angular/statuses/6a4c316db711312a0d34d09791db71dd1d17fa35","head":{"label":"kara:select","ref":"select","sha":"6a4c316db711312a0d34d09791db71dd1d17fa35","user":{"login":"kara","id":3871688,"avatar_url":"https://avatars.githubusercontent.com/u/3871688?v=3","gravatar_id":"","url":"https://api.github.com/users/kara","html_url":"https://github.com/kara","followers_url":"https://api.github.com/users/kara/followers","following_url":"https://api.github.com/users/kara/following{/other_user}","gists_url":"https://api.github.com/users/kara/gists{/gist_id}","starred_url":"https://api.github.com/users/kara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kara/subscriptions","organizations_url":"https://api.github.com/users/kara/orgs","repos_url":"https://api.github.com/users/kara/repos","events_url":"https://api.github.com/users/kara/events{/privacy}","received_events_url":"https://api.github.com/users/kara/received_events","type":"User","site_admin":false},"repo":{"id":30559627,"name":"angular","full_name":"kara/angular","owner":{"login":"kara","id":3871688,"avatar_url":"https://avatars.githubusercontent.com/u/3871688?v=3","gravatar_id":"","url":"https://api.github.com/users/kara","html_url":"https://github.com/kara","followers_url":"https://api.github.com/users/kara/followers","following_url":"https://api.github.com/users/kara/following{/other_user}","gists_url":"https://api.github.com/users/kara/gists{/gist_id}","starred_url":"https://api.github.com/users/kara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kara/subscriptions","organizations_url":"https://api.github.com/users/kara/orgs","repos_url":"https://api.github.com/users/kara/repos","events_url":"https://api.github.com/users/kara/events{/privacy}","received_events_url":"https://api.github.com/users/kara/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/kara/angular","description":"","fork":true,"url":"https://api.github.com/repos/kara/angular","forks_url":"https://api.github.com/repos/kara/angular/forks","keys_url":"https://api.github.com/repos/kara/angular/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kara/angular/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kara/angular/teams","hooks_url":"https://api.github.com/repos/kara/angular/hooks","issue_events_url":"https://api.github.com/repos/kara/angular/issues/events{/number}","events_url":"https://api.github.com/repos/kara/angular/events","assignees_url":"https://api.github.com/repos/kara/angular/assignees{/user}","branches_url":"https://api.github.com/repos/kara/angular/branches{/branch}","tags_url":"https://api.github.com/repos/kara/angular/tags","blobs_url":"https://api.github.com/repos/kara/angular/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kara/angular/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kara/angular/git/refs{/sha}","trees_url":"https://api.github.com/repos/kara/angular/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kara/angular/statuses/{sha}","languages_url":"https://api.github.com/repos/kara/angular/languages","stargazers_url":"https://api.github.com/repos/kara/angular/stargazers","contributors_url":"https://api.github.com/repos/kara/angular/contributors","subscribers_url":"https://api.github.com/repos/kara/angular/subscribers","subscription_url":"https://api.github.com/repos/kara/angular/subscription","commits_url":"https://api.github.com/repos/kara/angular/commits{/sha}","git_commits_url":"https://api.github.com/repos/kara/angular/git/commits{/sha}","comments_url":"https://api.github.com/repos/kara/angular/comments{/number}","issue_comment_url":"https://api.github.com/repos/kara/angular/issues/comments{/number}","contents_url":"https://api.github.com/repos/kara/angular/contents/{+path}","compare_url":"https://api.github.com/repos/kara/angular/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kara/angular/merges","archive_url":"https://api.github.com/repos/kara/angular/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kara/angular/downloads","issues_url":"https://api.github.com/repos/kara/angular/issues{/number}","pulls_url":"https://api.github.com/repos/kara/angular/pulls{/number}","milestones_url":"https://api.github.com/repos/kara/angular/milestones{/number}","notifications_url":"https://api.github.com/repos/kara/angular/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kara/angular/labels{/name}","releases_url":"https://api.github.com/repos/kara/angular/releases{/id}","deployments_url":"https://api.github.com/repos/kara/angular/deployments","created_at":"2015-02-09T21:32:22Z","updated_at":"2016-01-24T16:23:07Z","pushed_at":"2016-04-01T00:30:54Z","git_url":"git://github.com/kara/angular.git","ssh_url":"git@github.com:kara/angular.git","clone_url":"https://github.com/kara/angular.git","svn_url":"https://github.com/kara/angular","homepage":null,"size":17286,"stargazers_count":0,"watchers_count":0,"language":"TypeScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"angular:master","ref":"master","sha":"20812f446fdc4e8cd99a086091d5c516d3ee295d","user":{"login":"angular","id":139426,"avatar_url":"https://avatars.githubusercontent.com/u/139426?v=3","gravatar_id":"","url":"https://api.github.com/users/angular","html_url":"https://github.com/angular","followers_url":"https://api.github.com/users/angular/followers","following_url":"https://api.github.com/users/angular/following{/other_user}","gists_url":"https://api.github.com/users/angular/gists{/gist_id}","starred_url":"https://api.github.com/users/angular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/angular/subscriptions","organizations_url":"https://api.github.com/users/angular/orgs","repos_url":"https://api.github.com/users/angular/repos","events_url":"https://api.github.com/users/angular/events{/privacy}","received_events_url":"https://api.github.com/users/angular/received_events","type":"Organization","site_admin":false},"repo":{"id":24195339,"name":"angular","full_name":"angular/angular","owner":{"login":"angular","id":139426,"avatar_url":"https://avatars.githubusercontent.com/u/139426?v=3","gravatar_id":"","url":"https://api.github.com/users/angular","html_url":"https://github.com/angular","followers_url":"https://api.github.com/users/angular/followers","following_url":"https://api.github.com/users/angular/following{/other_user}","gists_url":"https://api.github.com/users/angular/gists{/gist_id}","starred_url":"https://api.github.com/users/angular/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/angular/subscriptions","organizations_url":"https://api.github.com/users/angular/orgs","repos_url":"https://api.github.com/users/angular/repos","events_url":"https://api.github.com/users/angular/events{/privacy}","received_events_url":"https://api.github.com/users/angular/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/angular/angular","description":"","fork":false,"url":"https://api.github.com/repos/angular/angular","forks_url":"https://api.github.com/repos/angular/angular/forks","keys_url":"https://api.github.com/repos/angular/angular/keys{/key_id}","collaborators_url":"https://api.github.com/repos/angular/angular/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/angular/angular/teams","hooks_url":"https://api.github.com/repos/angular/angular/hooks","issue_events_url":"https://api.github.com/repos/angular/angular/issues/events{/number}","events_url":"https://api.github.com/repos/angular/angular/events","assignees_url":"https://api.github.com/repos/angular/angular/assignees{/user}","branches_url":"https://api.github.com/repos/angular/angular/branches{/branch}","tags_url":"https://api.github.com/repos/angular/angular/tags","blobs_url":"https://api.github.com/repos/angular/angular/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/angular/angular/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/angular/angular/git/refs{/sha}","trees_url":"https://api.github.com/repos/angular/angular/git/trees{/sha}","statuses_url":"https://api.github.com/repos/angular/angular/statuses/{sha}","languages_url":"https://api.github.com/repos/angular/angular/languages","stargazers_url":"https://api.github.com/repos/angular/angular/stargazers","contributors_url":"https://api.github.com/repos/angular/angular/contributors","subscribers_url":"https://api.github.com/repos/angular/angular/subscribers","subscription_url":"https://api.github.com/repos/angular/angular/subscription","commits_url":"https://api.github.com/repos/angular/angular/commits{/sha}","git_commits_url":"https://api.github.com/repos/angular/angular/git/commits{/sha}","comments_url":"https://api.github.com/repos/angular/angular/comments{/number}","issue_comment_url":"https://api.github.com/repos/angular/angular/issues/comments{/number}","contents_url":"https://api.github.com/repos/angular/angular/contents/{+path}","compare_url":"https://api.github.com/repos/angular/angular/compare/{base}...{head}","merges_url":"https://api.github.com/repos/angular/angular/merges","archive_url":"https://api.github.com/repos/angular/angular/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/angular/angular/downloads","issues_url":"https://api.github.com/repos/angular/angular/issues{/number}","pulls_url":"https://api.github.com/repos/angular/angular/pulls{/number}","milestones_url":"https://api.github.com/repos/angular/angular/milestones{/number}","notifications_url":"https://api.github.com/repos/angular/angular/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/angular/angular/labels{/name}","releases_url":"https://api.github.com/repos/angular/angular/releases{/id}","deployments_url":"https://api.github.com/repos/angular/angular/deployments","created_at":"2014-09-18T16:12:01Z","updated_at":"2016-04-01T00:24:09Z","pushed_at":"2016-04-01T00:30:56Z","git_url":"git://github.com/angular/angular.git","ssh_url":"git@github.com:angular/angular.git","clone_url":"https://github.com/angular/angular.git","svn_url":"https://github.com/angular/angular","homepage":"https://angular.io","size":259565,"stargazers_count":10347,"watchers_count":10347,"language":"TypeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2711,"mirror_url":null,"open_issues_count":1415,"forks":2711,"open_issues":1415,"watchers":10347,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/angular/angular/pulls/7842"},"html":{"href":"https://github.com/angular/angular/pull/7842"},"issue":{"href":"https://api.github.com/repos/angular/angular/issues/7842"},"comments":{"href":"https://api.github.com/repos/angular/angular/issues/7842/comments"},"review_comments":{"href":"https://api.github.com/repos/angular/angular/pulls/7842/comments"},"review_comment":{"href":"https://api.github.com/repos/angular/angular/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/angular/angular/pulls/7842/commits"},"statuses":{"href":"https://api.github.com/repos/angular/angular/statuses/6a4c316db711312a0d34d09791db71dd1d17fa35"}}}}