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

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

Closed
wants to merge 1 commit into from

Conversation

caitp
Copy link
Contributor

@caitp 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
Copy link
Contributor Author

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?

@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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is not present

@lgalfaso
Copy link
Contributor

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
Copy link
Contributor Author

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
Copy link
Contributor Author

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
Copy link
Contributor

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.

@petebacondarwin petebacondarwin modified the milestones: 1.4.x, Backlog Dec 15, 2014
@e-oz
Copy link

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
Copy link
Contributor Author

caitp commented Dec 15, 2014

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

@googlebot
Copy link

CLAs look good, thanks!

@petebacondarwin
Copy link
Contributor

@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 fix($compile): throw when non-optional '&' binding is used but not specified fix($compile): do not initialize optional '&' binding if attribute not specified Jan 30, 2015
@caitp
Copy link
Contributor Author

caitp commented Jan 30, 2015

updated, PTAL

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);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Great - taking a look!

…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 angular#6404
parentGet = $parse(attrs[attrName]);

// Don't assign noop to destination if expression is not valid
if (parentGet.noop && optional) break;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@petebacondarwin
Copy link
Contributor

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

@caitp
Copy link
Contributor Author

caitp commented Jan 30, 2015

i'm not sure we should backport it

@petebacondarwin
Copy link
Contributor

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

@cburgdorf
Copy link
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
Copy link
Contributor

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

@cburgdorf
Copy link
Contributor

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

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