Oliver Dixon
Oliver Dixon

Reputation: 7424

AngularJS, updating ng-repeat within a child controller view by reference

I have a child controller that references values from it's parent.

The problem is: ng-repeat within the child controller view doesn't get updated when the parent controller values are updated.

So my question is: How does one update the child controller ng-repeat when parent controller values are updated while child values are by reference?

Child Controller:

angular.module('angularApp').controller('PostController', function ($scope) 
{
    $scope.mainController = $scope.$parent.getMainController();
    $scope.editController = $scope.$parent;
    $scope.posts = $scope.mainController.currentStation.posts;
    $scope.featuredAlbums = $scope.$parent.featuredAlbums;

    $scope.updatePost = function(postId){
        $scope.editController.updatePost(postId);
    };

    $scope.updateFeatured = function(featuredId){
        $scope.editController.updateFeatured(featuredId);
    };
});

ng-repeat under the child controller

<div ng-controller="PostController" class="posts">
<div ng-repeat="featuredAlbum in featuredAlbums">

Example that breaks:

http://plnkr.co/edit/GKjYAWEEWOrp84bwIIOt?p=info

** Answer **

Thanks for the fast response guys, I realise that everything created within the controller is passed by value and not reference, even values referenced from parent controllers are recreated as locally scoped controller values.

So the solution? Simple.

Just call the parent directly instead of recreating locally scoped vars

$scope.$parent.$someValue

Upvotes: 0

Views: 579

Answers (3)

David Beech
David Beech

Reputation: 1108

Imagine the scenario:

app.controller('ParentController', function($scope) {
   $scope.rawValue = 3;
   $scope.hiddenValue = false;
   $scope.objectValue = {
       name: 'David',
       age: 27
   };
   $scope.someFunction = function(input) {
       return input;
   }
});

app.controller('ChildController', function($scope) {
   $scope.hiddenValue = true;
   //Notice i don't need to wrap calls to parent functions or reassign parent data.
   //this is because the $scope object will automatically inherit from it's parent.
});


<div ng-controller="ParentController">
     {{ hiddenValue }} //false, remains false as setting only occured on child scope;
     {{ rawValue }} //3, remains 3 as setting will only occur on child scope;
     {{ objectValue.name }} // 'David' however will dynamically update with input below.

     <div ng-controller="ChildController">
         {{ hiddenValue }} //true because now it's scoped;
         <input type="button" ng-click="someFunction('hello')" value="calls function on parent scope" />
         <input type="text" ng-model="rawValue" /> //will initialise as 3 but as soon as updated it will be scoped on this scope.
         <input type="text" ng-model="objectValue.name" /> //will initialise as David and will correctly update parent scope as edited.
     </div>
</div>

So why does this work?

Anytime you are accessing a property or function it will automatically travel up the $scope hierarchy to find the value. No need to specify $parent expressly as this is how javascript inheritance works.

However whenever you are modifying/setting a value it will occur on the nearest $scope and be 'scoped'. that's what happens with hiddenValue and rawValue in example above. however notice that it works as expected on objectValue.name this is because in order to set the name property you must first 'get' objectValue. therefore javascript inheritance travels up the scope chain to get objectValue from the parent scope and then sets it's name property.

Two guidelines:

  1. ng-model should usually use a '.' so that it forces this scope walking.
  2. using $parent is usually a bad sign. If used correctly parent properties should already be available through the current $scope alone.

Upvotes: 1

chriskelly
chriskelly

Reputation: 7736

What's happening is that you are getting a new copy of the data in the child scope and the parent scope is not updated.

The simplest way to make it work is not to store any objects that need to be accessible by child controllers directly on the parent scope. You will have less code and far fewer complications.

In your case, in the parent have something like:

$scope.media = {
    featuredAlbums : [ ... ],
    currentStation : {
        posts : {...}
    }
}
$scope.functions = {
    updatePost : function (pid) {
        // your function
    },
    updateFeatured : function (pid) {
        // your function
    }
}

and in the child don't bother with all the inheritance and just call functions directly :

$scope.functions.updatedFeatured(featureID);
$scope.functions.updatePost(postId);

it doesn't matter which parent controller your functions and data are in, it will find them if you attach to a property of the controller but not the controller itself.

Take a look at this video which explains it better.

https://egghead.io/lessons/angularjs-the-dot

EDIT

As David Beech points, there is no need to store parent scope functions in a property because the function is not being modified. However, this approach is meant to be a simple rule that will work without any extra thinking about which data/functions are read-only and which are writable.

Upvotes: 1

ABOS
ABOS

Reputation: 3823

I am not sure I understand your question correctly. So I created a plunker that included two controllers. It seems to me that child values are always updated. Can you show us how your original questions are related or not?

`http://plnkr.co/edit/9aHqdbbIe5aGJSuHogPA?p=preview`

Upvotes: 1

Related Questions