Quantcast
Channel: Ember.JS - Latest topics
Viewing all articles
Browse latest Browse all 4828

Use output compiled handlebars at runtime as attribute and in DOM

$
0
0

@harianus wrote:

In our codebase we use handlebars out of an API so people can change the content of the handlebars. We also use these handlebars to change the text of meta-tags, because the texts are depending on the user of the platform. For example we want to say Robert Jackson's page with his 5 products. The handlebars in the API will return something like {{user.name}}'s page with his {{products.length}} products (simplified for now).

How so solve this type of problem in Ember?

What I created now is a big helper function which worked in Ember.js 3.0.0 but does not anymore in Ember 3.1.3.

import { getOwner, setOwner } from '@ember/application';
import Component from '@ember/component';
import { inject as service } from '@ember/service';
import Helper from '@ember/component/helper';
import Ember from 'ember';
const { HTMLBars: { compile } } = Ember;

// Here we store the keys with the corresponding content-element output
const stored = {};

// In Ember you can only render templates in a real component, so we do that here
export default Helper.extend({
  store: service(),

  createDomElement(key, format, template, properties) {
    // The following logic create a real DOM element
    const owner = getOwner(this);
    const component = Component.create({
      classNames: 'hide',
      layout: compile(template),
      renderer: owner.lookup('renderer:-dom')
    });
    setOwner(component, owner);
    component.setProperties(properties);

    // We wait for the component to render and than grab the innerHTML from it
    component.on('didRender', () => {

      // We add the result in the global `stored` object
      const html = component.element.innerHTML;
      stored[key] = html.replace(/\s\s+/g, ' ');
      component.destroy();

      // Ember helpers don't support Promises, so we recompute the helper which
      // will detect the element in the global `stored` object and returns that one.
      this.recompute();
    });

    // Here we append it to the body
    component.append();
  },

  // The compute function is the function Ember runs automatically
  compute(params, hash) {
    const key = hash.key;
    const format = hash.format;
    const offer = hash.offer;

    if (!offer) return;

    // We check if the key is already stored
    const storedKey = stored[key];
    if (storedKey) {
      stored[key] = null
      return storedKey;
    }

    // Here we get our template (content-element) with a certain key
    const template = this.store.peekAll('content-element').filterBy('key', key).get('firstObject.value');
    if (!template) return;

    this.createDomElement(key, format, template, {
      offer,
      product: offer.get('product'),
      project: offer.get('project')
    });
  }
});

We want to use this as a attribute of a link:

<a class="button" href={{social-url format=facebookUrl key='share_message.facebook' offer=offer}} {{action 'sendEvent' preventDefault=false}}>{{t 'share_facebook.open'}}</a>

And we want to use this in the body of our page:

{{{social-url
        key='meta.title'
        project=offer.product.project
        product=offer.product
        offer=offer}}}

And in our meta tags:

<meta name="twitter:description" content={{social-url
  key='meta.description'
  project=model.project
  product=model.offer.product
  offer=model.offer}}>

There error I get when running our current code in Ember.js 3.1.3:

Uncaught TypeError: Cannot read property 'fullName' of undefined
    at new RootComponentDefinition (vendor.js:44666)
    at InteractiveRenderer.appendTo (vendor.js:44883)
    at Class.exports.default._emberMetal.Mixin.create._Mixin$create.appendTo (vendor.js:70569)
    at Class.exports.default._emberMetal.Mixin.create._Mixin$create.append (vendor.js:70573)
    at Class.createDomElement (frontend.js:3976)
    at Class.compute (frontend.js:4023)
    at ClassBasedHelperReference.compute (vendor.js:40727)
    at ClassBasedHelperReference.value (vendor.js:40382)
    at Object.evaluate (vendor.js:29592)
    at AppendOpcodes.evaluate (vendor.js:28822)
    
RootComponentDefinition @ vendor.js:44666
appendTo @ vendor.js:44883
exports.default._emberMetal.Mixin.create._Mixin$create.appendTo @ vendor.js:70569
exports.default._emberMetal.Mixin.create._Mixin$create.append @ vendor.js:70573
createDomElement @ frontend.js:3976
compute @ frontend.js:4023
compute @ vendor.js:40727
value @ vendor.js:40382
(anonymous) @ vendor.js:29592
...

Posts: 1

Participants: 1

Read full topic


Viewing all articles
Browse latest Browse all 4828

Trending Articles