Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ngNonBindable can't handle unescaped { characters #11859

Open
tiagoroldao opened this issue Sep 23, 2016 · 16 comments
Open

ngNonBindable can't handle unescaped { characters #11859

tiagoroldao opened this issue Sep 23, 2016 · 16 comments
Labels
area: compiler Issues related to `ngc`, Angular's template compiler area: core Issues related to the framework runtime compiler: parser core: basic template syntax freq2: medium P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent type: use-case
Milestone

Comments

@tiagoroldao
Copy link

tiagoroldao commented Sep 23, 2016

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior
<div>Test binding: {{2 + 2}}</div>
=> Test binding: 4
<div ngNonBindable>Test non binding: {{2 + 2}}</div>
=> Test binding: {{2 + 2}}
<div>Test non binding: {2 + 2}</div>
=> Template parse errors, the "(Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)" message.

This is a problem because precisely due to the fact that they are [ngNonBindable] marked elements, "{{ '{' }}" doesn't produce the expected result.

Expected behavior
As the escaping of { characters isn't possible inside [ngNonBindable] elements so it's the compiler's job to ignore them altogether, I believe.

<div>Test non binding: {2 + 2}</div>
=> Test binding: {2 + 2}

Reproduction of the problem
here => http://plnkr.co/edit/GSzwEUyXyY1qDabjpEL1?p=preview

  • Angular version: 2.0.0
@vicb vicb self-assigned this Sep 23, 2016
@vicb vicb added type: bug/fix area: core Issues related to the framework runtime labels Sep 23, 2016
@tiagoroldao
Copy link
Author

tiagoroldao commented Oct 8, 2016

A bit of brainstorming, after taking a look at lexer.ts:

  • the lexer doesn't keep state while reading, and as it currently stands, it needs to in order to skip attempting ICU tokenization (which seems to be at the root of this issue)
  • there are two ways about this:
    • keep tabs on tags open and closed, and a isInNgNonBindable flag being set after the corresponding closing tag to the opening one is parsed
    • NgNonBindable + NgNonBindableEnd tags, or <ng-non-bindable></ng-non-bindable> approaches would make life easier on the lexer, but harder on the user - and break current API, which seems a no-no

Anyway, I feel I have a good understanding of how to approach the issue (using the first approach, I'd say).

@vicb should I submit a PR or is your work on this too conflicting?

@vicb
Copy link
Contributor

vicb commented Oct 8, 2016

Please go ahead and submit a pr. Thanks

@zkorz
Copy link

zkorz commented Oct 11, 2016

What is the reason that single braces must be escaped? The project I am working on includes a lot of templates with LaTeX math expressions of this sort:

\frac{2x+3}{x^{-1}+5}

Which is very inconvenient to have to escape. I realize double braces are for binding, but single braces used to be okay in RC4 but since upgrading all of my (hundreds) of templates are broken.

@tiagoroldao
Copy link
Author

This is due to the parsing of ICU expansion forms - http://userguide.icu-project.org/formatparse/messages.

If you don't need i18n at all, I don't know whether or not there is a way to remove it altogether - @vicb will know much more about this than me (and a way of opting out might make sense?)

Regardless, your options now are to either escape the strings altogether, or the { characters individually. After the related PR is available, using those forms inside a NgNonBindable would work, but I can see that is less than ideal for your use case, still.

@vicb
Copy link
Contributor

vicb commented Oct 11, 2016

Sorry, there is currently no way to opt-out

@Blackbaud-PatrickOFriel

Any word on if this is on the docket/there's a different approach to solve this? I'm just trying to show a simple code example in one my template and it's freaking out.

@bersling
Copy link

For everyone interpreting the angular error message too literally (like me), it doesn't have to be escaped like this:

\frac{{'{'}}d{{'}'}}{{'{'}}dx{{'}'}}\sqrt{{'{'}}x{{'}'}}

You can also escape it like that:

{{' \\frac{d}{dx}\\sqrt{x}= '}}

Still not perfect, but managable.

@dhardtke
Copy link

Anything new on this? I am writing a KaTeX Component and it would be nice to be able to pass arbitrary TeX strings through to the Component.

@anjmao
Copy link

anjmao commented Nov 10, 2017

I'm writing webpack loader which can transform code snippets in html files and highlight them https://github.com/anjmao/ng-snippets-loader. I have a problem with javascript code snippets, because of { and ngNonBindable seems to not work correctly for me too.

@vicb vicb removed their assignment Dec 14, 2017
@ngbot ngbot bot added this to the Backlog milestone Jan 23, 2018
@valmormn
Copy link

Im facing this problem using MathJax

@wibimaster
Copy link

Same problem for syntax highlighter support...

@NRaf
Copy link

NRaf commented Mar 6, 2020

Ran into a similar issue.

The following code has been working fine for a while now (potentially since Angular v2):

<div ngNonBindable i18n>
      Placeholders (labels in {{ curly }} braces) will be replaced with values
      from the external system or sensor streaming into the Event Type.
</div>

However, since upgrading to ng9, it's now spitting out a very cryptic error message:

ERROR in TypeError: Cannot read property 'visitExpression' of undefined
at createLocalizedStringTaggedTemplate (/Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/translator/src/translator.js:522:66)
at ExpressionTranslatorVisitor.visitLocalizedString (/Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/translator/src/translator.js:215:17)
at LocalizedString.visitExpression (/Projects/myapp/node_modules/@angular/compiler/bundles/compiler.umd.js:1574:28)
at ExpressionTranslatorVisitor.visitWriteVarExpr (/Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/translator/src/translator.js:166:112)
at WriteVarExpr.visitExpression (/Projects/myapp/node_modules/@angular/compiler/bundles/compiler.umd.js:1427:28)
at ExpressionTranslatorVisitor.visitExpressionStmt (/Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/translator/src/translator.js:126:49)
at ExpressionStatement.visitStatement (/Projects/myapp/node_modules/@angular/compiler/bundles/compiler.umd.js:1971:28)
at /Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/translator/src/translator.js:141:83
at Array.map (<anonymous>)
  at ExpressionTranslatorVisitor.visitIfStmt (/Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/translator/src/translator.js:141:47)
  at IfStmt.visitStatement (/Projects/myapp/node_modules/@angular/compiler/bundles/compiler.umd.js:2084:28)
  at Object.translateStatement (/Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/translator/src/translator.js:100:26)
  at /Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/transform/src/transform.js:180:33
  at Array.map (<anonymous>)
    at transformIvySourceFile (/Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/transform/src/transform.js:179:49)
    at /Projects/myapp/node_modules/@angular/compiler-cli/src/ngtsc/transform/src/transform.js:30:24
    at transformSourceFileOrBundle (/Projects/myapp/node_modules/typescript/lib/typescript.js:72535:57)
    at transformation (/Projects/myapp/node_modules/typescript/lib/typescript.js:89317:24)
    at transformRoot (/Projects/myapp/node_modules/typescript/lib/typescript.js:89337:82)
    at Object.map (/Projects/myapp/node_modules/typescript/lib/typescript.js:543:29)
    at Object.transformNodes (/Projects/myapp/node_modules/typescript/lib/typescript.js:89324:30)
    at emitJsFileOrBundle (/Projects/myapp/node_modules/typescript/lib/typescript.js:89858:32)

Can resolve either by removing the curly braces or removing i18n.

@pkozlowski-opensource
Copy link
Member

pkozlowski-opensource commented May 29, 2020

I can totally see hoe this one is confusing as it is not clear what is the intent of ngNonBindable - should it just "switch off" bindings or ignore all Angular constructs (special chars in template, i18n etc.).

Fixing this one properly will require review of all Angular specific constructs in relation to ngNonBindable. But yes, embedding code snippets / JSON in templates is a valid use-case that we should consider.

@pkozlowski-opensource pkozlowski-opensource added area: compiler Issues related to `ngc`, Angular's template compiler type: confusing type: use-case and removed type: bug/fix type: confusing labels May 29, 2020
@ngbot ngbot bot modified the milestones: Backlog, needsTriage May 29, 2020
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Sep 22, 2020
@jelbourn jelbourn added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent and removed severity3: broken labels Oct 1, 2020
@asteidle70
Copy link

asteidle70 commented Dec 2, 2021

In Angular 13 a simple single { produces
NG5002: Invalid ICU message. Missing '}'
ngNonBindable still no effect. The trick with {{foo {}} over multiple lines no longer works either (back ticks in {{ }} but interpreted as code here).
So it seems {{'{'}} for opening curly braces is the only way to go.
Or any new on this?
6 years after this this has been reported presenting a block of code or JSON in templates is still awkward. I would understand if double curly braces {{ are difficult to have in a template but single ones?

@rramsey
Copy link

rramsey commented Jun 1, 2023

So still no progress on this in Angular 16? I have:

  <p class="code" ngNonBindable>
    {
      "test": "test"
    }
  </p>

and I get:

Invalid ICU message. Missing '}'.
error NG5002: Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.) 

As soon as I do a search for { and replace with {{ '{' }} it is fixed. Seems pretty reasonable that if you aren't binding to {{ then you shouldn't care about a single {.

@joeskeen
Copy link

joeskeen commented Oct 4, 2023

Same issue here. I'm hoping with the new template control flow work (#50719 etc) that this will get some eyes.

For now, my only workaround has been to define my code snippet in a separate file, and have it loaded at runtime, for example instead of this:

<pre><code>
function myFunction() {
  return 1 + 1;
}
</code></pre>

which causes the Invalid ICU message error, I instead have to do this:

<pre><code src="assets/myFunction.js"></code></pre>

and define a component/directive with selector code that has a @Input() src?: string; and in ngAfterViewInit() does an HTTP GET to load the text contents of that file and populate the element's innerText. Super not ideal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: compiler Issues related to `ngc`, Angular's template compiler area: core Issues related to the framework runtime compiler: parser core: basic template syntax freq2: medium P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent type: use-case
Projects
None yet
Development

Successfully merging a pull request may close this issue.