How do I fake "Dynamic Outlets"?


#1

The issue that I’m trying to work around is getting a view to render in a Leaflet popup, which is created like this:

var popup = new L.Popup(),
  marker = new L.Marker(latlng);

popup.setContent("html and content here");
marker.bindPopup(popup);

What I need to do is update the popup content every time the view is updated with new data.


I was doing the follow:

contentUpdated: function () {
  //..update popup using this.$().html()
}.observes("controller.content.@each")

But this does not give me the latest this.$(), but the previous one, since the content doesn’t render at the same time that it changes. I know there is no way to do something like:

popup.setContent("{{outlet popup}}");

What are my options? Are dynamic outlets in the future of ember, or do I have to go about this in a jQueryish way?


#2

Looks like this approach might be helpful:

Although, I don’t think copying html is very Emberish, especially since I’ll need events later on. Any suggestions, is there a way to make a view and instance of L.Popup and also Ember.View?

Looking for any ideas at all.


#3

Can you explain what about the normal outlet approach doesn’t work for your case?


#4

I’m not positive, but I think the question boils down to this - http://jsbin.com/erepas/1/edit

Given that you just provide a simple string to set popup content, how can you make that content bindable like a normal template?


#5

Yeah, basically along those lines, although not limited to a string, could be jQuery object or just DOM elements, since I could extend the L.Popup class, since at the core it’s setting DOM elements via innerHTML and appendChild (see here).

This is what I’m doing now or this, and this “works”, except that the events are no longer bound, and I’m sure bindings are broken.

I can also do something like this:

  mapPopupOpen: function (event) {
    App.PopupView.create({}).appendTo($(".leaflet-popup-content"));    
  }

But that gives me the following error (the templates are still inserted), since I’m trying to insert a Ember.View into a parent view.

Assertion failed: You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.

Although, the same happens if I try to appendTo am Ember.ContainerView instance. I’m assuming it wants the container to be appended either using {{view}} or via an {{outlet}}.


#6

@knownasilya I’ve just been looking at the same problem - using a view for a leaflet.js popup where the popup content must be explicitly set through setContent.

Not sure of a solid Ember idiomatic approach but what seems to work for me is a hacky approach very similar to what you’re doing -

  • render the PopupView inside a hidden div
  • on popupopen:
  • store the view $().parent() in $parent so we have the original parent
  • view.$().detach() and store in $content
  • setPopupContent($content.get(0))
  • on popupclose:
  • setPopupContent(’’)
  • $parent.append($content.get(0))

The idea being that at any point the view elements are in the DOM, we just move them into the popup container and then back out again when the popup is closed. This appears to work and keep the bindings, events, etc but is not thoroughly tested.


#7

I wonder if there is a better way to do this now. I keep stumbling on use-cases that use this kind of content handling (html content as a string).

Here’s an example with Google Maps InfoWindow, although I get the following error:

DEPRECATION: Using the defaultContainer is no longer supported. [defaultContainer#lookup] see: http://git.io/EKPpnA

Edit: Fixed that issue by using hiddenPopup = this.container.lookup('view:popup'); (with set’s after instantiation) instead of hiddenPopup = App.PopupView.create({..})


#8

I’m having a similar issue with wrapping ACE editor in an Ember view. Currently I use the “create(), appenTo() Pattern” but even if I do it within the parent view’s didInsertElement(), I get "Assertion failed: You cannot append to an existing Ember.View." It works but I don’t like it. So far I haven’t found a better solution.


#9

I’ve got a similar issue. I’m using the Ember-Leaflet library (a wrapper that helps you dead with Leaflet in a more Ember-ish way). Unfortunately, it doesn’t support binding content in popups, so I am at a bit of a loss as to where to start with this.

Any suggestions?


#10

I had problems since Ember 1.4 Beta 5 because the error broke my app. The best solution I could came up with so far is to put everything in components and create a template with the HTML you need dynamically in the view and compile it on the go. This however only works if you really do not modify the HTML once inserted on the DOM.


#11

This is a bit of an aside, but how does one render a handlebars template programatically, one-off?

I’m trying Ember.TEMPLATES['template_name'](myContext), but getting an error due to there not being some buffer object. All I really want it to render it into a string.


#12

liike this:

MyApp.MyView = Ember.View.extend({
  template: Ember.Handlebars.compile('<p>{{blah}}</p>'),
})

Or you can even make the template a computed property and update it depending on your app state.


#13

Yes, but I don’t have the template as a string. It’s already been compiled by my build tools, and is contained in the Ember.TEMPLATES object. What I want to do is evaluate an already-existing template with a context of my choosing.