Giter Club home page Giter Club logo

emberx-select's Introduction

emberx-select

npm version Ember Observer Score CircleCI

A select component based on the native html select.

We've tried other select components, and were missing the reliability, maintainability, and accessbility of the native html <select>. <XSelect> is a drop-in component to let you use any object for your selectable options. You can use it out of the box, or as a building block of something more ambitious.

The goal of <XSelect> is to let you see how it works and style it right in your template, rather than passing in a ball of configuration or wrapping a hard-coded, inaccessible jQuery plugin.

Recommended

This addon contains older Ember patterns and depdendencies. While it is still ok to continue using, it is recommended to use the more modern Ember Select Light addon which has a near drop in API and better support for Octane, Embroider, and Accessibility concerns.

Installation

ember install emberx-select

Usage

By allowing arbitrary html to appear in the template of the select element, you can use it just like you would normally. This means things like having <optgroup> tags inside your select, or even plain old <option> elements to represent things like empty values.

<XSelect> thinly wraps a native <select> element so that it can be object and binding aware. It is used in conjuction with the x-option component to construct select boxes. E.g.

Ember >= 3.4:

<XSelect @value={{bob}} @onChange={{action "selectPerson"}} as |xs|>
  <xs.option @value={{fred}}>Fred Flintstone</xs.option>
  <xs.option @value={{bob}}>Bob Newhart</xs.option>
</XSelect>

Ember < 3.4:

{{#x-select value=bob on-change=(action "selectPerson") as |xs|}}
  {{#xs.option value=fred}}Fred Flintstone{{/xs.option}}
  {{#xs.option value=bob}}Bob Newhart{{/xs.option}}
{{/x-select}}

The options are always up to date, so that when the object bound to value changes, the corresponding option becomes selected.

Whenever the select tag receives a change event, it will fire onChange action. This is the default action that is fired but not the only event that's available.

Contextual Components

As of version 3.0.0, emberx-select will only support contextual components. This means you will have to use Ember 2.3 or higher. Using contextual components allows emberx-select to skip some potentially expensive DOM traversals. Now the options can register through data rather than through the DOM.

<XSelect @value={{model.status}} as |xs|>
  <xs.option @value=1>Active</xs.option>
  <xs.option @value=2>Inactive</xs.option>
</XSelect>

Multiselect

<XSelect> supports the multiple option. This means you can pass an array as its value, and it will set its selections directly on that array.

<XSelect @value=selections @multiple=true @onChange={{action "selectionsChanged"}} as |xs|>
 <xs.option @value={{fred}}>Fred Flintstone</xs.option>
 <xs.option @value={{bob}}>Bob Newhart</xs.option>
 <xs.option @value={{andrew}}>Andrew WK</xs.option>
</XSelect>

The selections array will be initialized to an empty array if not present.

Actions and Action Arguments

All of <XSelect>s actions are closure actions. This means you must use the action helper (i.e. @onClick={{action "onClick"}}). The function that is dispatched by <XSelect> whenever the event fires has a function signature of:

/**
* @param {Object} value - the value selected by the user.
* @param {Object} event - the DOM event of the action
*/
function (value, event) {
  // action body...
}

Most of the time all you need is the value that has been selected, but sometimes your action requires more context than just that. In those cases, you can pass any arguments you need from the template. For example:

<XSelect @onClick={{action "didMakeSelection" isXSelectRequired}} @required={{isXSelectRequired}} as |xs|>
  <option>Nothing</option>
  <xs.option @value={{something}}>Something</xs.option>
</XSelect>

then, inside your action handler:

import Controller from '@ember/controller';

export default Controller.extend({
  actions: {
    didMakeSelection(value, event, isXSelectRequired) {
      if (!value & isXSelectRequired) {
        this.set('error', 'You must fill out this field');
      } else {
        this.set('selection', value);
      }
    }
  }
});

<XSelect> provides other actions that fire on different event types. These actions follow the HTML input event naming convention.

onBlur

onBlur fires anytime the blur event is triggered on the <XSelect> component. When the action fires it sends two arguments: the value, the DOM event.

onFocusOut

onFocusOut fires anytime the focusOut event is triggered on the <XSelect> component. When the action fires it sends two arguments: the value, the DOM event.

onClick

onClick fires when <XSelect> is clicked. When the action fires it sends two arguments: the value, the DOM event.

onDisable (x-option)

onDisable fires when x-option detects a change to its disabled attribute. When the action fires it sends two arguments: the value and if it is disabled (boolean).

Test Helper

<XSelect> 4.0 ships with an entirely new test helper that goes beyond just allowing you to select an option. It allows you to interact with your <select> element in all different ways. For example, if you need to assert your first option is disabled or not:

expect(xselect.options(0).isDisabled).to.equal(true);

Under the hood this new test helper is using a BigTest Interactor. Interactors allow you to think about how you're going to interact with the DOM and abstract that into composable & immutable containers. Interactors are similar to page objects, but for components.

Using the test helper

Import the select interactor:

// you can name the import whatever you want
import XSelectInteractor from 'emberx-select/test-support/interactor';

At the top of your test file you need to initialize the interactor. This should go at the top most part of your test so it's available to all tests in the file. Here's an example in Qunit:

module("Acceptance | Your Test", function(hooks) {
  let xselect = new XSelectInteractor('.selector-for-select');
  setupApplicationTest(hooks);
  // ...
});

Once you have initialized the interactor, you're ready to start selecting!

module("Acceptance | Your Test", function(hooks) {
  let xselect = new XSelectInteractor('.selector-for-select');
  // ...

  test('Selecting an option', async (assert) => {
    await xselect
      .select('Fred Flintstone')
      .when(() => assert.equal(xselect.options(0).isSelected, true));

    // for a multiselect pass an array
    // await xselect
    //   .select(['Fred Flintstone', 'Bob Newhart'])
    //   .when(() => assert.equal(xselect.options(0).isSelected, true));;
  });
});

You can do more than just select options with this helper.

module('Acceptance | Your Test', function(hooks) {
  let xselect = new XSelectInteractor('.selector-for-select');
  // ...

  test('Selecting an option', async (assert) => {
    await xselect.select('Fred Flintstone')
      // assert the change is has happened. It's important to make the
      // assertion inside of `when`, so tests are not flakey.
      .when(() => assert.equal(xselect.options(0).isSelected, true));
  });
});

In this example we're using @bigtest/convergence#when to assert. The TL;DR of convergence is it basically converges on the state of the DOM. It checks every 10ms until the assertion is truthy. Once it's truthy the test passes. You can read more about convergences here

You don't need to include @bigtest/convergence in your project, it's already a dependency of @bigtest/interactor and interactor provides all of the convergence methods to you (like when and do).

This is the full interactor which has all of the attributes or interactions for an HTMLSelectElement.

const xSelectInteractor = interactor({
  hasFocus: is(':focus'),
  name: attribute('name'),
  form: attribute('form'),
  title: attribute('title'),
  size: attribute('size'),
  tabindex: attribute('tabindex'),
  isDisabled: property('disabled'),
  isRequired: property('required'),
  isAutofocus: property('autofocus'),

  options: collection('option', {
    name: attribute('name'),
    value: property('value'),
    title: attribute('title'),
    isSelected: property('selected'),
    isDisabled: property('disabled'),
    hasSelectedClass: hasClass('is-selected')
  })
});

Example usage might be:

<select name="World" class="x-select">
  <option value="hello world">Hello world!</option>
</select>
let xselect = new XSelectInteractor('.x-select');

xselect.options(0).value; //=> "hello world"
xselect.options(0).text; //=> "Hello World!"
xselect.name; //=> "World"
xselect.form; //=> null
xselect.hasFocus; //=> false
xselect.tabIndex; //=> 0

If you want to see this test helper used in many different ways look no further than this addons test suite!

Extending the XSelect interactor

If you want to add custom interactions to your <XSelect> interactor, you can do so by importing it into the custom interactor you want to create, and extend it:

import XSelectInteractor from 'emberx-select/test-support/interactor';
import { clickable } from '@bigtest/interactor';

@XSelectInteractor.extend
class NewInteractor {
  submitForm = clickable('[data-test-form-submit]');

  fillAndSubmit(value) {
    return this.select(value).submitForm();
  }
}

EmberX

emberx-select is part of the "missing components of ember" collectively known as emberx:

Other Resources

Running Tests

  • ember test
  • ember test --server

Release Process

Every commit to master results in a build and push to the demo application at http://emberx-select.netlify.com

Npm releases use semver and happen at the project owner's discretion.

Code of Conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms, which can be found in the CODE_OF_CONDUCT.md file in this repository.

emberx-select's People

Contributors

abulrim avatar andyhot avatar arunasf avatar backspace avatar cafreeman avatar cowboyd avatar dhaulagiri avatar enspandi avatar fivetanley avatar flexyford avatar gzurbach avatar jackca avatar jeffreybiles avatar jeremywrowe avatar joshuaconner avatar kategengler avatar locks avatar lydiaguarino avatar miguelcobain avatar mitchlloyd avatar odoe avatar robdel12 avatar rtablada avatar rwjblue avatar seanpdoyle avatar stefanpenner avatar steveklabnik avatar stopfstedt avatar tehviking avatar tp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emberx-select's Issues

Any way to attach to blur event?

Is there any way to attach an event handler to the blur event of an x-select? We are trying to use emberx-select as an "inline" editor that "commits" only on blur, but I can't figure how to attach to arbitrary DOM events as I can with, for instance, with a TextView. I considered options for extending or "reopening" the x-select component, but I've not found a good way to get a handle on the component to try to make that work.

Suggestions would be greatly appreciated.
Thanks!

Obligatory "doesn't work on Canary issue"

I tried upgrading an app to the latest Ember build today and I noticed that the x-select components weren't rendering anything. I ran the tests in this repo against Canary and it looks like they all fail each module has failing assertions (except for JSHint! ๐ŸŽ‰).

I'm sure there's nothing wrong on your end. You guys are great. But those Ember core people... ๐Ÿ˜‰ Maybe there is an issue that could be filed before 1.13 is out the door or maybe there is an open issue that might be affecting x-select?

Binding options

Is it possible to bind the options? I tried {{x-select value=condition.subject options=selectOptions action="selectSubject"}} where selectOptions is an array of objects with no success. I didn't see in the tests or code where it was or wasn't possible so figured I'd ask.

Thanks!

Deprecation warning with emberjs 1.13

DEPRECATION: Accessing 'template' in <app@component:x-select::ember516> is deprecated.
To determine if a block was specified to <app@component:x-select::ember516> please use '{{#if hasBlock}}' in the components layout.

Unexpected behavior when initially selected value is falsy

Version of x-select: 2.1.1

Ember Version / Ember CLI Version:

Ember Version: 2.4.3
Ember CLI Version: 2.4.2

Expected Behavior

When setting value on {{x-select}} to a falsy value (explicitly false in our case), the bound property should remain false.

Actual Behavior

If set to false, the bound property's value is updated to null. We tracked this down to this line:
https://github.com/thefrontside/emberx-select/blob/master/addon/components/x-select.js#L156

Steps To Reproduce:

  1. When using {{x-select}} pass in value bound to a property that is falsy (false, 0, etc)
  2. Observe that the bound value is updated to null.

JSBin / Ember Twiddle / Example repo / Failing test:

Tracked down to this line: https://github.com/thefrontside/emberx-select/blob/master/addon/components/x-select.js#L156

Attempts to set property after model is deleted/rolled back

On master, if a model's attribute is bound to the value of the select, you set a default value with selected=true, and you destroy/rollback a new model, it will trigger a

Uncaught Error: Attempted to handle event didSetProperty` error. 
It's attempting to modify the attribute after the model is set to `deleted.saved`.

This does not occur in 2.0.2.

Test case project: https://github.com/kmiyashiro/xselect-example

  1. Go to /wombat route
  2. Click on "back" link
  3. Error in console

how we can write integration test for x-select?

  • - I am aware of 'select' instead of fillIn in acceptance testing, would like to write integration test for my project.
  • - I tried the helpers as per the doc says and that is not working.
  • - currently I am using 'this.$('').prop('selectedIndex', 1).trigger('change');' - do we have any other way around for this?

Add support for missing attributes

Currently the x-select component supports a limited amount of the available attributes on a normal HTML select. The attributes that are currently not present on the component are as follows:

  • autofocus
  • form
  • required
  • size

For a complete overview of the available attributes and their functionality see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select#attributes

Some of these attributes will probably not be applicable to most Ember applications (mostly form and name), but they should probably be added as well to support some edge cases. Other attributes like required and autofocus are obviously pretty useful.

I can whip up a pull request to add these attributes, but I wanted to do a quick check if anyone has issues with adding these attributes.

Issues with promise values?

I'm trying to use this addon with a select value that is a promise. It seems that the === check here: https://github.com/thefrontside/emberx-select/blob/master/addon/components/x-option.js#L45 will not return true if the select.value is actually a promise object, even though the values are "equal". I've solved this locally by sending over the value.content if there is a content property. This leads to a lot of strange behaviors unfortunately.

Is this a problem others are seeing or am I doing something weird? Happy to put in a PR to fix this if this is an actual issue.

Matching selected value on related records via async

I've been trying to learn x-select and ran across some odd behaviour I'd like to ask about. Basically records from my api related via async: true are recognized with it's matching record. When I flip the switch and say async: false, the matching records are recognized.

The record loaded through an async:true relationship is wrapped up in a promise object. This happens even when records are eager loaded from the api.

So how can I compare related records when they are wrapped up in a promise object?

Here is a contrived example:

models/city.js

export default DS.Model.extend({
    ...
    state: DS.belongsTo('state', {async: true}),    
    //false means the matching value is detected in subsequent x-select    
});

city.state is different depending on async:true|false
consequently it doesn't match up correctly

            {{#x-select value=city.state}}
                {{#x-option value=null}}Select{{/x-option}}
                {{#each states as |item|}}
                    {{#x-option value=item}}{{item.id}}{{/x-option}}
                {{/each}}
            {{/x-select}}

x-option declared without x-select error

Version of x-select:

2.0.2

Ember Version / Ember CLI Version:

1.13.15

Problem:

{{#x-select value=task class="form-control"}}
  {{#x-option value=""}}Vลกechny รบlohy{{/x-option}}
    {{#each tasks as |t|}}
      {{#x-option value=t}}{{t.title}}{{/x-option}}
    {{/each}}
{{/x-select}}

tasks is computed property. When tasks changes, browser logs to console: Error: Assertion Failed: x-option component declared without enclosing x-select.

I expect x-option to update its items withnout prompting any error.

Steps To Reproduce:

Simply declare tasks as computed property and template as showed above.

Multiple {{x-selects}} on the same template

I am trying to use multiple selects on my template, as follows:

<label>Type</label>
{{#x-select value=model.type.content action="selectType"}}
  {{#each types as |item|}}
    {{#x-option value=item}}{{item.name}}{{/x-option}}
  {{/each}}
{{/x-select}}
<label>Status</label>
{{#x-select value=model.status.content action="selectStatus"}}
  {{#each statuses as |item|}}
    {{#x-option value=item}}{{item.name}}{{/x-option}}
  {{/each}}
{{/x-select}}

But this throws the following message in the console:

Error: Assertion Failed: x-option component declared without enclosing x-select

If I remove either of the selects, it works.

The relevant route code:

import Ember from 'ember';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller, model);

    controller.set('statuses', this.store.findAll('status'));
    controller.set('types', this.store.findAll('type'));
  },

  actions: {
    selectStatus: function(selection) {
      console.log('Selecting status');
      if (selection) {
        this.get('currentModel').set('status', selection);
      }
    },

    selectType: function(selection) {
      console.log('Selecting type');
      if (selection) {
        this.get('currentModel').set('type', selection);
      }
    }
  }
});

Am I doing something wrong?

PS: Using version 1.1.4, ember-cli 1.13.1.

emberx-select does not select initial value in component

I have a component whereby I inject a site ember-data model into it.

Using Ember.Select the following is working

                    {{view "select"
                    class="form-control"
                    content=sites
                    optionValuePath="content.id"
                    optionLabelPath="content.displayName"
                    selection=site
                    disabled=false
                    prompt="Please Select"
                    }}

I have converted it to emberx-select as follows

                    {{site.name}} <!-- This correctly displays the site name -->
                    {{log site}}
                    {{#x-select disabled=false value=site action=(action (mut site)) class="form-control"}}
                      {{#x-option value=null}}Please Select{{/x-option}}
                      {{#each sites as |item|}}
                        {{#x-option value=item}}
                          {{item.displayName}}
                        {{/x-option}}
                      {{/each}}
                    {{/x-select}}

But the selected item remains on "Please Select" when the page is refreshed. As the site is {{async:true}} in the parent model model.site I have tried using value=site.content but that does not work either.

Any ideas?

Depreciation - hasBlock

hasBlock is missing on the x-select.hbs.
Unfortunately, hasBlock is not available on the current ember version of the component.

action not fired when expected

Using this for the first time.

given this example

{{#x-select id="age-group" value=ageGroup action="selectAgeGroup"}}
    {{#x-option}}Select Age Group...{{/x-option}}
    {{#x-option value="18-25"}}18-25{{/x-option}}
    {{#x-option value="25-35"}}25-35{{/x-option}}
    {{#x-option value="35-55"}}35-55{{/x-option}}
    {{#x-option value="55+"}}55+{{/x-option}}
{{/x-select}}

when action is fired, it receives the previous value. So if I change to "25-35" from "18-25". this.get("ageGroup") is 18-25. Not the new value.

The only way I can get this to work is to use an observer. That has the correct value.

Disable x-select mutating "value" upon selection

Should we add a way to disable the mutating behavior of x-select? I want to trigger the action only and leave the value as-is.

I was surprised the component did this as it violates ember's "data down actions up" principle.

We can actually just remove the mutating behavior, and if you want to mutate the value, you can easily pass in an action with the mut helper.

Something like:

{{#x-select value=currentSelection action=(action (mut currentSelection))}}
  ....
{{/x-select}}

SyntaxError: Unexpected token

I installed the addon, but when I run the server I get the following error:

โฏ ember s                                                                                 โœฑ
version: 0.2.0-beta.1
Could not find watchman, falling back to NodeWatcher for file system events
Livereload server on port 35729
Serving on http://0.0.0.0:4200/floorplan-editor/
File: emberx-select/components/x-select
Unexpected token (84:2)
SyntaxError: Unexpected token (84:2)
    at raise (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:333:15)
    at unexpected (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:1366:5)
    at expect (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:1360:18)
    at parseObj (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:2203:9)
    at parseExprAtom (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:2136:14)
    at parseExprSubscripts (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:2012:28)
    at parseMaybeUnary (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:1995:16)
    at parseExprOps (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:1946:24)
    at parseMaybeConditional (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:1930:16)
    at parseMaybeAssign (/home/pedro/Finesce/code/floorplan_editor/node_modules/ember-cli/node_modules/broccoli-es6modules/node_modules/esperanto/node_modules/acorn/acorn.js:1913:16)

Note that I am using ember-cli 0.2.0.beta.1 which has changed a few things about addons. It might be related.

Icons not displayed (optgroups)

I'm trying to create a dropdown select box for icons by doing the following:

{{#x-select id='select-tag' class="form-control" value=currentIcon}}
  {{#each icons as |optgroup| }}
    {{#x-option class="disabled" value=null}}<strong> - {{optgroup.group}} - </strong>{{/x-option}}
    {{#each optgroup.icons as |icon|}}
      {{#x-option value=icon}}<i class="fa fa-{{icon}}"></i>&nbsp; {{icon}}{{/x-option}}
    {{/each}}
  {{/each}}
{{/x-select}}

However, the icons are not displayed. Also, optgroups don't seem to be implemented.

x-select to support attributes similar to ember select

x-select to support attributes similar to ember select

e.g.

{{x-select value=selections multiple=false action="selectionsChanged" content=model.books optionValuePath="content.id" optionLabelPath="content.title" prompt="Please select a name ember x-select"}}

i.e. in similar lines to
{{view "select"
content=model.books
optionValuePath="content.id"
optionLabelPath="content.title"
prompt="Please select a name ember select"
value=2}}

test against canary

new ember-addons ship with a travis.yml that does this automatically. This would likely be great for this add-on

How does this work with `fillIn` test helper?

Since the fillIn API uses jQuery under the hood, how will tests select values?

Instead of controlling the optionValuePath (i.e. content.id), the addon manages that for us by referring to the model's Ember ID (i.e. "<my-app@model:post::ember621:1>").

How could we select the proper <option>, given that calling fillIn with the text value doesn't seem to work?

dynamically hide options

I want to hide some options based on the property isStreak. So I wrote the following code:

{{#x-select value=format}}
  {{#each formats as |format|}}
    {{#x-option value=format}}{{format}}{{/x-option}}
  {{/each}}
  {{#unless isStreak}}
    {{#each buildStatesFormats as |format|}}
      {{#x-option value=format}}{{format}}{{/x-option}}
    {{/each}}
  {{/unless}}
{{/x-select}}

This code does show all options regardless of isStreak. If I put the whole x-select inside an unless everything works fine, but this is not what I am looking for.

Is this a bug, or is this just not supposed to work?

Version of x-select: 2.0.2
Ember Version / Ember CLI Version: 2.3.0

Default value not applied

Using the simple example with property binding, a normal select would have the first value selected without user interaction. With emberx-select, unless you manually select an option the value model.status will be empty/undefined/etc by default.
Can/should this be fixed, or is there a workaround?

{{#x-select value=model.status }}
  {{#x-option value=1}}Active{{/x-option}}
  {{#x-option value=2}}Inactive{{/x-option}}
{{/x-select}}

update readme to remove reference to Ember.select

Really minor, but Ember.Select is deprecated, so a new justification for this component in the readme would be helpful. The new suggested way to do selects in the ember doc is also not great....

Export `select` function for use in integration tests

It would be really nice if we could refactor the select test helper to a function that's exported and can be imported to integration tests. Something like:

import Ember from 'ember';

export function select(selector, ...texts) {
  let $options = Ember.$(`${selector} option`);

  $options.each(function() {
    let $option = Ember.$(this);

    Ember.run(() => {
      this.selected = texts.some(text => $option.is(`:contains('${text}')`));

      if(this.selected) {
        $option.prop('selected', true).trigger('change');
      }

    });
  });
}

export default function() {
  Ember.Test.registerAsyncHelper('select', function(app, selector, texts) {
    // let $options = app.testHelpers.findWithAssert(`${selector} option`); how to keep this?

    select(selector, texts);

    return app.testHelpers.wait();
  });
}

There are still things to figure out but it would be really nice to have this helper.

Deprecation in 1.13.8

I just upgraded to ember 1.13.8 and I'm seeing the following deprecation notice from emberx-select:

DEPRECATION: A property of <crawler-ui@view:-outlet::ember453> was modified inside the didInsertElement hook. You should never change properties on components, services or models during didInsertElement because it causes significant performance degradation.
        at _emberViewsViewsCore_view.default.extend.scheduleRevalidate (http://localhost:4200/crawler/assets/vendor.js:60027:34)
        at http://localhost:4200/crawler/assets/vendor.js:22220:32
        at Object.Stream.notifySubscribers (http://localhost:4200/crawler/assets/vendor.js:31572:11)
        at Object.Stream.notifyExcept (http://localhost:4200/crawler/assets/vendor.js:31512:14)
        at Object.Stream.notify (http://localhost:4200/crawler/assets/vendor.js:31506:12)
        at Object.apply (http://localhost:4200/crawler/assets/vendor.js:32915:18)
        at Object.sendEvent (http://localhost:4200/crawler/assets/vendor.js:26465:28)
        at notifyObservers (http://localhost:4200/crawler/assets/vendor.js:30002:25)
        at propertyDidChange (http://localhost:4200/crawler/assets/vendor.js:29798:5)

I'm getting one deprecation notice for each option tag in the select. My template is:

  {{#x-select value=daysFilter action="filterByDate"}}
    {{#each daysList as |day|}}
      {{#x-option value=day.value}}{{day.text}}{{/x-option}}
    {{/each}}
    {{#x-option value='custom' class=(if isStandardDate 'is-hidden')}}Custom range{{/x-option}}
  {{/x-select}}

I'm using the head of master, as recommended. I even tried rm -rf node_modules ; npm cache clean ; npm install to verify I was REALLY getting the latest, but no luck.

My package.son has "emberx-select": "thefrontside/emberx-select",

Is it possible to set a default value?

I'm currently doing this to preselect the default value:

{{#x-select value=currentSelection}}
  {{#each model.persons as |person|}}
    {{#if person.default }}
    {{#x-option value=person.id selected=true}}
      {{ person.name }}
    {{/x-option}}
    {{else}}
    {{#x-option value=person.id }}
      {{ person.name }}
    {{/x-option}}
    {{/if}}
  {{/each}}
{{/x-select}}

But this doesn't set currentSelection when rendered (even though it does show the default as selected). currentSelection is only set after manually selecting a value. Couldn't find anything about this in the docs. Is there a recommended way of doing this with emberx-select?

Depreciation - Performance degradation

A depreciation is trigger:
You should never change properties on components, services or models during didInsertElement because it causes significant performance degradation.

It is caused by addon/components/x-option.js (line 60) in the didInsertElement:

this.set('select', select);

Any way to find a better solution ?

Selection not synced properly when using model object

I came across this issue, I would like to share it, may be README could be updated as well, it took me several days to get it working.

Basically, the scenario is that you have an item model with belongsTo category property. you want to edit an item and show categories as a select box, so user can update the category.

you have to use the content in the select value because the belongsTo is a promise:

//template.hbs
{{#x-select class="form-control" value=model.Category.content}}
    <option></option>
    {{#each categories as |category|}}
        {{#x-option value=category}}{{category.name}}{{/x-option}}
    {{/each}}
{{/x-select}}

Selection not selected when component rerendered

{{x-select content=baseThemes
  action="changeBaseTheme"
  selection=currentBaseTheme
  optionLabelPath='content.label'
  optionValuePath='content.id'}}

When the action fires, it sets currentBaseTheme which is located in a service. Now this select is in a panel that renders in an outlet. Once the panel is closed, and reopened, even though currentBaseTheme is the last selected value, the select box shows the first option as selected.

Selection not set when using a RecordArray as `content` and a PromiseObject as `value`

I'm trying to build a select box to let the user choose a models.belongsTo property from a list of models retrieved through the store. While the selection process in general is working, the initial selection after reloading the page is not set.

x-select content=recordArray selection=model.belongsToRecord optionValuePath="content" optionLabelPath="content.title"

If I use recordArray.content and model.belongsToRecord.content, the initial selection is set properly, but the selection process stops working ( the model.belongsToRecord is not properly set anymore ).

Digging in with the Ember Inspector I can see that the value on the x-select component is a PromiseObject whereas the value of the x-option component is the resolved value of the Promise.

I guess the comparison between those two with an === operator is not working.

Emberx Select flashes/blinks on first click

Version of x-select: 2.1.2

Ember Version / Ember CLI Version:

Ember Version: 2.4.3
Ember CLI Version: 2.4.3

Expected Behavior

Actual Behavior

When clicking on an xselect for the first time, a flashing or blinking occurs. This also occurs when clicking away and back on the xselect.

Steps To Reproduce:

  1. Create xselect
  2. Click on it

GIF of behavior

xselect-bug

Can you use native HTML attributes within x-option

Version of x-select: 2.1.0

Ember Version / Ember CLI Version:

Ember Version: 2.1.0
Ember CLI Version: 1.13.13

Expected Behavior

I should first mention I am extremely new to Ember

I'm trying to include the native "disabled" attribute of a select option within the x-option.

The disabled attribute is a boolean attribute. When present, it specifies that an option should be disabled.

Actual Behavior

The native "disabled" attribute doesn't seem to be processed at all. The work around that I have is by adding a "didInsertElement" into my component js, but ideally it would be better/easier if the x-option had some kind of disabled attribute like the native HTML select does.

didInsertElement: function () { this.$('option:first').attr('disabled', true); }

Steps To Reproduce:

  1. Create an x-select
  2. Create an x-option and try using the native HTML select option "disabled" attribute
  3. Example: {{#x-option disabled value=defaultSelect}} {{defaultSelect}} {{/x-option}}

x-option registers too often

x-option component tries to register itself from didRender() hook (https://github.com/thefrontside/emberx-select/blob/master/addon/components/x-option.js#L54). And didRender() hook is called on every re-render cycle (http://emberjs.com/blog/2015/06/12/ember-1-13-0-released.html#toc_component-lifecycle-hooks).
Sometimes in acceptance tests we get into situations then x-option tries to register itself after outer x-select is removed (naturally an exception is thrown).

I think it is not necessary to register from every didRender call and it should be enough from didInsertElement() hook.

Changing x-select options gives `Cannot read property 'unregisterOption'` of undefined error

I am using x-select in the following way to render respective states of selected country,

.large-3.columns
  x-select value=model.country class="formcustominput"
    each model.countries
      x-option value=this | #{this}
.large-3.columns.left
  x-select value=model.state  class="formcustominput"
    each model.states
      x-option value=this | #{this}

To change states when user selects country I have added observer in the the model and whenever country changes I update my model.states but when I do that x-select throws an error

Block less not supporting ValuePath

Hey,

The optionValuePath isn't used - this makes the blockless version useless.

a283762
The fix to make it work is:

/**
   * Auxiliary computed array that holds `content` array
   * values and their labels. Used only in the blockless version.
   *
   * @private
   * @property _optionValues
   */
  _optionValues: Ember.computed.map('content', function(obj) {
    return {
      value:  Ember.get(obj, this.get('_ValuePath')),
      label: Ember.get(obj, this.get('_labelPath'))
    };
  }),

And add the following

/**
   * Auxiliary computed property that replaces `content.`
   * in `optionValuePath`.
   *
   * @private
   * @property _ValuePath
   */
  _ValuePath: Ember.computed('optionValuePath', function() {
    return this.get('optionValuePath').replace(/^content\.?/, '');
  }),

Which is just like the _labelPath

Convert to component integration test

This will probably end up happening when we get designs to make the demo page nicer. This will allow the demo page to be an actual demo and not actually our test bed.

Blockless and block form do not behave the same.

The following two controls are essentially the same. The problem is that the BLOCKLESS control does not set the initial selection property via selection=addressType; it remains on the first option. It work perfectly in the BLOCK control using value=addressType.

BLOCKLESS

                      {{x-select action=(action (mut addressType))
                      multiple=false
                      content=addressTypes
                      selection=addressType
                      optionValuePath="content.id"
                      optionLabelPath="content.name"
                      }}

BLOCK

                    {{#x-select value=addressType action=(action (mut addressType)) }}
                      {{#each addressTypes as |item|}}
                        {{#x-option value=item.id}}
                          {{item.name}}
                        {{/x-option}}
                      {{/each}}
                    {{/x-select}}

In my controller

  addressTypes : [
    {
      id : 'PRIVATE',
      name : 'Private Address'
    },{
      id : 'BUSINESS',
      name : 'Business Address'
    }
  ],

x-option declared without x-select error

The README mentions that using <optgroup> should be possible when using x-select block form. I'm having a bit of a hard time getting the block form version to work. I use the blockless version just fine in other cases.

Here's what I'm trying to run:

{{#x-select value=problem.service_code.id}}
  <option>Select a Service Code ...</option>
  {{#each model.all_service_codes as |group|}}
    <optgroup label={{group.label}}>
      {{#each group.content as |service_code|}}
        {{#x-option value=service_code.id}}{{service_code.description}}{{/x-option}}
      {{/each}}
    </optgroup>
  {{/each}}
{{/x-select}}

If I add some debugging to the x-option component to try to find the parentView, I'm only getting back a view outlet. Not sure if this is a change to ember in the 2.0 beta 1, or something else.

If I have a chance, I'll try to downgrade back to 1.13 to find out.

Thanks for your help!

Maintainer note: Anyone coming across this issue please try upgrading to Ember 1.13.4. If that doesn't solve your problem, I'd love to hear more :) -@Robdel12

Possibility to insert glyphicons in select options

Version of x-select: 2.0.2

Ember Version / Ember CLI Version:

Ember Version: 2.2.0
Ember CLI Version: 1.13.13

Expected Behavior

Recommendation: When inserting the glyphicons inside the select options or produce other span elements, then it should reflect in the menu options.

{{#x-option value=conf}}
  <span class="glyphicon glyphicon-ok"></span>
  {{conf.title}}
{{/x-option}}

Actual Behavior

No Glyphicon icon is visible.

Steps To Reproduce:

Value not selected after async loaded options

Hello, I searched through the issues but I'm not 100% if my case is the same as others.
Should x-select select the option set in value after the async options are loaded?
Are there any workarounds for this?

My model

import DS from 'ember-data';

export default DS.Model.extend({
  countryId: DS.attr('integer'),
  stateId: DS.attr('integer'),
});

My route

import Ember from 'ember';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller, model);
    controller.set('countries', this.store.findAll('country'));
    controller.set('states', this.store.find('state', { country_id: model.get('countryId') });
  }
});

My template

{{#x-select value=model.countryId action='countryChanged'}}
  {{#each countries as |country|}}
    {{#x-option value=country.id}}{{country.name}}{{/x-option}}
  {{/each}}
{{/x-select}}

{{#x-select value=model.stateId action='stateChanged'}}       
  {{#each states as |state|}}
    {{#x-option value=state.id}}{{state.name}}{{/x-option}}
  {{/each}}
{{/x-select}}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.