harshit
harshit

Reputation: 7951

Error: [$compile:nonassign] Expression 'undefined' used with directive 'myFacebook' is non-assignable

I am writing a directive in angularjs and get the above mentioned error. I am using the code from a book.

.directive('myFacebook', [function(){
return {
    link: function(scope,element,attributes) {
        (function(d) {
                var js, id = 'facebook-jssdk',
                    ref = d.getElementsByTagName('script')[0];
                if (d.getElementById(id)) {
                    return;

                }
                js = d.createElement('script');
                js.id = id;
                js.async = true;
                js.src = "//connect.facebook.net/en_US/all.js";
                ref.parentNode.insertBefore(js, ref);
            }(document));
            // Initialize FB
            window.fbAsyncInit = function() {
                FB.init({

                    appId: 'xxxx', //birthday reminder
                    status: true, // check login status
                    cookie: true, // enable cookies to access the session
                    xfbml: false // parse XFBML
                });
                //Check FB Status
                FB.getLoginStatus(function(response) {
                     xxxx
                });
            };
        scope.username='';
    },
    scope: {
            permissions: '@',
            myFriends: '=friends'
        },
    controller: function($scope) {
        $scope.loadFriends = function() {
            FB.api('/me/friends?fields=birthday,name,picture', function(response) {
                    $scope.$apply(function() {
                        $scope.myFriends = response.data;
                    });
                });
        }
    },

    template:'Welcome {{username}}'
   }}])

I get error at

 $scope.$apply(function() {
            $scope.myFriends = response.data;
 });

The HTML code

<div my-facebook></div>
<h1> My Friend's Birthday Reminder</h1>
<div ng-repeat="friend in myFriends">
     {{friend.name}}
</div>

Upvotes: 50

Views: 57088

Answers (6)

Lesh_M
Lesh_M

Reputation: 616

If you're using it as a one way binding just define the scope appropriately:

scope: {
   example: '<'
}

In my case I was using a bi-directional binding as a one-way binding, passing inline objects like these:

<directive bindings="{key: value}"></directive>

My case was a special one because I (purposely) destroyed objects and thereby broke their bindings, but if you only need one-way binding just define it that way.

Upvotes: 1

Basheer AL-MOMANI
Basheer AL-MOMANI

Reputation: 15337

I had this because I tried to update another variable in my directive's scope but not passed it in html even though it's computed and should not be passed in html

here is an example of a directive scope

scope: {
  var1: '=',
  var2: '='
}

in that directive, I can pass to it var1 or var2 but not both and the directive logic will find the value of the other var

that error happened to me when I called the directive with var1 and updated var2 in code

<pb-my-directive  var1="something"></my-directive>

to overcome this issue call the directive with all scope variables you want to update even with non-meaning values in my example

<pb-my-directive  var1="something" var2="false"></my-directive>

hope this helps you

Upvotes: 0

Matt Lishman
Matt Lishman

Reputation: 1817

Not a direct answer to OPs question, but this just happened to me so for anyone else that might Google this error in the future. This is similar to JohnP's answer.

This error can also appear if you have a camelCase attribute in your directive.

So if you have:

<div my-facebook myFriends></div>

It will throw the error.

This is because (taken from the angular documentation):

Angular normalizes an element's tag and attribute name to determine which elements match which directives. We typically refer to directives by their case-sensitive camelCase normalized name (e.g. ngModel). However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case forms, typically using dash-delimited attributes on DOM elements (e.g. ng-model).

The normalization process is as follows:

Strip x- and data- from the front of the element/attributes.

Convert the :, -, or _-delimited name to camelCase.

so <div my-facebook myFriends></div>

will need to become <div my-facebook my-friends></div>

Upvotes: 20

Louis
Louis

Reputation: 1035

My solution was harder to find out here, but easier to implement. I had to change it to the equivalent of (Note that the question mark makes the attribute optional. Prior to 1.5 this apparently wasn't required).

scope: {
    permissions: '@',
    myFriends: '=?friends'
}

Upvotes: 80

JohnP
JohnP

Reputation: 1076

I run to this same issue and for me the problem was upper case characters in DOM name.

<div my-facebook FRIENDS="friendList"></div>

did not work, but

<div my-facebook friends="friendList"></div>

worked. I spent a day working on this and found the solution by accident.

Upvotes: 4

bmleite
bmleite

Reputation: 26880

The problem is that you are not defining the attribute friends in the directive element <div my-facebook></div>.

When you define the directive's scope like this:

scope: {
    permissions: '@',
    myFriends: '=friends'
}

You are basically saying:

  • Bind to the local scope's permissions property the value of DOM attribute with the same name
  • Set up bi-directional binding between the local scope's myFriends property and the parent scope's friends property

Since you are not defining the attribute friends in the DOM, Angular cannot create the bi-directional binding and throws the error. More information here.

Define the friends attribute on your DOM and it should fix the problem:

<div my-facebook friends="friendList"></div>

And, for example, on the controller:

app.controller('Ctrl', function($scope) {
  $scope.friendList = [];
});

Upvotes: 76

Related Questions