{"action":"created","issue":{"url":"https://api.github.com/repos/angular/angular.js/issues/13962","repository_url":"https://api.github.com/repos/angular/angular.js","labels_url":"https://api.github.com/repos/angular/angular.js/issues/13962/labels{/name}","comments_url":"https://api.github.com/repos/angular/angular.js/issues/13962/comments","events_url":"https://api.github.com/repos/angular/angular.js/issues/13962/events","html_url":"https://github.com/angular/angular.js/pull/13962","id":131854831,"number":13962,"title":"f[eat|ix](select): support values added by ngValue","user":{"login":"Narretz","id":1153097,"avatar_url":"https://avatars.githubusercontent.com/u/1153097?v=3","gravatar_id":"","url":"https://api.github.com/users/Narretz","html_url":"https://github.com/Narretz","followers_url":"https://api.github.com/users/Narretz/followers","following_url":"https://api.github.com/users/Narretz/following{/other_user}","gists_url":"https://api.github.com/users/Narretz/gists{/gist_id}","starred_url":"https://api.github.com/users/Narretz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Narretz/subscriptions","organizations_url":"https://api.github.com/users/Narretz/orgs","repos_url":"https://api.github.com/users/Narretz/repos","events_url":"https://api.github.com/users/Narretz/events{/privacy}","received_events_url":"https://api.github.com/users/Narretz/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/angular/angular.js/labels/cla:%20yes","name":"cla: yes","color":"bfe5bf"},{"url":"https://api.github.com/repos/angular/angular.js/labels/component:%20forms","name":"component: forms","color":"7B947B"},{"url":"https://api.github.com/repos/angular/angular.js/labels/frequency:%20moderate","name":"frequency: moderate","color":"fef2c0"},{"url":"https://api.github.com/repos/angular/angular.js/labels/severity:%20broken%20expected%20use","name":"severity: broken expected use","color":"fbda00"},{"url":"https://api.github.com/repos/angular/angular.js/labels/type:%20feature","name":"type: feature","color":"00a606"}],"state":"open","locked":false,"assignee":{"login":"petebacondarwin","id":15655,"avatar_url":"https://avatars.githubusercontent.com/u/15655?v=3","gravatar_id":"","url":"https://api.github.com/users/petebacondarwin","html_url":"https://github.com/petebacondarwin","followers_url":"https://api.github.com/users/petebacondarwin/followers","following_url":"https://api.github.com/users/petebacondarwin/following{/other_user}","gists_url":"https://api.github.com/users/petebacondarwin/gists{/gist_id}","starred_url":"https://api.github.com/users/petebacondarwin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petebacondarwin/subscriptions","organizations_url":"https://api.github.com/users/petebacondarwin/orgs","repos_url":"https://api.github.com/users/petebacondarwin/repos","events_url":"https://api.github.com/users/petebacondarwin/events{/privacy}","received_events_url":"https://api.github.com/users/petebacondarwin/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/angular/angular.js/milestones/90","html_url":"https://github.com/angular/angular.js/milestones/1.5.x","labels_url":"https://api.github.com/repos/angular/angular.js/milestones/90/labels","id":1025270,"number":90,"title":"1.5.x","description":"","creator":{"login":"petebacondarwin","id":15655,"avatar_url":"https://avatars.githubusercontent.com/u/15655?v=3","gravatar_id":"","url":"https://api.github.com/users/petebacondarwin","html_url":"https://github.com/petebacondarwin","followers_url":"https://api.github.com/users/petebacondarwin/followers","following_url":"https://api.github.com/users/petebacondarwin/following{/other_user}","gists_url":"https://api.github.com/users/petebacondarwin/gists{/gist_id}","starred_url":"https://api.github.com/users/petebacondarwin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petebacondarwin/subscriptions","organizations_url":"https://api.github.com/users/petebacondarwin/orgs","repos_url":"https://api.github.com/users/petebacondarwin/repos","events_url":"https://api.github.com/users/petebacondarwin/events{/privacy}","received_events_url":"https://api.github.com/users/petebacondarwin/received_events","type":"User","site_admin":false},"open_issues":94,"closed_issues":127,"state":"open","created_at":"2015-03-17T12:15:49Z","updated_at":"2016-05-18T12:49:37Z","due_on":null,"closed_at":null},"comments":1,"created_at":"2016-02-06T13:12:23Z","updated_at":"2016-05-18T17:57:30Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/angular/angular.js/pulls/13962","html_url":"https://github.com/angular/angular.js/pull/13962","diff_url":"https://github.com/angular/angular.js/pull/13962.diff","patch_url":"https://github.com/angular/angular.js/pull/13962.patch"},"body":"select elements with ngModel will now set ngModel to option values added by ngValue.\r\nThis allows setting values of any type without the use of ngOptions.\r\n\r\nInterpolations inside attributes can only be strings, but the ngValue directive uses attrs.$set,\r\nwhich does not follow any type restriction. Any $observe on the value attribute will therefore receive\r\nthe original value (result of ngValue expression). However, when a user selects an option, the browser\r\nsets the select value to the actual option's value attribute, which is still always a string.\r\nFor that reason, when option are added by ngValue, we set the hashed value of the original value in\r\nthe value attribute and store the actual value in an extra map. When the select value changes, we\r\nread access the actual value via the hashed select value.\r\n\r\nCloses #9842\r\nCloses #6297\r\n\r\n- [ ] Test that it takes precedence over interpolated option / option text\r\n- [x] Test for multiple selections\r\n- [x] Fix failing Chrome tests\r\n- [ ] Docs\r\n\r\nTalking points:\r\n- The implementation works reasonably well, although it's a bit ~~hacky~~special\r\n- With ngValue, option values are hash values, not the real values (which makes sense, but might be confusing)\r\n- ~~afaik angular 2 suffers from the same problem as ng1 right now~~"},"comment":{"url":"https://api.github.com/repos/angular/angular.js/issues/comments/220107922","html_url":"https://github.com/angular/angular.js/pull/13962#issuecomment-220107922","issue_url":"https://api.github.com/repos/angular/angular.js/issues/13962","id":220107922,"user":{"login":"petebacondarwin","id":15655,"avatar_url":"https://avatars.githubusercontent.com/u/15655?v=3","gravatar_id":"","url":"https://api.github.com/users/petebacondarwin","html_url":"https://github.com/petebacondarwin","followers_url":"https://api.github.com/users/petebacondarwin/followers","following_url":"https://api.github.com/users/petebacondarwin/following{/other_user}","gists_url":"https://api.github.com/users/petebacondarwin/gists{/gist_id}","starred_url":"https://api.github.com/users/petebacondarwin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petebacondarwin/subscriptions","organizations_url":"https://api.github.com/users/petebacondarwin/orgs","repos_url":"https://api.github.com/users/petebacondarwin/repos","events_url":"https://api.github.com/users/petebacondarwin/events{/privacy}","received_events_url":"https://api.github.com/users/petebacondarwin/received_events","type":"User","site_admin":false},"created_at":"2016-05-18T17:57:30Z","updated_at":"2016-05-18T17:57:30Z","body":"This test fails:\r\n\r\n```js\r\n      it('should work update the value as a result of changes to the options', function() {\r\n        var A = { name: 'A'}, B = { name: 'B'}, C = { name: 'C'};\r\n        scope.options = [A, B, C];\r\n        scope.obj = {};\r\n        compile(\r\n          '<select ng-model=\"obj.value\">' +\r\n            '<option ng-repeat=\"option in options\" ng-value=\"option\">{{$index}}</option>' +\r\n          '</select>'\r\n        );\r\n\r\n        var optionElements = element.find('option');\r\n        expect(optionElements.length).toEqual(4);\r\n        browserTrigger(optionElements.eq(0));\r\n\r\n        optionElements = element.find('option');\r\n        expect(optionElements.length).toEqual(3);\r\n        expect(scope.obj.value).toBe(A);\r\n\r\n        scope.options.shift();\r\n        scope.$digest();\r\n\r\n        optionElements = element.find('option');\r\n        expect(optionElements.length).toEqual(3);\r\n        expect(scope.obj.value).toBe(null);\r\n      });\r\n```"}}