Have you also noticed that semantic ui dropdowns don't work well with blaze conditionals?


#1

Hi,

I noticed that if I use IF, UNLESS etc. in blaze together with semantic ui dropdown, that the dropdown does not work well.

any ideas how to solve this?

(here is my big fight with them)

<!-- {{#unless loading}} -->
            <div class="ui floating dropdown icon button">
                <i class="dropdown icon"></i>
                <div class="menu">
                    <div class="item resetEnvironment"><i class="delete icon "></i> Initialize demo</div>
                    <div class="item insertDummyCustomers"><i class="edit icon "></i> Insert dummy customers</div>
                    <div class="item deleteAllCustomers"><i class="delete icon "></i> Delete all customers</div>                    
                    <div class="item toggleAllCustomers"><i class="refresh icon"></i> Toggle the selected customers</div>
                </div>
            </div>
            <!-- {{/unless}} -->

I noticed that it starts/stops working after you do something in Mongo…

PS: i build this a couple of weeks ago, but I can’t find any js for the dropdown. So maybe this is just HTML, but if that is that case, why doesn;t it work…

thank you


#2

I will admit this is complete and utter hackery, but this is what my selects look like right now:

<select class="ui dropdown groups-select">
  {{#each groups}}
    <option value="{{_id}}">{{name}}</option>
  {{/each}}
  {{> selectRefresher selector=".groups-select"}}
</select>

Template.selectRefresher.onRendered( function () {
  let self = this;
  $(self.data.selector).dropdown();
});

Template.selectRefresher.onDestroyed(function () {
  let self = this;
  $(self.data.selector).remove();
});

I’ve struggled with the same issues, and found this to at least be reliable, despite the fact that it’s not really good programming.

I also sometimes set a timeout in the onRendered and set the value of the select, but that is even hackier, ha!


#3

I can guarantee there is a sensible way to do this but I need an example to work it. If you can create a minimal example (i.e. a public github repo I can clone) showing the problem I’ll be more than happy to help.

It’s likely that you need to split your page into smaller components because you are currently trying to initialise a dropdown that doesn’t exist (because you’ve wrapped it in the {{#unless loading}} block). When the data loads, the dropdown is rendered but you don’t initialise it. If the dropdown was a separate component you could just initialise the dropdown inside the onRendered callback of that component, and pass in the items from the main template when they are loaded.

I also suggest you do some reading of the docs and guide / elsewhere online around these topics, it feels like you don’t really get what’s going on when a template gets initialised and rendered. Understanding that (even on a basic level) will make the rest of it ‘click’ and you’ll understand why it’s not just a case of chucking everything in a big template with an onRendered callback and hoping for the best.


#4

The dropdowns in Semantic are annoying because they are very async. In particular the initialization and updates are async.

What I do is I return the items that go in <div class="menu"> ... </div> as a string that I build in a helper. And that same helper calls a Meteor.defer() method which in turn calls dropdown('refresh')

Template.myDropdown.helpers({
  tree : () => {
    const r = []
    Items.find().forEach(i => r.push(`<div class="item" data-value="${i}">${i}</div>`))
    const t = Template.instance()
    Meteor.defer(() => {
      t.dropdown('clear')
      t.dropdown('refresh')
    })
    return r.join("\n")
  }
})

#5

I also see that in the other post you linked you have a double loop

<div class="menu">
{{#each customers}}
    {{#each users}}
      <div class="item" data-value="{{name}}" data-text="{{name}}">
          <i class="male icon"></i> {{name}} ({{../name}})
      </div>
    {{/each}}
{{/each}}
</div>

Meteor was throwing recomputation errors with a similar (triple) loop in my code. Generating a string from a helper also solved this problem.


#6

Thank you very much for you help. Based on your feedback I looked at my code with a fresh mind (a week later) and saw the issue.

I already had separate it into different templates, but forgot to to put the onrendered in 1 template… so it lifted on the code of the other template…

Template.OEMPartner.onRendered(function() {
    console.log('OEMPartner onRendered');
    $('.ui.dropdown')
  .dropdown()
{{#if readyToTestSSO}}
    <div class="ui segment">
    
        {{> simulateUserLogin}}
    </div>
    {{/if}}
    <div class="ui segment">
        <!-- <i class="users icon"></i> -->
        <!--  <div class="ui left input">
            <form class="new-customer">
                <input type="text" name="text" placeholder="Add new customer" />
            </form>
        </div> -->
        <a class="ui labeled icon button" href="{{pathFor 'users'}}"> <i class="edit icon "></i>1: Insert Customers</a>
        <!-- APP GENERATION BUTTON -->
        <div class="ui buttons">
            <div class="ui buttons">
                <div class="ui {{loading}} button resetEnvironment"><i class="undo icon "></i> Initialize demo</div>
                <!-- {{#unless loading}} -->
                <div class="ui floating dropdown icon button">
                    <i class="dropdown icon"></i>
                    <div class="menu">
                        <div class="item insertDummyCustomers"><i class="edit icon "></i> Insert dummy customers</div>
                        <div class="item deleteAllCustomers"><i class="delete icon "></i> Delete all customers</div>
                        <div class="item toggleAllCustomers"><i class="refresh icon"></i> Toggle the selected customers</div>
                    </div>
                </div>
        
            </div>
            {{#if readyToGenerate}}
            <div class="or"></div>
            <div class="ui {{loading}} primary button generateStreamAndApp"><i class="play icon "></i> 3: Generate</div>
            {{/if}}