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

directives that have '=' binding, changing scope value causes error if not specified(optional) #1435

Closed
johnnyelwailer opened this issue Oct 3, 2012 · 30 comments

Comments

@johnnyelwailer
Copy link

If I have a directive with a scope definition, and setting a value in the scope:

directive('some', function () {
  return  {
    scope: {optionalValue: '='},
    bind: function(scope) {
      scope.optionalValue = something;
    }
  }
}

And create it like

<some />

With optionalValue not specified, it yields the NON_ASSIGNABLE_MODEL_EXPRESSION error.
But I'd expect it to work in this case.

This could be solved in the "scope mode parser" by simply not applying the binding:

case '=': {
  if (attrs[attrName] == null) {
    return;
  }
   ...

Or is this intentionally? If so, maybe add a new symbol like '~' for optional attributes?

(just realized that I opened essentially the same issue 3 months ago: #1131)

@NickHeiner
Copy link
Contributor

I would like to see any easy way for optional arguments / argument defaults on directive attributes as well.

@pkozlowski-opensource
Copy link
Member

Created a jsFiddle to expose the same issue with the latest version of AngularJS: http://jsfiddle.net/yA2rn/
The use case seems to be a valid one...

@presstube
Copy link

Just chiming in that this is something that would be very useful to me as well. thanks

@bendalton
Copy link

ditto.

@fx
Copy link

fx commented Dec 13, 2012

+1

@ryanzec
Copy link

ryanzec commented Dec 24, 2012

I also think this would be very useful. Right now I am doing this in my directives:

var optionalParameters = scope.$eval(attributes.optionalParameters);

which works ok if I don't need bi-directional binding with the parent scope.

@tschieggm
Copy link

+1

lrlopez added a commit to lrlopez/angular.js that referenced this issue Jan 26, 2013
If you bind using '=' to a non-existant parent property, the compiler
will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception, which is right
because the model doesn't exist.

This enhancement allow to specify that a binding is optional so it
won't complain if the parent property is not defined. In order to mantain
backward compability, the new behaviour must be specified using '=?' instead
of '='. The local property will be undefined is these cases.

Closes angular#909
Closes angular#1435
@just-boris
Copy link
Contributor

That's good. Now, I make optional binding like this:

link: function(scope, element, attrs) {
    if (attrs.selected) {
        getSelected = $parse(attrs.selected);
        setSelected = getSelected.assign;
        scope.$watch(
            function watchSelected() {
                 return getSelected(scope.$parent); 
            },
            function updateSelected(value) {
                if(setSelected) {
                     setSelected(scope.$parent, value);
                }
                scope.selected = value;
            }
        );
        scope.selected = getSelected ? getSelected(scope.$parent) : false;
    }
}

This code can be replaced by simple config

scope: {
    selected: "=?"
}

@roypeled
Copy link

roypeled commented Feb 3, 2013

Please merge lrlopez's fix with the master build!

@Mischi
Copy link

Mischi commented Feb 14, 2013

+1

3 similar comments
@aaronwhite
Copy link

+1

@innovationhero
Copy link

+1

@marcospassos
Copy link

+1

@rgraffconnect
Copy link

I'm seeing this issue in 1.0.7 and getting an error when using =?

Error:
Invalid isolate scope definition for directive ...: =?

Is this issue back!??

@lrlopez
Copy link
Contributor

lrlopez commented Aug 29, 2013

This feature was merged into the 1.1.x branch so it's not available in 1.0.x, sorry...

@rgraffconnect
Copy link

Oh ok, thank you.

On Aug 29, 2013, at 5:40 PM, Luis Ramón López notifications@github.com wrote:

This feature was merged into the 1.1.x branch so it's not available in 1.0.x, sorry...


Reply to this email directly or view it on GitHub.

@SimplGy
Copy link

SimplGy commented Mar 12, 2014

Understanding that it works to use the syntax = for a required 2-way binding and =? for an optional 2-way binding, I wonder why both are needed.

Could they always be optional? This makes the API simpler. Is there a performance issue there?

@just-boris
Copy link
Contributor

@SimpleAsCouldBe conversely, performance would be improved if the required binding will be removed, because regexp will become simpler.
So I agree with you.

@just-boris
Copy link
Contributor

Someone from @angular, please take attention for this question

@SimplGy
Copy link

SimplGy commented Jul 22, 2014

We might want to make this a separate feature request, @just-boris. Succinctly, the request is:

"Make = an optional binding all the time"

Wondering about performance and structure implications. Also maybe some folks depend on the enforcement of this.

I tend to think the better default is "just work/silently fail", sort of like exceptions in templates ({{ myUndefinedObject.name }}) don't throw. If enforcement is wanted syntax like =! or === could opt-in.

@wbeange
Copy link

wbeange commented Aug 19, 2014

Thanks

@bernhard-hofmann
Copy link
Contributor

If the parent scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You can avoid this behavior using =? or =?attr in order to flag the property as optional.

The above was quoted from the $compile documentation.

I see it's been mentioned before, but after that there are more people calling for this feature who might only read the first and last post.

@caitp
Copy link
Contributor

caitp commented Sep 23, 2014

it won't throw if the parent scope property doesn't exist --- it will throw if the expression is just not assignable (for instance, foo.bar is assignable, while foo.bar() is not) --- need an lvalue

@joshribakoff
Copy link

@bernhard-hofmann Thanks for the explanation, this fixed it for me.

To improve the documentation, you should know that I think the users are confused (I was at least) because many guides including the official one (https://docs.angularjs.org/guide/directive) mention '&', '@', and '=' syntax... (which is already confusing)... no guides that I read mention '=?' syntax. Nothing would have prompted me to look into the documentation for $compile since I'm not touching that service with my code.

@BorisKozo
Copy link

Agree with @joshribakoff , I would never found this in the docs unless someone from my team pointed me to this thread.

@LeonardoGentile
Copy link

@just-boris I can't use angular 1.1.x so I'm using your approach.

The problem is that I can't make a two ways binding with your approcah meaning that when I change the scope variable in the directive it doesn't get updated in the container controller. Would you clarify a little bit your solution ?
It's not very clear, I'm missing something..

@just-boris
Copy link
Contributor

@LeonardoGentile updated my code snippet, now it has a call of setSelected(scope.$parent, value);
But there is already three major releases, so I advice you to update

@LeonardoGentile
Copy link

Thanks @just-boris but that did not work for me...I had to make a little modification:

link: function(scope, element, attrs) {
    if (attrs.selected) {
        getSelected = $parse(attrs.selected);
        setSelected = getSelected.assign;
        scope.$watch(
            function watchSelected() {
                 return getSelected(scope.$parent); 
            },
            function updateSelected(value) {
                scope.selected = value
            }
        );
        scope.selected = getSelected ? getSelected(scope.$parent) : false;
    }
    scope.$watch('selected', function(value) {
        if(setSelected) {
            setSelected(scope.$parent, value)
        }
    })   
}

@unusualpseudo
Copy link

+1

@Narretz
Copy link
Contributor

Narretz commented Aug 29, 2016

@marsechelon I don't know why you are +1 this as optional bindings have been in Angular since 1.1.x.

@angular angular locked and limited conversation to collaborators Aug 29, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.