I have the following Java variables:
context.setVariable("content", "test <b>test</b>");
context.setVariable("condition", condition);
and I want to place this into the following template:
<p th:text="${condition}?${content}:''"></p>
The expected result is: "test test" if the condition is true. However,
the result is
"test <b>test</b>"
if I open my page and the condition is true. Changing th:text=... to th:utext=... results in
"test <b>test</b>"
displayed on my page, which is still not what I want.
Is there a way to do this?
If you want the actual HTML, then you need to pass actual (not escaped) HTML and use th:utext. (It doesn't make sense to pass in escaped HTML and think Thymeleaf will unescape it for you.)
// Controller
context.setVariable("content", "test <br>test</br>");
<!-- HTML -->
<p th:utext="${condition}?${content}:''"></p>
If you really do want to pass in "test <br>test</br>", then you're going to have to use string search/replace to change those characters back into < and > (probably using the #strings utility object).
Related
I'm new to angular, and I would like to know if there's is a way to send a string to the Html file with a variable inside?
test.ts
test: string = "Display this {{testText}}";
testText: string = "Success";
test.html
<p>{{test}}</p>
What I want to achieve is that it displays this: Display this Success.
I'm just curious if this is possible, perhaps I can retrieve from an API chunks of HTML string and display them like that.
**
It is basic Javascript string operation. For this, there is nothing special with Angular at your TypeScript file.
Without handling updates on test
On Typescript file you have two options to merge strings:
First Way:
testText: string = "Success";
test: string = `Display this ${this.testText}`;
Second Way:
testText: string = "Success";
test: string = "Display this " + this.testText;
Of course you can see a problem with both of them. What will happen when you update your test? Based on these ways, the testText just initializing when the component instance is created, so if you want to fetch changes on your test variable you should use the way from one of following
**
First Way:
test.html
<p>Display is {{testText}}</p>
<p>{{'Display is ' + testText}}
Socond Way:
Specifically you can create a custom Pipe. You should check documentation about how are them work. For only this case you don't need to use this way. Pipes are generally for more generic or more complex operations.
Third way:
(more bad than others. Because change detector of Angular will not understand when your content should update the paragraph. You should use others.)
test.ts
getTestText() { return 'Display is ' + this.testText }
test.html
<p>{{ getTestText() }}</p>
**
Binding Dynamic Html Content
For binding any dynamic HTML template you need to use innerHTML attribute like
<div [innerHTML]="htmlVariable"></div>
but this is not a trusted way because there is nothing to check is the html is trusted or is it valid etc. Or if the html contains the selector of any component, it won 't render as expected. You should use more complex ways to do it.
<div data-collapse class="left-justify" id="requirements">
#Html.Raw(string.Format(#_stringLocalizer["RegisterNoticeMessage"], #Html.ActionLink(#_stringLocalizer["RegisterLinkDisplayName"], "Register")))
</div>
In this piece of code, #Html.ActionLink() is returning Microsoft.AspNetCore.Mvc.Rendering.TagBuilder instead of returning anchor element containing URL path to the specified action.
What is the right way to use #Html.ActionLink() in string.Format(). Or, do I missing anything, here?
The helper method Html.ActionLink always returns a TagBuilder object. When you pass such an object into a string parameter, the ToString() method will be called, resulting in your observed output (the class name: "Microsoft.AspNetCore.Mvc.Rendering.TagBuilder").
It seems to me you are trying to create a hyperlink in a rather weird way. Have you tried using the Url.Action helper method? This method returns a plain old string, ready to plug into any href attribute.
E.g. this code would be equivalent of what you're trying to achieve:
#Html.Raw(
string.Format(_stringLocalizer["RegisterNoticeMessage"],
"" + _stringLocalizer["RegisterLinkDisplayName"] + "")
)
Sidenotes:
It is possible get the string value of a TagBuilder, as illustrated in this post.
No need to repeat # when you're already working in Razor/C# context.
Be extremely careful when using Html.Raw as it might result in XSS vulnerabilities.
I'm using handlebars and assemble with yeoman and gulp.
I want to have some globalized partials that are able to be nested or injected into another partial by calling it within the context of a data object.
A simple example of that would be having a list of links that I could reference inside content throughout the site. The reason behind this, is the need for consistency. If for example, if I have a link within text on a page that I reference a 15 times throughout an entire website, but then realize I need to add a trade mark or modify the text, I want to update it once, not 15 times.
This is an example of what I want to do. Define global data inside a json file:
links.json
{
"apple": {
"linktext": "apple",
"target": "_blank",
"href": "http://www.apple.com"
},
"blog-article-foo-bar": {
"linktext": "foo bar",
"href": "http://www.foobar.com"
},
"dell": {
"linktext": "dell",
"target": "_parent",
"href": "http://www.dell.com"
}
}
Generate a partial from that content using a simple or complex template:
links.hbs
<a href="{{href}}" {{#if target}}target="{{target}}"{{/target}}>{{linktext}}</a>
And be able to embed that partial into another one by referencing it some how. This didn't work, but I've been reading about custom helpers, but can't figure out how I would intercept the partial and bind it into the other partial.
text.json
{
"text": "If you need a computer, go to {{> link link.apple}}."
}
text.hbs
<p>
{{text}}
</p>
compiled.html
<p>
If you need a computer, go to apple.
</p>
If you have suggestions or examples that might help me understand how to achieve this, I'd really appreciate the support. Thanks in advance.
There is some information about Handlebars helpers in their docs but not that much.
Since you're trying to use handlebars syntax in the value of a property on the context (e.g. text), handlebars won't render the value since it's already rendering the template. You can create your own helper that can render the value like this:
Handlebars.registerHelper('render', function(template, options) {
// first compile the template
const fn = Handlebars.compile(template);
// render the compiled template passing the current context (this) to
// ensure the same context is use
const str = fn(this);
// SafeString is used to allow HTML to be returned without escaping it
return new Handlebars.SafeString(str);
});
Then you would use the helper in your templates like this:
{{render text}}
Thanks for the example #doowb, your code did work but not for what I was trying to do. I really wanted something more complicated but I simplified my question not knowing it would be an issue. The code you provided worked (I think after a slight tweak) for a simple render of a template, but my templates use helpers such as #each and #if which caused the issue. Where the helpers were in my template, I ended up getting async placeholders. For example: <a $ASYNC$1$3...> I later learned this has to do with how partials are rendered. Understanding that lead me to subexpressions and the below solution.
Keeping my example above with some modifications, this is how I was able to merge partials.
First, I simplified the placeholder in text.json to basically a unique ID, instead of trying to render the partial there.
On the hbs template that I'm rendering to, such as a page or whatever, I included the insert helper with 3 arguments. The first two are subexpressions, each return a flattened partials as strings. The key here is that subexpressions process and return a result before finishing the current process with the helper. So two flattened templates are then sent to the helper along with the placeholder to search for.
The helper uses the third argument in a regex pattern. It searches the second argument (flattened parent template) for this pattern. When found, it replaces each instance of the pattern with the first argument (yes its a global fine replace).
So, the flattened child string gets inserted into parent each time placeholder is found.
First argument
(partial "link" link.apple)
Returns
'apple'
Second argument
(partial "text" text.text-example)
Returns
'<p class="text font--variant">If you need a computer, go to {{linkToApple}}.</p>'
Third argument
'linkToApple'
text.json
{
"text-example": {
"elm": "quote",
"classes": [
"text",
"font--variant"
],
"text": "If you need a computer, go to {{linkToApple}}."
}
}
text.hbs
<{{elm}} class="{{#eachIndex classes}}{{#isnt index 0}} {{/isnt}}{{item}}{{/eachIndex}}">{{text}}</{{elm}}>
compile.hbs
{{insert (partial "link" link.apple) (partial "text" text) 'linkToApple' }}
compile.html
<p class="text font--variant">If you need a computer, go to apple.</p>
gulpfile.js
app.helper('insert', function(child, parent, name) {
const merged = parent.replace(new RegExp('\{\{(?:\\s+)?(' + name + ')(?:\\s+)?\}\}', 'g'), child);
const html = new handlebars.SafeString(merged);
return html;
});
Hope this helps someone else. I know this can use improvements, I'll try to update it when I get back to cleaning up my gulp file.
I have a generic template in play 2.6, that I want to pass in a variable amount of HtmlContents. I've defined the template like this (including the implicit parameter I have in case that changes anything):
#(foo: String)(content: Html*)(implicit bar: Bar)
On the template side, this works fine-- I can dissect content with for and render it as I want. However, I haven't been able to figure out a clean way to invoke the variable arguments from the underlying template.
e.g, I have a view named "Baz":
#(something: String)(implicit bar: Bar)
In it, I try to invoke the template with multiple Html arguments. I've tried the following:
#template("fooString"){{123},{abc}}
and
#template("fooString")({123}, {abc})
and
#template("fooString"){{123}, {abc}})
And various other permutations, but inside of an enclosing bracket it seems to interpret everything literally as a single parameter in the HtmlContent vararg.
However, this ended up working as I intended, passing in multiple HtmlContents:
#template("fooString")(Html("123"), Html("abc"))
So that works, and I can use a triple-quoted interpolated string for a large Html block-- but it seems like there should be a cleaner way to do this, and the string interpolation is dangerous as it doesn't do html escaping.
Is there a way to do this using the { enclosed syntax? I'd like to understand more what is actually happening on an underlying level, and how play parses and generates HtmlContent in brackets.
So consider you have below template
// main.scala.html
#(title: String)(contents: Html*)
There are different ways you can call this template
Option #1
This is what you already posted in the question
#main("This is a title")(Html("abc"), Html("123"))
Options #2
#html1 = {
Hello
}
#html2 = {
<div>Tarun</div>
}
#main("This is a title")(html1, html2)
Option #3
#main("This is a title")(Html(<div>Tarun
</div>.toString), Html(<div>
Lalwani
</div>.toString))
Options #4
This is not exactly same option, but needs change in Template signature itself
#(title: String)(contents: List[String])
And then calling it like below
#main("This is a title")(List(
"""<div>
Tarun
</div>
""", """Hello"""))
Option #5
This requires code files and was already answered on another SO thread
Paul Draper's answer on Why doesn't this pass multiple HTML parameters to template
I wish to insert into message a line like "view.mail.warning". It contains a html code, but using encodeAs="html", the message shows a href ... too and does not show a link. What is the correct way for do these things?. I don't want to insert the message in parts :(.
In a gsp:
<"p style='color:#ddd; font-size:12px; text-align:center;'> <"g:message code="view.mail.warning" encodeAs="html>
In message.properties:
<"view.mail.warning= textPart1 <"a href=['http://page.com']> <"g:message code="view.pageName"/> textPart2 <"a href='mailto:support#page.com'">'support#page.com' textPart3
The correct way /is/ to insert it in parts. However, if you /must/ include html in your properties file you can. What you can not include there however, is GSP/taglibs. Your call to g:message will never be parsed/executed. Messages from the resources are just strings. The following are perfectly valid:
messages.proprties
view.mail.warning=<p>I {0} do html in here!</p><em>But I {1} shouldn't.</em>
GSP
<g:message code="view.mail.warning" args="['can', 'really']" />
Output
<p>I can do html in here!</p><em>But I really shouldn't.</em>
A few things to note about this. As you can see you can pass arguments to your message codes. They are ordinal, and start a zero. This way you can tokenize your message and even pass values from your GSP to your messages.
This is the correct way to use message resource bundles in Grails.
For example:
message.properties
view.mail.warning= >p>I can do html in here!>/p> >p>But I really shouldn't.>/p>
GSP
Output
I can do html in here!>/p> >p>But I really shouldn't.
i want insert into message properties, message with strings+html