Spacebars, semantic dropdown does not show values


#1

hi,

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

I would like to show the name of the customer next to the name of the user. Is this possible?


thank you very much


#2

{{#each customers}}
{{obj.custName}}
{{#each users}}


{{obj.userName}}

{{/each}} {{/each}}

Template.xxx.helpers({
obj:{
userName: abc,
custName: xyz
}
})


#3

Thanks, so the only way is to flatten my sub document to something like
customer.name, user.name array? (your solution uses a different datamodel as input)


#4

I know, my last reply doesn’t fulfill your thing exactly. But will give an idea. Just take required vales from dB to render on ui, and put it in like Json object format and access it in html.


#5

You can use ../ notation to access parent contexts. You can even use ../../, etc to keep going further…

{{#each customers}} 
  {{#each users}}
    <div class="user">{{name}}</div>
    <div class="customer">{{../name}}</div>
  {{/each}} 
{{/each}}

#6

Cool! that did the trick! thank you.

The only thing still left is that if I restart the server, the values are not populated of the listbox (if I insert a new item in the customer collection, then the listbox works. Deleting an item does not force the update)

my helper is

Template.OEMPartner.helpers({
    customers() {
        return Customers.find({}, { sort: { checked: -1 } });
    },

Server side: make http call to external REST API with a certificate to authenticate
#7

What does your subscription look like for customers?


#8

Hi, since it is a demo app i have autopublish still on, see my helper code above

Thanks for your help!


#9

If i inspect the html, i DO see the users already. So it looks like the javascript is not working of the semantic ui dropdown. The dropbox won’t open.

I must say i also have another dropdown in the template. That one works perfect but has static content in it.

this is my onRendered:

Template.OEMPartner.onRendered(function() {
    this.$(".dropdown")
        .dropdown();
});

this is the dropdown that always works

 <div class="ui teal buttons">
            <div class="ui {{loading}} button generateStreamAndApp">Generate</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>
            {{/unless}}
        </div>

this is our problem child:’

<div class="ui selection dropdown">
                    <input type="hidden" id="currentUser">
                    <i class="dropdown icon"></i>
                    <div class="default text">User</div>
                    <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>
                </div>

#10

Ah I think I do know what this is. The onRendered function is only called once, and this will be before the data is loaded.

Assuming you have es6 ecmascript package installed try:

Meteor.defer(() => {
    this.$(".dropdown").dropdown();
});

You can also use

setTimeout(() => {
    this.$(".dropdown").dropdown();
}, 0);

it’s the same thing.

If you’re not using es6 (ecmascript package), you can’t use fat arrow functions so you’d have to do:

var self = this;

Meteor.defer(function () {
    self.$(".dropdown").dropdown();
});

This may not fully solve the issue, if you are expecting the data to be reactive. You may be able to move the defer block inside the helper, so it will call dropdown() whenever the data changes.

Hopefully this is a step in the right direction though :slight_smile:


#11

Thanks,

well we have a tough crowd today… I have ES6 installed, use latest meteor version.

I tried both options, with no luck…

import { Template } from 'meteor/templating';
import { senseConfig as config } from '/imports/api/config.js';
import { Apps, TemplateApps } from '/imports/api/apps.js'
import { Customers, dummyCustomers } from '../api/customers.js';
import { Streams } from '/imports/api/streams.js'

import './OEMPartner.html';

Template.OEMPartner.helpers({
    customers() {
        return Customers.find({}, { sort: { checked: -1 } });
    },
    // users() {
    //     return Customers.find({}, { sort: { checked: -1 } }).fetch().users;
    // },
    templateApps() {
        return TemplateApps.find();
    },
    loading() {
        return Session.get('loadingIndicator');
    },
    NrCustomers() {
        return Customers.find()
            .count();
    },
    linkToApp() {
        return 'http://' + config.host + '/sense/app/' + this.id
    }
});

Template.OEMPartner.events({
    'submit .new-customer' (event) {
        // Prevent default browser form submit
        event.preventDefault();
        // Get value from form element
        const target = event.target;
        const customerName = target.text.value;
        // Insert a task into the collection
        Customers.insert({
            name: customerName,
            checked: true,
            createdAt: new Date(), // current time
            createdBy: Meteor.user()
        });
        // Clear form
        target.text.value = '';
    },
    'change #currentUser' (event, template) {
        var currentUser = template.$("#currentUser")
            .val();
        console.log('helper: user made a selection in the simulateUserLogin box, for user: ' + currentUser);
        try {
            Meteor.call('simulateUserLogin', currentUser);
        } catch (err) {
            sAlert.error(err.message);
        }
    },
    'click .generateStreamAndApp' () {
        console.log('click event generateStreamAndApp');
        Session.set('loadingIndicator', 'loading');

        var selectedCustomers = Customers.find({ checked: true })
            .fetch();
        // console.log('get customers from database, and pass them to the generateStreamAndApp method', selectedCustomers);

        Meteor.call('generateStreamAndApp', selectedCustomers, function(err, result) {
            if (err) {
                sAlert.error(err);
                console.log(err);
                Session.set('loadingIndicator', '');
            } else {
                Session.set('loadingIndicator', '');
                console.log('generateStreamAndApp succes', result);
                sAlert.success('For each selected customer a stream equal to the name of the customer has been made, and a copy of the template has been published in this stream');
            }
        });
    },
    'click .removeTemplateApp' () {
        TemplateApps.remove(this._id);
    },
    'click .insertDummyCustomers' () {
        _.each(dummyCustomers, function(customer) {
            Customers.insert(customer);
            console.log("Inserted " + customer.name);
        })
    },
    'click .deleteAllCustomers' () {
        console.log('delete all dummyCustomers clicked');
        Meteor.call('removeAllCustomers', function(err, result) {
            if (err) {
                sAlert.error(err);
            } else {
                sAlert.success('All customers have been deleted from the local database of the SaaS platform');
            }
        });
    },
    'click .toggleAllCustomers' () {
        console.log('deSelect all dummyCustomers clicked');

        _.each(Customers.find({})
            .fetch(),
            function(customer) {
                Customers.update(customer._id, {
                    $set: { checked: !customer.checked },
                });
            })
    }
}); //end Meteor events

// Template.OEMPartner.onRendered(function() {
//     this.$(".dropdown")
//         .dropdown();
// });

Meteor.defer(() => {
    this.$(".dropdown").dropdown();
});

#12

How about making a new template that just contains the dropdown?

{{#each customers}}
    {{> MyDropdownTemplate users=users}}
{{/each}}

Then use the Meteor.defer(...) inside the onRendered callback of your MyDropdownTemplate.


#13

Mmm, in the html example you can see the values of the users in the dom, so I think it is just the drop down code that is not being executed?

Verstuurd vanaf mijn iPhone


#14

Should I give the drop downs maybe different id or class names?

Ps: on the other side: after I have modified my collection it always works, I only have the issue with a fresh page. So maybe it has nothing to do with this

Verstuurd vanaf mijn iPhone


#15

Btw, to be honest I have just copy pasted the sample code from semantic, and then it works. So. I don’t really know how to modify it as you suggested.

Verstuurd vanaf mijn iPhone


#16

I’ve just created a test app using the semantic:ui package following the instructions at https://github.com/Semantic-Org/Semantic-UI-Meteor.

Works for me with just the this.$('#my-dropdown').dropdown() in the onRendered callback.

I suggest you re-create the most basic app possible and work it out from there. Sorry for the wild goose chase here, often DOM manipulation requires a setTimeout to ensure everything is rendered first.


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

will try that one. thanks. I noticed that if I press f5 (refresh) the dropdown does not work. If I enter some customers in the collection it starts working…

I think there is a bug. I tried tried the demo code: it works. Then i tried my own code again in little steps, it broke, it “undo” my code in sublime text, and it still was not working…

so… the final outcome… it was due to the fact I used a if else statement…

now that I commented out the code it works… thanks for your help sofar!

<template name='simulateUserLogin'>
    <!--   {{#if noCustomers}}
    <div class="ui icon message">
        <img class="icon" src="images/id.png">
        <div class="content">
            <div class="header">
                <h4>No users</h4>
            </div>
            <p> Please insert at least one user in a customer so we can simulate the Single Sign on</p>
        </div>
    </div>
    {{else}} -->
    <div class="ui icon message">
        <img class="icon" src="images/id.png">
        <div class="content">
            <div class="header">
                <h4>Simulate a user login</h4>
            </div>
            <p> We will pass this user and his group membership in a JSON object to Qlik Sense and in this way we create a Single Sign on</p>
            <div class="ui selection dropdown">
                <input name="gender" type="hidden">
                <div class="default text">Select a value</div>
                <i class="dropdown icon"></i>
                <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>
            </div>
        </div>
    </div>
    <!-- {{/if}} -->
</template>

#18

we need a way that we can ensure that a template is not rendered at all. I am playing with the if and unless but I have the idea that that is not really the way to go… that also caused this isssue, and I see the screen flickering. How do you guys do this?

I want to check

  • if customers in mongo then show …

thanks


#19

(note that I did not change the customers based on updates from external API’s), the customers are created and stored locally in meteor.

I load other collections with API’s. (delete first, then load)