zestia / ember-select-box

:capital_abcd: A faux select box for Ember apps
MIT License
64 stars 14 forks source link

Passing label as a property to sb.option component #9

Closed markcellus closed 7 years ago

markcellus commented 8 years ago

Hey, awesome, awesome package!

I just have one quick question. I see that by default, in order to show a label, the code looks to accept an object as a value, and uses a label-key off of that to display the label in the dropdown. Was there any reason why it doesn't just allow passing a label property into the sb.option component? ie:

{{sb.option value="A" label="Apple"}}
amk221 commented 8 years ago

Thanks! That's what you do? I'm confused 🙂

amk221 commented 8 years ago

Ah I see, it seems you're looking at the addon's dummy app, whose select boxes are just demos of what you can acheive.

markcellus commented 8 years ago

Sorry, I want to display the label in the {{#selected-options}} block upon initial load of the select-box component (i'm passing the same value that matches a value passed in one of the {{sb.options}} blocks), but the callback selected only passes the value property as the first param, not the label. I'm looking at the call made in the code here

amk221 commented 8 years ago

Could you perhaps put the hbs/js of your select-box in pastebin so I can have a look?

The select box only stores the selected value, so at any one time it is not aware what the label being displayed is - it could be anything in-between the selected <option></option> tags. Hence it is up to the developer to make their own way of rendering a selected-option. This example: (component.js, usage) shows just one way, but there are many... it depends on what how you want to interact with the select box and what sort of data you will be selecting from it.

markcellus commented 8 years ago

Yeah I can do a jsfiddle example demonstration for you...

Just off-hand though, I can provide a little more clarity.

The select box only stores the selected value, so at any one time it is not aware what the label being displayed is

Yeah, definitely. So my question now is, if the select-box component doesn't care about the label or even consider it, why is it passed into the select.option component, shown in the initial examples on the README? It makes me think that the select-box uses the label in some way.

amk221 commented 8 years ago

This:

{{#api.option value=1}}One{{/api.option}}

will render...

<option value=1>One</option>

Whereas,

{{api.option value=1 label='One' }}

is just an alternative syntax. The select box on the other hand, still knows nothing about this.

(Perhaps the sb. prefix made you think you were telling the select what the label was? when in fact, you are working with the select box's 'api' for rendering an option)

Don't worry about a fiddle/twiddle, I don't think you can include Ember addons into them yet. I'd be curious to see your code at least, maybe I could help some more...

markcellus commented 8 years ago

Yeah I understand that those three options are the same. I guess I'm wondering, why even allow the label in the second one:

{{api.option label='One' value=1}}

You're just yielding the contents of the sb.option block (as demonstrated by your first example above), so it may be less confusing to avoid passing in a label attr that the component never uses. Due to my confusion, I was spending time on trying to figure out why the label attr I was passing into my select-option wasn't being passed back into the on-select callback so that I could deal with it.

Am I making any kind of sense? lol

amk221 commented 8 years ago

Ah, understood... so in me adding the ability to use a label attr, it set up your expectations of extra functionality that doesn't exist. Which is fair!

For the faux-select boxes, a label can be more than just a string.

e.g. Imagine this:

{{sb.option value='Foo' label='Label goes here'}}

Outputting...

<div class="my-select-box-option">
  <span>Label goes here</span>
  <span>&raquo;</span>
</div>

Then imagine the same, but without the ability to pass in a label attribute:

{{#sb.option value='Foo'}}
  <span>Label goes here</span>
  <span>&raquo;</span>
{{/sb.option}}

...how is the select box author supposed to know what your label is: $label = this.$('?');

Perhaps it would be sensible to remove this capability from the native select box?

markcellus commented 8 years ago

how is the select box author supposed to know what your label is

the author is the one passing in the label, so they should know what the label is.

let fruits = Ember.A([
{ value: 'A', label: 'Apple'},
{ value: 'P', label: 'Pear'} 
])
{{#select-box on-select=(action 'onSelect') as |sb|}}}
    {{#each fruits as |fruit|}}
        {{#sb.option value=fruit}}{{fruit.label}}{{/sb.option}}
    {{/each}}
{{/select-box}}

Then their onSelect action handler will get passed the entire selected fruit object which now has a label property on it. So they can display it correctly in their selected-option block.

amk221 commented 8 years ago

If you want the label attribute removing make a PR! I personally like the syntax

markcellus commented 8 years ago

But I feel that if you're already accepting a label property (decoupled from the value object), you should pass that back in the on-select callback, or at the very least pass all the attrs that I'm passing into the select-option component.

let fruits = Ember.A([
{ value: 'A', label: 'Apple'},
{ value: 'P', label: 'Pear'} 
])
{{#select-box on-select=(action 'onSelect') as |sb|}}}
    {{#each fruits as |fruit|}}
        {{sb.option value=fruit.value label=fruit.label}}
    {{/each}}
{{/select-box}}

Then my onSelect action should be called with both the value and the label (or at least the entire attrs object, I'm passing into the select-option component). I guess what I'm getting at is, the callback should give me all of the data I'm passing back into it. If not, I'll have to map everything myself in the callback. What do you think?

markcellus commented 8 years ago

If you want the label attribute removing make a PR!

lol okay I was actually going to, but just wanted to get your take on this first.

amk221 commented 7 years ago

Hey, I hope you don't mind, but I'm going to close this - my primary reason being that the select box is for selecting values, not labels.

markcellus commented 7 years ago

No problem. I've been quite busy, so haven't had a chance to submit a PR for the change to clarify the syntax. But will do once I get some down time. Thanks for your time.

amk221 commented 6 years ago

In v5 (coming soon) I have phased out the label attribute to align better with a native select box.

You should be able to do this:

this.set('models', [{
  id: 1,
  name: 'Foo'
}, {
  id: 2,
  name: 'Bar'
}, {
  id: 3,
  name: 'Baz'
}]);
actions: {
  selected(value) {
    this.set('selectedValue', value);
  }
}
{{#select-box value=model on-select=(action "selected") as |sb|}}
  {{#sb.selected-option}}
    {{selectedValue.name}}
  {{/sb.selected-option}}
  {{#each models as |model|}}
    {{#sb.option value=model as |o|}}
      {{o.value.name}}
      {{! same as model.name, but will resolve the value if a promise }}
    {{/sb.option}}
  {{/each}}
{{/select-box}}
markcellus commented 6 years ago

haha that is awesome! And it makes this API much more understandable. Was it a typo? or did you mean...

{{#each models as |model}}
    {{#sb.option value=model as |o|}}
      {{o.name}}
    {{/sb.option}}
  {{/each}}

?

amk221 commented 6 years ago

^updated

markcellus commented 6 years ago

Oh.... you expect for the consumer to asynchronously get each value's name? On render? I've seen dropdowns asynchronously fetch a set of options from a server but never a dropdown that would have asynchronous behavior at the option level.

Edit: typo

amk221 commented 6 years ago

No work for the consumer, the select box should just handle everything.

Perhaps this makes it clearer:

{{#select-box value=promise}}
  {{#each promises as |promise|}}
    {{#sb.option value=promise as |o|}}
      {{promise}} {{! Would render [object Object], obviously not very useful }}
      {{o.value}} {{! Would render the resolved value }}
    {{/sb.option}}
  {{/each}}
{{/select-box}}

When an option is selected, instead of receiving <Promise>, you will get the result of the resolved promise, which I assume would be the expected behaviour?