cibernox / ember-power-select

The extensible select component built for ember.
http://www.ember-power-select.com
Other
540 stars 377 forks source link

Unable to render a trigger component instead of the default one in new release of ember-power-select. #1429

Open alireza-far opened 3 years ago

alireza-far commented 3 years ago

Upgrading our apps from Ember v.3.16 to v.3.20, but I’m not able to use my trigger instead of the default one in the ember-power-select(-multiple).

    "ember-cli": "3.20.2",
    "ember-cli-babel": "7.21.0",
    "ember-basic-dropdown": "3.0.12",
    "ember-power-select": "4.1.2",
    "ember-concurrency": "1.0.0",
    "ember-concurrency-decorators": "2.0.3",

FYI: there was no issue with overriding triggers in ember v.3.16 since we used ember-power-select v3.0.6

Since there was a bug in ember-basic-dropdown “TypeError: Cannot read property 'appendChild' of null at BasicDropdown.animateOut” (this issue has been solved in the library release of v.3.0.0-beta.9.) and Ember-power-select point to that release in its release of v.4.0.0, it's needed to upgrade to Ember-power-select new release which is also compatible with ember v.3.20 (v.4.0.5 and upper)

Since Ember-power-select started using TypeScript from release of 4.0.0 and changed its component structure to using JS and HBS files in the same directory from version 4.0.5, I think there is a conflict with Ember components structure!

I’ve also tried using "triggerComponent" api for rendering our component instead of the default one inside the trigger, but it didn’t work.

I'll be thankful if you help me for addressing this issue.

cibernox commented 3 years ago

Can you provide a simple reproduction. I believe that this scenario is covered by the tests, seems weird that we had a regression on that. Perhaps you have conflicting versions of ember-basic-dropdown?

abel-n commented 3 years ago

I might have the same issue, I shared some details here.

alireza-far commented 3 years ago

Thanks @cibernox for your response.

Here is the simple reproduction of our use case: As you can see below ember-power-selection is a part of our form component.

app
  components
    form
      select.js
app
  components
    form
      multiselect.js
....
app
  template
    components
      form
        select.hbs
app
  template
    components
      form
        power-select
          trigger.hbs
app
  template
    components
      form
        multiselect.hbs
app
  template
    components
      power-select-multiple
        trigger.hbs
....

And here is an example of our components/templates for select/multiselection fields:

// app/components/form/select.js

import Component from '@ember/component';

export default class FormSelectComponent extends Component {
....
}

// app/components/form/multiselect.js

export default class FormMultiSelectComponent extends Component {

}

app/template/components/form/multiselect.hbs
<PowerSelectMultiple
    @triggerComponent={{component "app/template/components/power-select-multiple/trigger"}}
    @onChange={{onchange}}
    @options={{@options}}
    @searchEnabled={{@searchEnabled}}
    @searchField={{searchField}}
    @selected={{this.selected}}
    @verticalPosition={{@verticalPosition}}
    as |items|
>
  {{#if (has-block)}}
    {{yield items}}
  {{else if this.objectOptions}}
    {{#if items.length}}
      {{#each items as |item index|}}
        {{~if index ', '~}}{{~get item ~}}
      {{/each}}
    {{else}}
      {{get items}}
    {{/if}}
  {{else}}
    {{items}}
  {{/if}}
</PowerSelectMultiple>

app/template/components/power-select-multiple/trigger.hbs
<ul
  id="ember-power-select-multiple-options-{{@select.uniqueId}}"
  class="ember-power-select-multiple-options"
  touchstart= {{fn this.chooseOption}}
  mousedown= {{fn this.chooseOption}}
  ...attributes>
  {{#each @select.selected as |opt index|}}
    <li class="ember-power-select-multiple-option {{if opt.disabled "ember-power-select-multiple-option--disabled"}}">
      {{#if @selectedItemComponent}}
        {{component @selectedItemComponent extra=(readonly @extra) option=(readonly opt) select=(readonly @select)}}
      {{else}}
        <span class="ember-power-select-selected-item">{{~if index ', '~}}{{yield opt @select}}</span>
      {{/if}}
    </li>
  {{else}}
    {{#if @placeholder}}
      <span class="ember-power-select-placeholder">{{@placeholder}}</span>
    {{/if}}
  {{/each}}
</ul>

Reaching out ember-power-multiselect in the other components is like:

 <form.multiselect
   @options={{this.options}}
   @placeholder='Select options'
   @searchEnabled={{true}}
    ...
 />

FYI: The goal is using power-select input field instead of multiselect one and also deleting the remove element options spans. There is no conflicting versions of ember-basic-dropdown in our app as I've tested with its different versions. Also I've tried overriding by using triggerComponent api like below but it didn’t find our trigger components.

<PowerSelectMultiple
    @triggerComponent={{component "app/template/components/power-select-multiple/trigger"}}
  .....

<PowerSelectMultiple
    @triggerComponent="app/template/components/power-select-multiple/trigger"
  .....

Those components has been worked fine with previous versions of :

  ember v.3.16
  ember-power-select v3.0.6
  ember-basic-dropdown 2.0.6

And I believed that it's not related to conflicting versions of ember-basic-dropdown, since I've tried the same structure of using our form in another app which is not using ember-basic-dropdown as its dependencies.

PS: @abel-n Probably, It's look like the same issue.

alireza-far commented 3 years ago

Any update for this issue?Any help would be appreciated !

bobisjan commented 3 years ago

👋, @kaspiZonky and I faced with similar issue today - our component extending add-on's trigger was ignoring custom template. Since the add-on's components are co-located now, we were able to fix the issue by co-locating our component as well.

BAD ⛔️ (using pods, but assuming the same applies for classic)

// app/components/ui/dropdown/trigger/component.js
import Trigger from 'ember-power-select/components/power-select/trigger';
export default class UiDropdownTriggerComponent extends Trigger {}
{{!-- app/components/ui/dropdown/trigger/template.hbs --}}
<div>...</div>

GOOD ✅

// app/components/ui/dropdown/trigger/index.js
import Trigger from 'ember-power-select/components/power-select/trigger';
export default class UiDropdownTriggerComponent extends Trigger {}
{{!-- app/components/ui/dropdown/trigger/index.hbs --}}
<div>...</div>

Hope this helps 🤞

abel-n commented 3 years ago

@bobisjan @alireza-far Jan's hint worked like a charm, everything was fine after I replicated the original component hierarchy.

However, since then I've started recreating my addon (newest Ember, newest power-select) and I had some problems overriding trigger template, once again.

To resolve, I needed to add ember-power-select to ember-addon.after in package.json to ensure my addon overrides app exports after power-select had done its part.

{
  [...]
  "ember": {
    "edition": "octane"
  },
  "ember-addon": {
    "after": [
      "ember-intl",
      "ember-power-select"
    ],
    "configPath": "tests/dummy/config"
  }
}
bmaehr commented 2 years ago

Could please, please, please one of

@abel-n @bobisjan @alireza-far @cibernox @betocantu93

post a complete, correct and working configuration to use a custom trigger like it was possible before version 4?

I have spent during the last year around 5 days to get this ... trigger component working by trying to combine all the different snippets form this issue, #1422 and the source code after upgrade to version 4.1.6 and I'm about to remove the whole componet from the project.

I have a ember addon wrapping the power-select component and at the moment when I'm using the same version of the addon the custom trigger is rendered, in the other project not.

Even

xx<Controls::-PowerSelectCustomTrigger />xx

<div class="select-custom-search">
  <PowerSelect @selected={{this.selected3}}
    @onChange={{fn (mut this.selected3)}}
    @triggerComponent="Controls::-PowerSelectCustomTrigger" as |num|>
    {{num}}
  </PowerSelect>
</div>

renders

xx
<!---->
<span class="ember-power-select-status-icon custom"/><!--CUSTOM-TRIGGER-->
xx
<div class="select-custom-search">
  <div class="ember-basic-dropdown-trigger
      ember-power-select-trigger " role="button" tabindex="0" data-ebd-id="ember317-trigger" aria-owns="ember-basic-dropdown-content-ember317" aria-expanded="false">
      <!---->
    <span class="ember-power-select-status-icon"/> <!--DEFAULT-TRIGGER-->
  </div>
  <div id="ember-basic-dropdown-content-ember317" class="ember-basic-dropdown-content-placeholder" style="display: none;"/>
</div>

in the second project.

abel-n commented 2 years ago

@bmaehr The way I managed to resolve it was already described just above, apart from having the same "file structure" (so, co-located template, like addon/components/power-select.js and addon/components/power-select.hbs, with one app re-export app/components/power-select.js), I had to configure my addon so in package.json it has after: ['ember-power-select'].

I referenced power-select component here but the same applies for all sub-components of this addon.

Passing @triggerComponent is a different matter, though, if you did not override the original <PowerSelect>, it should work fine for sure.

power select version used in our addon: 4.1.6

addon folder: image

app folder: app/components/power-select.js

export { default } from 'ember-smily-base/components/power-select';

package.json:

  "ember-addon": {
    "after": [
      "@docfy/ember",
      "ember-intl",
      "ember-power-select"
    ],
  // [...]
  },
bmaehr commented 2 years ago

@abel-n Thank you for your answer. But where are you overriding the trigger component if not with triggerComponent ?

bmaehr commented 2 years ago

I finally found out what the problem with triggerComponent is: You have to add (at least with the dependencies and versions in my package.json) the dependency "ember-truth-helpers": "3.0.0", to package.json

betocantu93 commented 2 years ago

@bmaehr I prefer doing wrappers (composition) instead of extending or overriding, it tends to be easier to maintain specially templates... like so: https://github.com/prysmex/ember-eui/blob/master/packages/core/addon/components/eui-combo-box/index.hbs

abel-n commented 2 years ago

@betocantu93 is right, unless you want to override a behavior not exposed in any way.

And for future reference, the original issue of @bmaehr is not related to ember-power-select. ember-truth-helpers only needs to be included in dependencies if you actually use it in an exported component, which is the expected behavior of ember addons. (That is, my very basic reproduction did not include truth helpers and everything went fine.)

bmaehr commented 2 years ago

@betocantu93 is right, unless you want to override a behavior not exposed in any way.

I'm doing a wrapper and setting triggerComponent and that stopped working.

And for future reference, the original issue of @bmaehr is not related to ember-power-select. ember-truth-helpers only needs to be included in dependencies if you actually use it in an exported component, which is the expected behavior of ember addons. (That is, my very basic reproduction did not include truth helpers and everything went fine.)

I think this line https://github.com/cibernox/ember-power-select/blob/00498e6d1045d6de53000e4cb62bf0be3c3a17cd/addon/components/power-select.hbs#L52 is not working without ember-truth-helpers

You didn't use the triggerComponent attribute, that's why you didn't have a problem.

abel-n commented 2 years ago

You didn't use the triggerComponent attribute, that's why you didn't have a problem.

My previous example was from our very complex addon and indeed it is overriding the <PowerSelect> instead of wrapping it.

My very basic reproduction was done on a clean addon / app to ensure there is nothing that affects the test case that shouldn't be there. I pushed the repositories, here is the application you can clone and serve locally to see a fully functional select with custom trigger, no truth helpers added in addon or in consumer app: https://github.com/abel-n/power-select-trigger-override-example-app