Call component dynamically via string in Ember.js - javascript

I want to invoke a component via string. The reason is that I have on my DB a text and within that text I have some keys that I want to invoke a component in case they are listed in my app.
I know there is a {{component}} helper to invoke components dynamically and I was wonder if could make use here somehow. The example I will post is trivial, but the idea is use more complex components like ember-light-table, for example.
Example:
// my-route.hbs
{{my-special-component text=complexString}}
// my-route.js
// the content of the string is never the same, which means the dynamic helpers won't be the same, nor will be at the same place.
let complexString = "This is my complex string {{my-simple-helper text="this will be bold"}}. Etc, etc...";
// my-special-component.hbs
{{formatted}}
// my-special-component.js
formatted: computed('text', function() {
// ??
})
The output would be:
This is my complex string <b>this will be bold</b>. Etc, etc...
I've tried using triple brackets but that is only for < tags >.

What if you just made a component that takes a block?
{{my-special-component}}
This is my complex string {{my-simple-helper text="this will be bold"}}. Etc, etc...
{{/my-special-component}}
and the template for that would look like:
To show above your complex string
{{yield}}
to show below your complex string

Related

Javascript custom template engine

I'm trying to create a custom template engine in javascript but I'm having trouble getting started as I cannot extract tokens using regex.
Here are the requirements:
Variables are defined like this: $(variable)
Functions: $(name arg1 "this is arg2 but it contains whitespaces.")
Function arguments can contain other variables $(name $(variable) arg2)
Both variables and functions will be rendered async. For example: Get the value for $(variable) from db then replace it.
This is not for rendering an html page but to simply replace a string entered by a user on the backend.
Edit
More information:
Suppose a user enters the following string:
$(id $(lowercase John))
On the backend application must do:
Convert "John" to lowercase.
Get the id for "john" from db.
This is only a simple example to demonstrate how this should work.
Are there any libraries that can help me achieve this? If not, any idea how to implement this?
EDIT 2:
I tried using Mustache and I changed the delimiters to $(), however the function (section) tags do no satisfy the requirements. In Mustache, for functions I must do this: $(#name) $(variable) "this is arg2 but it contains whitespaces."$(/name) also it does not support async rendering.
If not, any idea how to implement this?
You should use an Abstract Syntax Tree, and write a compatible parser. While regex (as Pedro Lima stated) is good for simple templating, if you ever want to extend the parser, you'll need something a bit more robust.
As an example of an Abstract Syntax Tree parser, $(test1 $(test2) test3) lorem ipsum $(test4) would be turned into the following:
(Thanks to Mile Shang's Syntree for the tree generator.)
As for specifically how to write a parser, I think you can figure it out. Just iterate over the string and check for the template delimiter. Reading the source code for a templating library like Handlebars might help.
Here. This regex will identify the templates that can be replaced. Note that it only selects the innermost templates in nested templates.
/\$\((?<FirstTerm>\S+?)(?<OtherTerms>(?:\s+(?:\w+|".*?"))+)?\)/g
So just use a regex replace function with your templating logic recursively until there are no more matches. The inner templates will be replaced and you'll be left with the string with templates replaced.
Other answers on this post are correct, however, I want to share exactly how I managed to implement this:
Create a recursive match function. I used Steven Leviathan's article to implement this.
Create a render function and inside the function call the recursive match function to find and replace variable/function names with appropriate values.
Keep calling the render function recursively until all arguments inside a function have been replaced.

Using a string as input with reactDOM.render, marked.js and babel

So I am attempting to build a git markdown previewer using React, babel and marked.js. Marked.js is a markdown parser.
So say I have a value that I want to use from my html.
<div id="markdownInput"># This is my input</div>
In javascript, I store it as the variable myInput.
var myInput = document.getElementById("markdownInput").value;
myInput is now "# This is my input" and is a string. Marked.js uses a function called "marked()" that takes a string as input and converts the git markdown to html.
var myOutput = marked(myInput);
myOutput is now equal to:
"<h1>This is my input</h1>"
Notice that the markdown is converted (# =>h1) but it is also stored as a string. If I attempt to use this with reactDOM.render like so:
ReactDOM.render(myOutput, document.getElementById("output-container"));
My "output-container" in my HTML ends up with displaying:
<h1>This is my input</h1>
rather than displaying "This is my input" in large header letters. What it boils down to is that React.DOM.render() needs an object as input and not a string. It needs:
<h1>This is my input</h1>
As an object but I am inputting it as a string because the marked() function only outputs as a string (which wraps everything in quotes).
Is there anything that I can do to convert myOutput to an object? I am extremely knew to React so perhaps I haven't learned a better method for something like this.
Thanks
Well, found this Using marked in react and used the "dangerouslySetInnerHTML" attribute. Is there perhaps a better way to do this though?

UTF-8 symbol is converted when inserted to dom

I have a following problem, i am building app that uses data stream from ajax calls, the data that is coming is therefore escaped inside json string.
example: 1°Set
When i insert that data to DOM it is being converted like this: 1°Set
I dont use any libraries like jQuery, pure Javascript.
I tried to store converted name also in another place but i cannot seem to convert it manually, i tried following functions:
var test = function(str) {
console.log(unescape(encodeURIComponent(str)) );
console.log(decodeURIComponent(escape(str)) );
};
test('1°Set');
It stays the same, does anyone have an idea how to convert it to a DOM like version?
I have a following problem, i am building app that uses data stream from ajax calls, the data that is coming is therefore escaped inside json string.
example: 1°Set
Sounds like you're having a problem because your backend serves a JSON that looks like:
{
"something": "1°Set"
}
Instead of a string "1°Set", you're serving HTML source code that amounts to "1°Set". This looks very unnecessary. I cannot see a good reason of using HTML escaping inside JSON, unless you actually want your JSON to actually contain a part of HTML source (with formatting and everything), rather than just a string.
My suggestion: Let's keep it simple and instead serve something like:
{
"something": "1°Set"
}
or equivalently escape it properly using JSON syntax:
{
"something": "1\u00b0Set"
}
Now you'll JavaScript will receive a plain string that can be easily displayed, for example inside element.textContent or element.value or anywhere else. You won't even need any conversions.

Is there some way that I can pass the return value of one helper function into another as a parameter in Handlebars

I have run into a problem with a current project using Handlebars.js. I am writing a complex template which must be output only as text (it is fed directly as a string to a text printer) and that text can be a maximum of 40 chars wide.
The problem I have is that I need to use various helper functions to get and organise my data, but I then need to take that text and put it though another function to format it into the 40 char width.
So... I have helper functions that look a bit like this:
Handlebars.registerHelper('getLit' , function (litName) {
// some logic to retrieve a string lit in correct language
});
Handlebars.registerHelper('getArrayValue', function(array, key) {
return array[key];
});
Handlebars.registerHelper('textFormat', function(string, max_width, align) {
// logic to format the text
});
Now if my htm looks like this:
{{textFormat "This is a really long string that needs formating into the correcct length blah blah blah blah" 40 'left'}}
I have no problems.
However I need to be able to use helper function to build the string e.g.
{{textFormat {{getArrayValue address 0}} 40 'right'}}
I hope my explanation is not too convoluted, obviously the data I am dealing with is very large and very complex so simply preparing all the data to feed into the template (e.g. instead of using getLit making 6 forms of each string in their various languages) is just not practical.
Is there anyway to make this work or do I need to use a totally different approach?
You cannot use nested helpers. If you need include new helper, use construct
{{#textformat 10 'right'}}
{{getArrayValue address 0}}
{{/textformat}}
You can find out more about constructing block helpers here: http://handlebarsjs.com/block_helpers.html

Regex replacement with prompting/callback UI

I'm trying to write a function that takes a long string of text, identifies place holders within the text, and prompts the user to supply a value that should take the place of the placeholder. The markup for the placeholders looks similar to markdown used for images or links:
some text, some more text, ?[name][description] more text, not just commas
Where name and description are arbitrary runs of text. When I've found these placeholders, I want to pop up a nicely formatted dialog, using the names and descriptions, and have the user supply a replacement value.
I already have a nice function (called htmlPrompt) available where you hand it a piece of HTML (for the main part of the prompt), has a text box, and then calls a callback function you've supplied with the result (or null if Cancel is pressed), with the following signature:
function (htmlText, inputStartValue, callback)
Before plugging in this function, I wrote the rough and ready:
myText = myText.replace(/(\?\[(.+)\][ ]?(?:\n[ ]*)?\[(.+)\])/g,
function (wholematch, m1, m2, m3) {
var repValue = prompt(m2);
if (repValue == null)
{
return m1;
}
return repValue;
});
Which uses the DOM built-in prompt method - which doesn't really do an adequate job for me, when it comes to formatting.
However, I can't think of a way of plugging in htmlPrompt - it only simulates a modal dialog and provides the final result by calling callback.
I did think of trying to manually do the replacements, using the results from match rather than replace - but so far as I can see, the values returned by match are just strings - they don't give you anything useful (such as the location of the match within the overall text).
Or do you think I'm going about this completely wrong? The overall flow I want is:
Find each placeholder in the text
Prompt the user for a replacement, using both the name and description values
Replace the placeholder expressions in the text with the user supplied value.
For each of the name and description tupples:
First use match to read name and desription.
Prompt user.
Then use replace to replace those.

Categories

Resources