2

I have an Angular directive which permit to render an user, and create a link to view the user profile, declared as:

.directive('foafPerson', function() {
    return {
      restrict: 'E',
      templateUrl: 'templates/person.html',
      scope: {
        personModel: '=',
        onClickBindTo: '=',
        onPersonClick: '&'
      }
    };

As you can see, I'm trying 2 solutions to be able to visit and load the full user profile: onClickBindTo and onPersonClick

I use it like that to render a list of persons + their friends:

// display the current user
<foaf-person person-model="person" on-person-click="changeCurrentProfileUri(person.uri)" on-click-bind-to="currentProfileUri"></foaf-person>

// display his friends
<div class="profileRelationship" ng-repeat="relationship in relationships">
    <foaf-person person-model="relationship" on-person-click="changeCurrentProfileUri(relationship.uri)" on-click-bind-to="currentProfileUri"></foaf-person>
</div>

On the template, I have a link that is supposed to change an attribute of the controller (called currentProfileUri)

<a href="" ng-click="onClickBindTo = personModel.uri">
    {{personModel.name}}
<a/>

I can see that the controller scope variable currentProfileUri is available in the personTemplate.html because I added a debug input: <input type="text" ng-model="onClickBindTo"/>

Unfortunately, when I modify the input value, or when I click on the link, the currentProfileUri of the controller is not updated. Is this normal or am I missing something?


With the other method it seems to work fine:

<a href="" ng-click="onPersonClick()">
    {{personModel.name}}
<a/>

So to modify a model of the parent scope, do we need to use parent scope functions?


By the way, passing an expression with &, I tried another solution: not using a function declared in the controller scope:

<foaf-person person-model="relationship" on-person-click="currentProfileUri = relationship.uri"></foaf-person>

How comes it does not work?


My controller has nothing really fancy:

$scope.currentProfileUri = 'https://my-profile.eu/people/deiu/card#me';

$scope.$watch('currentProfileUri', function() {
  console.debug("currentProfileUri changed to "+$scope.currentProfileUri);
  loadFullProfile($scope.currentProfileUri);
})

$scope.changeCurrentProfileUri = function changeCurrentProfileUri(uri) {
  console.debug("Change current profile uri called with " + uri);
  $scope.currentProfileUri = uri;
}

I am new to Angular and read everywhere that using an isolate scope permits a two-way data binding with the parent scope, so I don't understand why my changes are not propagated to the parent scope and my debug statement doesn't fire unless I use the scope function changeCurrentProfileUri

Can someone explain me how it works?

John Slegers
  • 45,213
  • 22
  • 199
  • 169
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419

1 Answers1

0

In your example the scopes hierarchy is the following:

controller scope 
    ng-repeat scope
        foaf-person scope

so when you declare two-way binding for 'currentProfileUri' it is actually bound to the scope created by ng-repeat, not by the controller, and when your code changes value of onClickBindTo then angularjs executes 'currentProfileUri = newValue' in the ng-repeat scope.

Solution is to use objects instead of primitive values for two-way bindings - in this case scopes inheritance always work in proper way. I mean something like that:

// display the current user
<foaf-person person-model="person" on-click-bind-to="currentProfile.uri"></foaf-person>

// display his friends
<div class="profileRelationship" ng-repeat="relationship in relationships">
    <foaf-person person-model="relationship" on-click-bind-to="currentProfile.uri"></foaf-person>
</div>

I've prepared a js-fiddle which illustrates this behavior

GRaAL
  • 616
  • 3
  • 14
  • Yes, I forgot I found out the answer to this question described here: http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs – Sebastien Lorber Jan 26 '14 at 16:29