Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

ng-model not binding <select> list values in 1.4.rc2 #11890

Closed
RickStrahl opened this issue May 17, 2015 · 18 comments
Closed

ng-model not binding <select> list values in 1.4.rc2 #11890

RickStrahl opened this issue May 17, 2015 · 18 comments

Comments

@RickStrahl
Copy link

I have a list of static values that are bound to a list and I'm trying to get the list to display the value from the model.

The model value is an integer:

wm.activeResource.ValueType = 0;

Then in the html I'm binding this value to a dropdown list of static values:

{{view.activeResource.ValueType}}  <-- correctly displays 0 -->

<!-- list displays empty element --->
<select ng-model="view.activeResource.ValueType">
    <option value="0">Text</option>
    <option value="2">Markdown</option>
    <option value="1">Binary</option>
</select>

This worked fine in v1.3 but in 1.4 the list comes back with no selection. Or, more specifically it has a selection of an injected element:

<option value="? number:0 ?"></option>
@Narretz
Copy link
Contributor

Narretz commented May 18, 2015

Is this a correct reproduction? http://plnkr.co/edit/k09Xh9xEgcXQBbKTkRdh So the select does not reflect the model?

@petebacondarwin
Copy link
Contributor

The reason for this is that in 1.4 we test for exact equality in the select directive.
If you have static options then the values of these options are strings.
See http://plnkr.co/edit/KCM6Kz22sB5GVcPvOZgT?p=preview

You can provide a simple directive to convert the value from number to string and back between the model and view: http://plnkr.co/edit/BnNkVENvNYyArbRjVaov?p=preview

@petebacondarwin
Copy link
Contributor

We should probably highlight this in the docs for select if it is not already.

@RickStrahl
Copy link
Author

While I think that this makes sense conceptually and probably for performance as well, I think this has a terrible usability aspect. I would imagine that this is a fairly common scenario that needs to be addressed and there's no intuitive discovery of this behavior until it fails. If you're new and starting out you're not going to make the connection that you have a type conversion problem.

Even the solution of requiring a custom directive to make this work seems heavy handed. Shouldn't there be something built in to provide these types of conversions for you more easily without having to create a component?

I don't want to derail this issue - the solution given is straight forward enough for me to fix and I can live with that. Thanks for pointing to the source of the issue and the solution!

But I think in the grander scheme of things this should be thought over going forward (not sure how this will be handled in 2.0).

@Narretz
Copy link
Contributor

Narretz commented May 18, 2015

We previously compared the model and attribute value with == which did type conversion. However, did caused false to be equal to 0 for example. Also bad. The root problem is simply that HTML does only allow strings inside value attributes, so your integers become strings in the DOM. You can use ngOptions to remedy this problem.

@petebacondarwin
Copy link
Contributor

A more pernicious issue with using == and implicit conversion is that on the way "out" of such a select your model would change from being a number to a string.

@petebacondarwin
Copy link
Contributor

I updated the select docs to highlight this issue and to provide a running example of using a custom conversion directive.

@RickStrahl
Copy link
Author

Thanks all. The docs and sample are definitely a good addition.

@annechinn
Copy link

I have a scenario that I am still unable to get to work, even with the directive: I have a set of enumerated values that I want to use for the options. It is unable to bind to get the initial value correctly, but if I put in the value directly for each enumerated value it works correctly.

<select ng-model="vm.frameworkContext.frameworkViewType" convert-to-number>
  <option value="{{vm.enums.FrameworkViewType.STATE_FRAMEWORK_ONLY}}">
    State Framework Only
  </option>
  <option value="{{vm.enums.FrameworkViewType.INSTRUCTION_FRAMEWORK_ONLY}}">
    Instructional Framework Only
  </option>
  <option value="{{vm.enums.FrameworkViewType.STATE_FRAMEWORK_DEFAULT}}">
    State Framework Default
  </option>
  <option value="{{vm.enums.FrameworkViewType.INSTRUCTIONAL_FRAMEWORK_DEFAULT}}">
    Instructional Framework Default
  </option>
</select>

where

vm.enums.FrameworkViewType: {
  UNDEFINED: 0,
  STATE_FRAMEWORK_ONLY: 1,
  STATE_FRAMEWORK_DEFAULT: 2,
  INSTRUCTIONAL_FRAMEWORK_DEFAULT: 3,
  INSTRUCTION_FRAMEWORK_ONLY: 4
}

@gkalpak
Copy link
Member

gkalpak commented Oct 28, 2015

@annechinn, it seems to be working as expected.
If you experience any issues, please open a new issue, providing all necessary info to reproduce the problem (preferrably a live demo of the bug, using CodePen, Plnkr, etc).

@petebacondarwin
Copy link
Contributor

@annechinn I think your problem might be that option values are strings, while your enum values are integers. This is precisely the problem discussed here and now described in the select.

@annechinn
Copy link

I created the plunker and found that it is reproducible in 1.3, but fixed
in 1.4, so I will not create a new issue. In case you're interested, i've
provided a link to the plunker to demontrate that it was broken in 1,3,
even with the convert-to-number directive.

http://plnkr.co/edit/A5onypmeEm8xUzSDdpG1?p=preview

On Wed, Oct 28, 2015 at 2:38 AM, Pete Bacon Darwin <notifications@github.com

wrote:

@annechinn https://github.com/annechinn I think you problem might be
that option values are strings, while your enum values are integers. This
is precisely the problem discussed here and now described in the select.


Reply to this email directly or view it on GitHub
#11890 (comment)
.

@gkalpak
Copy link
Member

gkalpak commented Oct 29, 2015

@annechinn, the issue demonstrated in your plnkr is not the same (hence the convertToNumber directive does not solve it). It is a timing problem (due to interpolations in value attributes) and can be reproduced even with string model-values.
It can be worked around by initializing your model values in a timeout.

I don't think such kind of bugs are getting fixed on v1.3.x (since it's an old version).

@campbeln
Copy link

I understand why === is much more better-er than ==, but this causes all sorts of issues when trying to bind to an object (as I am currently fighting with). We have an object barfing out as { boundValue: 69 } yet with the changes as described above, I'm going to need to do something equivalent to this: { boundValue: 69, boundValueStr: "69" }... really!?

How about due to the new use of === and the fact that the right-hand side of this equation is always a string thanks to the HTML DOM, how about we force the left-hand side to be a string as well? Or at least give us the option to do so without some hack-y secondary directive (which I've still not gotten to work right in our case, by the way).

@Narretz
Copy link
Contributor

Narretz commented Jan 29, 2016

@campbeln The value attribute in selects can only be a string, so when you have numbers you should use the ngOptions directive. Why the directive workaround doesn't work in your case is hard to say, but that's a question better asked on Stackoverflow etc. Lastly, if you have an idea how to improve the directive, opening a new issue is probably the better idea.

@campbeln
Copy link

campbeln commented Feb 5, 2016

@Narretz ng-options doesn't bind it either in our tests!? Besides it seems boneheaded to require all SELECT values to be strings when the right is always a string. Then we devs will be required to coerce all API values to strings if we need to use a SELECT?!

@Narretz
Copy link
Contributor

Narretz commented Feb 5, 2016

If ng Options doesn't bind satisfactorily please provide a minimal demo in a plnkr.co or similar and I'll have a look.

@campbeln
Copy link

campbeln commented Feb 6, 2016

Raised new issue here - #13955

You can't use ng-options if you're doing something stupid like returning a new array of objects from a function call (e.g. ng-options='item in myFunct()'). Then you try and use track by but that cannot be used with selects (as in the horrible ng-options version, not HTML DOM objects). What _may_ get us around it is to cache the results from the first call so that all references are the same and we won't need track by, but I'm not sure that will work in all cases in our system.

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

6 participants