Render a component within a Widget. (Using select-kit components within plugin code)

If we successfully define a select-kit component within a plugin we are easily able to use it within a *.hbs template file using its pluginApiIdentifiers however, in order to attach that component within a widget using JS code I am not able to make it work. For instance:

I have:

import DropdownSelectBoxComponent from 'select-kit/components/dropdown-select-box';

export default DropdownSelectBoxComponent.extend({
  pluginApiIdentifiers: ['header-profile-dropdown'],
  ...
  
  autoHighlight() { ... },

  computeContent() {
    ...
    return items;
  },

  mutateValue(id) { ... }
});

Then I can go to any template I want to overwrite and write like:

(taking as an example the discovery template)

...
<div id="list-area">
        {{header-profile-dropdown}}
...

And the snippet above will work flawlessly, BUT how I will include that component into a widget like:

    api.reopenWidget('user-dropdown', {
        html(attrs, state) {
          if (this.site.mobileView) {
            return h('div.profile-dropdown-container', [
              this.attach('header-notifications', attrs),
              --> I NEED ATTACH THE COMPONENT HERE <--
            ]);
          }

          ...
        }
      });

NOTE: much of the code has been skipped to keep the post brief. Feel free to ask for the full code if needed.

PD: I have already tried to describe this issue at How to attach a component to a widget with just markup? but looks like it was a too complicated explanation so I am trying to reduce the information here to make it clear and try to find an answer.

إعجاب واحد (1)

I think it was a matter of ask myself the right question: “How to render a component within a widget?” that’s why I updated the topic title. I have found few results already such as: How to render Component inside Widget? I will take a look and post any useful finding if it is needed.

Sadly enough looks like it is not possible, simply put we need to find a way to create a widget instead to render what we need to and render a widget within a widget, cause using the connector there are a lot of limitations. Check also: Rendering Component in decorativeWidget API

same issue here.
this is really terrible frontend code that uses widgets and ember components in the same page, it’s really hard to revamp and maintain.
can’t understand what’s the logic

An example of this is available in Discourse itself:

https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6#L362

I wasn’t there when widgets were created, but as far as I can tell, it was created for performance reasons at a time where frontend and especially mobile frontend had huge performance issues. And for dev simplicity it was added the possibility to inject components into widgets.

You got to understand that Discourse carries some history and we can’t start from scratch every year.

6 إعجابات

This topic was automatically closed after 32 hours. New replies are no longer allowed.

للتسجيل - لدينا نظام جديد لعرض مكونات Ember داخل الأدوات. يمكن العثور على التفاصيل في رسالة الالتزام هنا:

ابحث عن RenderGlimmer في قاعدة الكود الأساسية للعثور على أمثلة للاستخدام.

5 إعجابات

هذا رائع يا @David! … ولكن لماذا قد أواجه صعوبة في استيراد:

import { hbs } from "ember-cli-htmlbars";
Error: Could not find module `ember-cli-htmlbars`

عند محاولة استخدام هذا في مكون سمة (Theme Component)؟

(أنا على أحدث إصدار tests-passed)

إعجابَين (2)

آه… من المحتمل جدًا أن الترجمة المضمنة لا تعمل (حتى الآن) في مكونات السمات. يجب أن تعمل في المكونات الإضافية (منذ هذا الأسبوع). سأرى ما يمكنني فعله لإضافة دعم لمكونات السمات :eyes:

إعجابَين (2)

هذا يجب أن يجعل الأمور تعمل:

سأحاول دمجه الأسبوع المقبل

3 إعجابات

تقدم ممتاز. لدي استخدام لهذا لذا أتطلع إليه :+1:t2:

إعجابَين (2)

تم دمج ذلك - أخبرنا كيف تسير الأمور معك يا @merefield

3 إعجابات

رائع! المكون يظهر الآن في عنصر واجهة المستخدم المستند إلى TC الخاص بي، حتى أن البيانات يتم ملؤها بشكل صحيح، رائع جدًا! :rocket:

شكرًا على الاستجابة المذهلة التي تمت على الرغم من عطلة البنك في المملكة المتحدة!

أعلم أن عناصر واجهة المستخدم تتعامل مع أحداث النقر، ولكن ماذا لو كان لدي مكون يطلق إجراءً، فأين يمكنني التعامل مع هذا الإجراء داخل عنصر واجهة مستخدم؟

إعجابَين (2)

عفوًا ديفيد، لقد رأيت للتو مثالًا، أنا أدرسه!

إعجاب واحد (1)

نعم، هذا على الأرجح أفضل مرجع. لا أعتقد أننا تجاوزنا الإجراءات “حقيقية” بعد في النواة، لذا اصرخ إذا واجهت أي مشاكل.

بالنظر إلى هذا الاختبار مرة أخرى، أشك في أن الدالة actionForComponentToTrigger() ستحتاج إلى @bind فوقها للتأكد من أن this يعمل بشكل صحيح بداخلها.

إعجابَين (2)

حسنًا، هذا يعمل إلى حد ما:

    contents.push(
      new RenderGlimmer(
        this,
        "div.tag-chooser-component",
        hbs`<TagChooser @id="list-with-tags"  @tags={{@data.chosen}} @onChange={{action @data.onChangeUpdateTagSet}}/>
        <button onClick={{@data.actionForClick}} label="blah"/>`,
        {
          chosen: this.chosen,
          onChangeUpdateTagSet: this.onChangeUpdateTagSet,
          actionForClick: this.actionForClick
        }
      ),
    );
    return contents;
  },

  @bind
  onChangeUpdateTagSet(chosen) {
    this.chosen.push(chosen.lastObject);
  },

  @bind
  actionForClick () {
    console.log(this.chosen)
  }
});

يتم استدعاء onChangeUpdateTagSet للتغيير، ويتم استدعاء actionForClick عند الضغط على الزر.

ومع ذلك، أواجه صعوبة في إبقاء مُختار العلامات ممتلئًا.

بمجرد إدخال الإجراء المخصص الخاص بي لـ onChange، يفشل العنصر في تحديث العلامات المحددة في واجهته (على الرغم من أن المتغير المخصص الخاص بي يحتوي على القيم الصحيحة).

وإذا لم أقم بتضمين الإجراء المخصص الخاص بي لـ onChange، فإن واجهة المستخدم للعناصر تعمل مرة أخرى، ولكن لا يمكنني ملء مجموعتي. :thinking:

حاولت إضافة this.scheduleRerender() إلى الدالة onChangeUpdateTagSet ولكن هذا يظهر كـ undefined - من الواضح أنه ليس في نطاقه؟

أضفت حدث نقر إلى الأداة وهي تقوم بعد ذلك بالتحديث مع عرض البيانات الصحيحة.

ومع ذلك، يبدو أن الربط يسير في اتجاه واحد فقط، لذا لا يمكنني استخدام العنصر لتحديث البيانات الخارجية، فقط لدفع بيانات جديدة إلى العنصر.

هل هناك طريقة لجعل الربط ثنائي الاتجاه؟

أعتقد أنك ستحتاج إلى استخدام widget ‘state’ بدلاً من الوصول إلى this.chosen - مثيلات الأداة قصيرة العمر و “عديمة الحالة”. ستحصل على مثيل جديد عند كل إعادة عرض، مما يعني أنه سيتم إعادة تعيين this.chosen.

إعجاب واحد (1)

this.state غير معرفة داخل دالة التغيير، مما يجعل الأمور صعبة بعض الشيء؟

(يمكنني تمريرها، لكن ذلك يكتب فوق البيانات الواردة من المكون لإخباري بما تم اختياره

  onChangeUpdateTagSet: this.onChangeUpdateTagSet(this.state),

)

إعجاب واحد (1)

هل يمكنك مشاركة المزيد من كود الويدجت؟ على حد علمي، لكي تعمل الحالة (state) تحتاج إلى تعريف دالة buildKey ودالة defaultState().

سأرى ما إذا كان بإمكاني إضافة مثال لهذا النوع من الأشياء في اختبارات MountWidget :eyes:

إعجاب واحد (1)