Insert partial/component at dynamic location

2019-05-21 11:56发布

问题:

I created a blog where I've got a {{downloads}} component showing the downloads which belong to a post. Currently I render the downloads below {{{post.content}}}.

I'd like to have a special string withing post.content like [postDownloads] and render {{downloads}} there.

Is this somehow possible or are there other approaches to solve this problem?

I put together an easy example illustrating one of the use-cases I'm trying to solve: http://emberjs.jsbin.com/raresalihu/3/edit

App = Ember.Application.create();

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return {
      title: "cool post title", 
      content: "<p>Lorem ipsum</p>[postDownloads]<p>coool stuff</p>",
      downloads: [ { src: "http://example.com/cool-stuff.zip", name: "cool stuff"},
                   { src: "http://example.com/cooler-stuff.zip", name: "cooler stuff"}]};
    }
  }
);

Here's the HTML:

<script type="text/x-handlebars">
  <h2>My Blog example</h2>
  {{outlet}}
</script>

<script type="text/x-handlebars" id="components/down-loads">
  <h3>Downloads</h3>
  {{#each download in downloads}}
    <p><a {{bind-attr href=download.src}}>{{download.name}}</a></p>
  {{/each}} 
</script>

<script type="text/x-handlebars" data-template-name="index">
  {{#with model as post}}
    <h3>{{post.title}}</h3>
    <div>{{{post.content}}}</div>
    {{down-loads downloads=post.downloads}}
  {{/with}}
</script>

回答1:

It seems like in an ideal world you'd be able to get a more structured representation, but if you're confident you can unambiguously find the placeholder (and you trust it to be in a reasonable place), you could split the HTML in half at that point and render the two halves of the HTML on either side of your injected content.

You could extract that process pretty easily into a component; take a look at this JSBin for an example. Using the component there, in your sample above you could do something like:

<script type="text/x-handlebars" data-template-name="index">
  {{#with model as post}}
    <h3>{{post.title}}</h3>
    {{#replace-sigil body=post.content sigil='[postDownloads]'}}
      {{down-loads downloads=post.downloads}}
    {{/replace-sigil}}
  {{/with}}
</script>


回答2:

I would summarize your requirements as so:

1) Provide a single string with the post content. 2) Within that content include handlebars helpers that will be processed to generate embedded content.

The easiest way to do this is to process the original post content as a handlebars template on the server. Use the handlebars compiler on the server to produce a final HTML string that you send to the client as the post content.

If you also need the handlebars helpers to access the context of the template/controller on the client, then you will have to do some the handlebars compiler on the client and process the post text on the client with the proper context from the post. You could do this with a custom helper.

In the client case you could use the HTMLBars compiler and runtime within Ember to better integrate with Ember, rather than handlebars.

If your downloads content is static (meaning it is just HTML), then you can always use {{{downloads}}} to include the html in the output. I am assuming you want full HTMLBars or handlebars syntax in the downloads content.