Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

[$parse:syntax] Syntax Error: Token ':' is an unexpected token (ngForm) #13771

Closed
marcorinck opened this issue Jan 14, 2016 · 20 comments
Closed

Comments

@marcorinck
Copy link

I have an issue updating angular.js from 1.3.20 to 1.4.8 for an internal project which I can't reproduce on a simple jsfiddle. The error is happening since 1.4.4, its working without any problem til 1.4.3

The project is using JSF (java framework) which is automatically generating IDs and name attributes with a colon in it, something like this:

<form id="permanentFilter:closeFilterForm" name="permanentFilter:closeFilterForm" method="post" action="/liste/uebersicht.jsf?windowId=072" class="navbar-form navbar-right" enctype="application/x-www-form-urlencoded">
</form>

When bootstrapping this without any manual directives or controllers angularjs 1.4.8 is throwing an error:

Error: [$parse:syntax] Syntax Error: Token ':' is an unexpected token at column 16 of the expression [permanentFilter:closeFilterForm] starting at [:closeFilterForm].
http://errors.angularjs.org/1.4.8/$parse/syntax?p0=%3A&p1=is%20an%20unexpec…d%20token&p2=16&p3=permanentFilter%3AcloseFilterForm&p4=%3AcloseFilterForm
    at http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:68:12
    at Object.AST.throwError (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:13100:11)
    at Object.AST.ast (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:12870:12)
    at Object.ASTCompiler.compile (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:13319:31)
    at Parser.parse (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:14189:29)
    at $parse (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:14291:39)
    at getSetter (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:20608:14)
    at ngFormPreLink (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:20579:37)
    at invokeLinkFn (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:8841:9)
    at nodeLinkFn (http://127.0.0.1:8080/resources/javascript/external-libs/angular.js:8314:11)

Its throwing the error for every form which has a colon, its working with every form which has an ID/name without a colon.
Since angularjs 1.4.4 ngForm directive is automatically creating expressions from name attributes which is causing this problem as the colon is confusing the parser. (function getSetter(expression) on line 20442 in unmodified angularjs 1.4.4)

Is there any solution to that on the angularjs side?

@Narretz
Copy link
Contributor

Narretz commented Jan 14, 2016

Oh, Java you so silly.
I think the name setting logic should check if the attribute contains an interpolation, instead of creating an assignable expression in any case.

@Narretz Narretz added this to the 1.5.x - migration-facilitation milestone Jan 14, 2016
@Narretz
Copy link
Contributor

Narretz commented Jan 14, 2016

Ok, so that's not the cause after all. I think we need expert guidance here. @lgalfaso do you have an idea how to solve this? We could re-introduce the old setter helper, but maybe there's a better way.

@marcorinck
Copy link
Author

what do you mean? That the colon is not the problem?

I'll take another look into it then tomorrow to find out what it could be then instead.

The error definitely happens only on some forms and not for every form.

@Narretz
Copy link
Contributor

Narretz commented Jan 14, 2016

The colon is definitely the problem. I was just wrong about how to fix it.
Am 14.01.2016 20:18 schrieb "Marco Rinck" [email protected]:

what do you mean? That the colon is not the problem?

I'll take another look into it then tomorrow to find out what it could be
then instead.

The error definitely happens only on some forms and not for every form.


Reply to this email directly or view it on GitHub
#13771 (comment)
.

@marcorinck
Copy link
Author

ok thanks.

And yeah, java is silly. :) Admittedly, you can change the separator char to something other, but its so rarely done that a lot of code just assumes the colon. So yeah, it would be quite hard to do that.

@lgalfaso
Copy link
Contributor

Hi, I am not able to find an easy way. form:name is an expression so it expects for permanentFilter:closeFilterForm to be an expression. The only way I can think of that would work around this issue is for you to create a directive on the element form with a higher priority than the built-in form directive, and there, during compile, set the name attribute to the empty string (or remove it completely)

@Narretz
Copy link
Contributor

Narretz commented Jan 15, 2016

The thing is that it worked before, no? Before we allowed interpolated form names, this kind of name was allowed. It was just using a different kind of setter: https://github.com/angular/angular.js/blob/v1.3.x/src/ng/parse.js#L838
So I think we could go back to this setter, if there's no other fix possible.

@lgalfaso
Copy link
Contributor

@Narretz the previous behavior was very very strange. Eg, for <form name="abc().def['ghi']"> would be as assigned to the expression this["abc()"]["def['ghi']"]. The new behavior works the way people expect it to work.

@marcorinck
Copy link
Author

@lgalfaso Your suggestion per se would not be possible as the server framework is rebuilding server state out of the id/name so elements need to have persistent id and name attributes.

But I have now a (somewhat) ugly solution with 2 directives: one with a high priority which changes the name attribute for the ngForm directive. And another directive with low priority during link time which changes it back to the original name.

It works for me, but its not ideal.

@Narretz
Copy link
Contributor

Narretz commented Jan 15, 2016

Looks like we have to live with this then, and add a BC notice to the changelog.

@lgalfaso
Copy link
Contributor

@marcorinck if you are not using the angular form directive, you can also disable the directive using a decorator. Another alternative would be to change the priority order for the controller name to
1/ ngForm
2/ name
3/ (the empty string)

This would be, to change 1 and 2

@petebacondarwin
Copy link
Contributor

@lgalfaso so you suggestion would mean that @marcorinck would need to add a ngForm attribute to the <form> element to prevent Angular from trying to use the name attribute, right?

@petebacondarwin
Copy link
Contributor

Here is an alternate workaround which modifies the name attribute before it gets to the form directive.

http://plnkr.co/edit/VuHgBr5EQHTLJrk0HEVC?p=preview

You could make this more clever by checking for some other attribute on the element that the server might attach...

@lgalfaso
Copy link
Contributor

@petebacondarwin if you are going to change $attr.name without using the setter, then you can just change it to be the empty string. That would disable the name property on form without changing the attribute itself.

@petebacondarwin
Copy link
Contributor

Here is a more robust example: http://plnkr.co/edit/414QyUt32eZ129kJeJik?p=preview

@Narretz
Copy link
Contributor

Narretz commented Feb 29, 2016

With these workarounds, and the difficulty in restoring the previous behavior, should I add this to the CL / migration guide and close this afterwards?

@petebacondarwin
Copy link
Contributor

I think so. It was really a bug in the old parser.

@Narretz Narretz self-assigned this Feb 29, 2016
Narretz added a commit to Narretz/angular.js that referenced this issue Feb 29, 2016
@Narretz
Copy link
Contributor

Narretz commented Feb 29, 2016

@petebacondarwin If you actually need the original form name, for example for server-side form submission, you still need to change the form name back to what it was, for example in a postLink fn.

Narretz added a commit to Narretz/angular.js that referenced this issue Feb 29, 2016
@petebacondarwin
Copy link
Contributor

Good point
On 29 Feb 2016 22:28, "Martin Staffa" [email protected] wrote:

@petebacondarwin https://github.com/petebacondarwin If you actually
need the original form name, for example for server-side form submission,
you still need to change the form name back to what it was, for example in
a postLink fn.


Reply to this email directly or view it on GitHub
#13771 (comment)
.

@JoernBerkefeld
Copy link

JoernBerkefeld commented Jun 28, 2017

hi, i ran into the same problem with Salesforce on the back end side. In my case I did not want Angular to mess with the form that Visualforce created at all. My solution was therefore to tell Angular to ignore the form in question all together:

<span ng-non-bindable="ng-non-bindable"><apex:form id="myform"></apex:form></span>

Notes:

  • usually it's enough to write the attribute like <span ng-non-bindable> but Salesforce requires a full attribute definition...
  • <apex:form> is a short handle that creates a standard form tag that starts like <form id="theSalesWorkspace:theFrm" name="theSalesWorkspace:theFrm">

Source:
https://docs.angularjs.org/api/ng/directive/ngNonBindable (see Examples section)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants