ember-remarkable
ember-remarkable copied to clipboard
Dynamic text not working on ember-cli 2.8
{{md-text
text = "{{link-to 'index' 'index'}}"
dynamic=true
}}
Works fine without the dynamic flag. No error in console or anything, just a blank page.
Error in console while trying to use dynamic=true
in ember-cli > 2.6:
_ember['default'].HTMLBars.compile is not a function
They for some reason removed .compile
from HTMLBars
. I tried looking for solution, but couldn't find any. I'll gladly provide a pull request if anyone can point me in the right direction.
Hello, I have found this useful answer on StackOverflow: https://stackoverflow.com/questions/37345098/dynamically-compile-a-htmlbars-template-at-runtime-in-ember-2-5 May be helpful; sure, at this point it will require more NPM dependencies, but I think it's worth the effort if it gives dynamic template compile from ember-remarkable.
By adding app.import('vendor/ember/ember-template-compiler.js');
on ember-cli-builld.js
it worked (taken from the link pasted above), so I think we should close this issue @johnotander
I'm having similar problems with ember 3.1 with
Error: Cannot call compile
without the template compiler loaded. Please load ember-template-compiler.js
prior to calling compile
. How?
ember-template-compiler.js now lives at ember-source/dist/ember-template-compiler.js but I don't know how to use it in my module.
@buzzware, I have followed the solution suggested by @vasilakisfil, and have also manually added the component to my app/components
folder slightly editing the original code.
updateTemplate() {
this.set('subLayout', null);
scheduleOnce('afterRender', this, function() {
try {
let layout = null;
if (this.get('dynamic'))
layout = Ember.HTMLBars.compile(this.get('parsedMarkdownUnsafe'), false);
else
layout = Ember.HTMLBars.compile(htmlSafe(this.get('parsedMarkdownUnsafe')), false);
this.set('subLayout', layout);
}
catch(error) {}
});
},
... or at least I believe I have edited it... I may have rolled it back to the original one somehow... but maybe this can guide you in the right direction.
Keep in mind to add app.import('vendor/ember/ember-template-compiler.js');
to ember-cli.js
too, though.
@danidr Thanks for the reply, but I haven't understood your point. I'm trying to get Ember.HTMLBars.compile to work in production for the dynamic feature of this component with Ember 3.1.
There must be another step after app.import to use Ember.HTMLBars.compile as you do.
The source is here https://github.com/emberjs/ember.js/blob/87f7ee8a8e76c1809ad32b59eb62fc5cd35daa58/packages/ember-template-compiler/lib/system/compile.js and it specifically says "This is not present in production builds." but how do we import/include it anyway? My knowledge of JS module systems is very poor.
I don’t understand why it wasn’t working before, but its working now.
Weirdly, it started working when I added @glimmer/compiler
as a dependency (not devDependency) in packages.json. But then I removed it, and rebuilt, and even did “rm -rf node_modules && rm-rf dist/* && npm install” and it still works.
So, the only required addition is
app.import('vendor/ember/ember-template-compiler.js');
to ember-cli-build.js
@danidr I'm now having an issue with the markdown rendering working when the first route is loaded, but when I navigate and then hit the back button, the md-text component doesn't rerender. The model is a POJO, not Ember.Object. {{model.title}}
updates fine, but {{md-text text=model.content html=true dynamic=true}}
doesn't.
Would your updateTemplate code fix this? Can you paste the whole component?
I wonder if its something to do with the convoluted way dynamic rendering is happening here eg. md-text.hbs : {{#if dynamic}} {{md-dummy layout=precompiledTemplate}} {{else}} {{parsedMarkdown}} {{/if}}
@buzzware Well, I have rewritten the component, but I honestly can't remember WHERE I edited it exactly...
I'll just post the whole code for you here below. Sorry for spamming, but all this code is in a private repository, therefore I can't link to it directly.
components/md-text.js
import Ember from 'ember';
import Component from '@ember/component';
import { computed, observer } from '@ember/object';
import { getOwner } from '@ember/application';
import { htmlSafe } from '@ember/string';
import { scheduleOnce } from '@ember/runloop';
import Remarkable from 'npm:remarkable';
export default Component.extend({
tagName: '',
text: '',
breaks: true,
typographer: true,
linkify: true,
linkTarget: '',
html: false,
extensions: true,
dynamic: true,
didInsertElement() {
scheduleOnce('afterRender', this, 'updateTemplate');
},
highlightJsExcluded: computed(function () {
let config;
if (getOwner) {
config = getOwner(this).resolveRegistration('config:environment');
} else {
let registry = this.container.registry || this.container._registry;
config = registry.resolve('config:environment');
}
let remarkableConfig = config.remarkable || {};
return remarkableConfig.excludeHighlightJs || false;
}),
highlight: computed('highlightJsExcluded', function() {
let highlightJsExcluded = this.get('highlightJsExcluded');
return (str, lang) => {
if (!highlightJsExcluded) {
if (lang === 'text' || lang === 'no-highlight') {
return '';
}
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (err) {}
}
try {
return hljs.highlightAuto(str).value;
} catch (err) {}
}
return '';
};
}),
parsedMarkdownUnsafe: computed('text', 'html', 'typographer', 'linkify', 'linkTarget', function () {
var md = new Remarkable({
breaks: this.get('breaks'),
typographer: this.get('typographer'),
linkify: this.get('linkify'),
linkTarget: this.get('linkTarget'),
html: this.get('html'),
highlight: this.get('highlight')
});
if (this.get('extensions')) {
md.core.ruler.enable([
'abbr'
]);
md.block.ruler.enable([
'footnote',
'deflist'
]);
md.inline.ruler.enable([
'footnote_inline',
'ins',
'mark',
'sub',
'sup'
]);
}
md.core.ruler.disable([ 'smartquotes' ]);
let plugins = this.get('plugins');
if (plugins) {
plugins.forEach((plugin) => md.use(plugin));
}
return md.render(this.get('text'));
}),
updateTemplate() {
this.set('subLayout', null);
scheduleOnce('afterRender', this, function() {
try {
let layout = null;
if (this.get('dynamic'))
layout = Ember.HTMLBars.compile(this.get('parsedMarkdownUnsafe'), false);
else
layout = Ember.HTMLBars.compile(htmlSafe(this.get('parsedMarkdownUnsafe')), false);
this.set('subLayout', layout);
}
catch(error) {}
});
},
observerSource: observer('text', function() { this.updateTemplate(); }),
}).reopenClass({
positionalParams: ['text']
});
components/md-text-renderer.js
import Component from '@ember/component';
export default Component.extend({
tagName: ''
});
templates/components/md-text.js
{{#if subLayout}}
{{md-text-renderer layout=subLayout}}
{{/if}}
NOTES:
- I only use dynamic text, therefore I haven't tested this component with dynamic text disabled.
- Usage is slightly different; it's enough to say
{{md-text string}}
instead of{{md-text text=string}}
Let me know if it helps somehow.
Big thanks @danidr ! Thats working. This dynamic rendering is very cool. I'm using it with https://github.com/buzzware/broccoli-static-site-json#remove-showdown to achieve something a bit like https://www.gatsbyjs.org ie dynamically loaded markdown with ember components
@buzzware Glad to hear it worked! I'll have a look at your code.