fix($compile): do not initialize optional '&' binding if attribute not specified #9216

Closed
wants to merge 1 commit into
from

Projects

None yet
@caitp
Contributor
caitp commented Sep 22, 2014

Also, do not set up an expression in scope if the '&' binding is optional.

BREAKING CHANGE:

Previously, '&' expressions would always set up a function in the isolate
scope. Now, if the binding is marked as optional and the attribute is not
specified, no function will be added to the isolate scope.

Finally, if the '&' expression is not optional, and the attribute is not
specified, then rather than the function being essentially a NOOP, it will
instead throw an error indicating to the programmer that a required attribute
was not specified.

Closes #6404

@caitp caitp added this to the 1.3.0 milestone Sep 22, 2014
@caitp
Contributor
caitp commented Sep 22, 2014

So, the error content isn't very good, I'm not sure what else to add to it really.

I feel like this will surprise people, which isn't very nice :( Also it's another breaking change, so we probably can't really get this into 1.3.

However it has been asked for, and it probably is the expected behaviour.

/cc @IgorMinar can you take a look and decide if we want to do this or not?

@mary-poppins mary-poppins added cla: yes and removed cla: no labels Sep 22, 2014
@gkalpak gkalpak commented on an outdated diff Sep 22, 2014
docs/content/error/$compile/reqattr.ngdoc
@@ -0,0 +1,9 @@
+@ngdoc error
+@name $compile:reqattr
+@fullName Required Attribute Not Present
+@description
+
+If a directive requires an attribute to be present, by specifying a non-optional isolate scope binding for that attribute, and the attribute
+not present, this error is thrown.
@gkalpak
gkalpak Sep 22, 2014 Member

is not present

@lgalfaso
Member

I think this can cause more than one WTF moment... that said, what the patch does is closer to what it is expected... Can this be made an opt-in?

@caitp
Contributor
caitp commented Sep 22, 2014

we probably have to make it opt-in, otherwise it's a breaking change :( will see if we even want to do this though

@caitp
Contributor
caitp commented Sep 22, 2014

The problem with opt-in is, nobody will ever opt into it. The problem with not opt-in is, it breaks apps. It's an endless struggle .v.

@IgorMinar
Member

it's too late for this change to get into 1.3.

making this an opt-in is not a great option because as soon as you come across a third-party component that doesn't specify some required attributes in its template you have to opt-out.

I do agree that it's a good change though.

@IgorMinar IgorMinar modified the milestone: Backlog, 1.3.0 Oct 2, 2014
@petebacondarwin petebacondarwin modified the milestone: Backlog, 1.4.x Dec 15, 2014
@e-oz
e-oz commented Dec 15, 2014

It will break a lot of existing directives... What is profit of that change? If attribute is not marked as optional but in code of directive it is optional (sometimes even with checks, if it's function in scope.variable) - it will work.
I see only profit of this change is more clean and less buggy code in future (maybe not only this - let me know please), but I think "breaking change" in stable branch is too high price for it.

@caitp
Contributor
caitp commented Dec 15, 2014

we all think so --- but it is what it is

@googlebot

CLAs look good, thanks!

@petebacondarwin
Member

@caitp - I am also feeling uncomfortable about this change.
How about this compromise:

  • if the expression is not optional then we leave the behaviour as-is (i.e. we just pass a noop to the scope)
  • if the expression is optional (new feature) then we do not define it on the scope

This way, we do not break existing directives; plus we provide a way for directive developers to specify optional expressions and easily check for their existence in the template, etc.

What do you think?

(cc @IgorMinar)

@caitp caitp changed the title from fix($compile): throw when non-optional '&' binding is used but not specified to fix($compile): do not initialize optional '&' binding if attribute not specified Jan 30, 2015
@caitp
Contributor
caitp commented Jan 30, 2015

updated, PTAL

@caitp caitp commented on the diff Jan 30, 2015
test/ng/compileSpec.js
@@ -3224,6 +3226,38 @@ describe('$compile', function() {
});
+ it('should not initialize scope value if optional expression binding is not passed', inject(function($compile) {
+ compile('<div my-component></div>');
+ var isolateScope = element.isolateScope();
+ expect(isolateScope.optExpr).toBeUndefined();
+ }));
+
+
+ it('should not initialize scope value if optional expression binding with Object.prototype name is not passed', inject(function($compile) {
+ compile('<div my-component></div>');
+ var isolateScope = element.isolateScope();
+ expect(isolateScope.constructor).toBe($rootScope.constructor);
@caitp
caitp Jan 30, 2015 Contributor

The Object.prototype stuff is optional --- I mean, it's basically going to do the wrong thing no matter what, so it's kind of weird. One option is to just always assign to undefined instead of just breaking, I guess?

@petebacondarwin
Member

Great - taking a look!

@caitp caitp fix($compile): do not initialize optional '&' binding if attribute no…
…t specified

BREAKING CHANGE:

Previously, '&' expressions would always set up a function in the isolate scope. Now, if the binding
is marked as optional and the attribute is not specified, no function will be added to the isolate scope.

Closes #6404
4f55ebf
@jbedard jbedard commented on an outdated diff Jan 30, 2015
src/ng/compile.js
parentGet = $parse(attrs[attrName]);
+
+ // Don't assign noop to destination if expression is not valid
+ if (parentGet.noop && optional) break;
@jbedard
jbedard Jan 30, 2015 Contributor

This will only happen if a non-string/function is passed to $parse. When would that happen?

@caitp caitp added a commit that closed this pull request Jan 30, 2015
@caitp @petebacondarwin caitp + petebacondarwin fix($compile): do not initialize optional '&' binding if attribute no…
…t specified

BREAKING CHANGE:

Previously, '&' expressions would always set up a function in the isolate scope. Now, if the binding
is marked as optional and the attribute is not specified, no function will be added to the isolate scope.

Closes #6404
Closes #9216
6a38dbf
@caitp caitp closed this in 6a38dbf Jan 30, 2015
@petebacondarwin
Member

Not so easy to cherry pick to 1.3.x ...

@caitp
Contributor
caitp commented Jan 30, 2015

i'm not sure we should backport it

@petebacondarwin
Member

I realise after trying to do so manually that it is effectively a breaking change. So yes, you are right

@cburgdorf
Contributor

Sorry for digging out an old thread. I noticed that there is a breaking change regarding =? between 1.3 and 1.4 as well and I would like to figure out if that's due to what is described in this issue. It seems this issue is only referring to & bindings but it seems to be related.

This example throws with an exception when you try to toggle the second zippy because it doesn't use the open binding and the binding isn't marked as optional. The example is based on 1.3.

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

The same example using 1.4 does not throw however.

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

/cc @PascalPrecht

@petebacondarwin
Member

That is weird @cburgdorf - can you open a new issue for it. I think it is a bug.

@cburgdorf
Contributor

Thanks for the fast reply! I opened this one #13367

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment