Insert meteor template contents from helper?

I have a leaflet map with a popup on each marker. I’d like to use https://github.com/yogiben/meteor-autoform-modals to offer a button in the popup which will open a modal and allow a user to edit the markers data. I don’t want to put a lot of HTML in the JS code as the popup will show a lot of information. Currently all examples show just simple text in the popup, all in the JS - e.g.

var popup = L.popup()
.setLatLng(latlng)
.setContent('<p>Hello world!<br />This is a nice popup.</p>')
.openOn(map);

Is there a way to invoke a template for the popup content, something like {{#afModal collection=data omitFields=‘createdBy,createdAt’ id=245klhb3lk4lkj435 }} from within JS?

Yes! Kind of: you can use Blaze.toHTMLWithData: http://docs.meteor.com/#/full/blaze_tohtmlwithdata

It would look like this probably:

var html = Blaze.toHTMLWithData(Template.adModal, {
  collection: data,
  omitFields: 'createdBy,createdAt',
  id: id
});
var popup = L.popup()
  .setLatLng(latlng)
  .setContent(html)
  .openOn(map);
2 Likes

The basic idea would be to write the popup as a template and then execute the JS necessary to display it in the onRendered callback of the template! I’m not 100% sure that this already covers your exact use case, but that’s the core idea. Render all you can with Blaze/Templates and then add some JS in event handlers on top to implement show/hide/destroy behavior.

Also, Blaze.renderWithData might be useful and is being used for popups/modals as well, in case you have the data available from external sources and it’s more convenient to trigger and render the modal in this way!

HTH!

ps. Damn, @sashko so fast. Will type faster next time. :wink:

1 Like

Great stuff, thanks @sashko and @seeekr - will give it a go tonight.

1 Like

OK so here we go:

var popupHtml = Blaze.toHTMLWithData(Template.afModal, {
            class: "btn btn-primary",
            collection: "CourseLayers",
            omitFields: "createdBy,createdAt,updatedBy,updatedAt",
            operation: "update",
            buttonContent: "Edit",
            doc: document._id
        });

l = L.marker(document.latlng, {icon: iconCheckpoint});
drawnItems.addLayer(l).bindPopup(popupHtml);

I get an empty button (so the template is at lease partially rendering) that generates this code:

<a href="#afModal" class="btn btn-primary" collection="CourseLayers" operation="update">
	
</a>

however when clicking on the button nothing happens. I have {{> autoformModals}} on my page and verified in the code of the page. Seems as if the helpers for {{afModal}} aren’t present as all we are doing with Blaze.toHTMLWithData is generating HTML. Any way to have the template helpers come across too?

Template helpers are naturally already available since they’re defined on the Template itself and there’s no way to even turn them off.

(if we’re talking about helpers on that template)

Now! It’s hard to tell what exactly is going on. (Lots of code that is left out / would have to be looked up.) The only thing that I notice is the smelly doc: document._id definition. I have no idea what the template expects exactly, but a document is not an id.

Oh, and another thing:
I’m not sure how the onRendered / onCreated callbacks are handled, or if that is done at all, when you use the toHTML... method for rendering. Maybe those are just not called and that means those parts of the code simply don’t run and can’t initialize the modal? I’m not entirely sure how Blaze would know that you’ve now used the HTML it rendered and attached it to the page, and that now it should attach its event and lifecycle handlers to it…

You’re right, if you render with toHTMLWithData, event handlers won’t be attached, and the helpers won’t automatically update. I’m not sure how to make this particular popup library work with live templates, it would require more investigation.

Thanks @sashko and @seeekr once again - looks like there may be a stop gap solution - https://github.com/bevanhunt/meteor-leaflet/issues/1

The way I got around this is pretty simple:

var popup = L.popup()
    .setLatLng(latlng)
    .openOn(map);

Blaze.renderWithData(Template.testTest, {}, popup._contentNode);

Reactive variables and events work.

2 Likes