0

I am currently learning AngularJS.

I am stuck trying to update a series of buttons which I have generated from a directive when the object data is updated.

I have read a number of posts addressing similar issues for where data not created in a directive won't update to no avail.

HTML

<body>
    <div id="application" data-ng-app="ApplicationDirective" ng-controller="ApplicationController" class="container-fluid">
        <side-panel class="col-lg-2"></side-panel>
        <div ng-controller="HomeController" class="content col-lg-10">

        </div>
    </div>
</body>

As you can see I have defined 2 controllers. 1 ApplicaitonControler to manage the application as a whole and then a second HomeController to manage an inner section of the HMTL.

I then have a directive which generates a series of buttons for a side panel.

var app = angular.module('ApplicationDirective', []);

app.directive("sidePanel", function() {
    return {
        restrict: "E",
        template : "<div>" +
                   "<input ng-repeat='btn in sidePanelButtons' type='button' value={{btn.value}}>" +               
                   "</div>"
    };
});

The $scope data for the above is defined in the ApplicationContoller. Then I update the data in HomeController.

app.controller("HomeController", function($scope) {
    $scope.sidePanelButtons = $scope.sidePanelButtons.concat([
        {value:"TEST"}
    ]);
});

At this point, if I log the sidePanelButtons var then I can see that the data was successfully appended, however nothing in the HTML changes?.

I have tried using the $scope.$apply method however I get an error.

Potentially I have the wrong design methodologies, so any help would be appreciated.

Zze
  • 18,229
  • 13
  • 85
  • 118
  • As a quick hint: Try a `$timeout` instead. It is doing an `$scope.$apply` automatically. – Beat Apr 28 '16 at 05:58

3 Answers3

2

The concat() method returns a new array.

So when you do

$scope.sidePanelButtons = $scope.sidePanelButtons.concat([
    {value:"TEST"}
]);

You're creating a new sidePanelButtons property in HomeController scope, breaking the reference to sidePanelButtons array in ApplicationController scope. Your side panel directive is watching ApplicationController scope which remain un-altered.

Do $scope.sidePanelButtons.push() instead.

T J
  • 42,762
  • 13
  • 83
  • 138
  • Ahhhhhh interesting, that makes a lot of sense, I will test this out ASAP. – Zze Apr 28 '16 at 06:05
  • So I just tested this and it kind of worked, however now I have the 3 original buttons and a single blank button even though I tried to push 2 new values into the object.. ? `$scope.sidePanelButtons.push([ {value:"TEST1"}, {value:"TEST2"} ]);` – Zze Apr 28 '16 at 06:34
  • @Zze I don't know what your `ng-repeat` iterates on, but ideally you should be pushing objects like `$scope.sidePanelButtons.push( {value:"TEST1"}, {value:"TEST2"});` rather than array of objects. – T J Apr 28 '16 at 07:18
  • 1
    Legend! Syntax error on my part leaving those square brackets in. Good pickup. Cheers. – Zze Apr 28 '16 at 07:24
0

Try this

var app = angular.module('myApp', []);

app.directive("sidePanel", function() {
    return {
        restrict: "E",
        scope: {
         buttons: '='
        },
        template : "<div>" +
                   "<input ng-repeat='btn in buttons' type='button' value={{btn.value}}>" +               
                   "</div>"
    };
});

app.controller("ApplicationController", function($scope) {
  $scope.sidePanelButtons = [
        {value:"TEST"}
    ];
});
Sachin K
  • 192
  • 5
0

You can not update the $scope of one controller from another controller. $scope is local for every controller therefore the updated value displayed in the log belongs to HomeController and not ApllicationController. Either you define and update your data in the same controller or use a service if you are really in need of accessing same set of data from two controllers.

Another way is using $rootScope instead of $scope to make it available in all controllers.

app.controller("HomeController", function($scope, $rootScope) {
$rootScope.sidePanelButtons = $rootScope.sidePanelButtons.concat([
    {value:"TEST"}
]);
});

app.controller("ApplicationContoller", function($scope, $rootScope) {
$rootScope.sidePanelButtons = //define here; 
});

But i think there is another problem with your directive. You need to access your controller $scope from your directive to access the variables like sidePanelButtons. For solution to that problem please refer: Access controller scope from directive

Community
  • 1
  • 1
Avantika Saini
  • 792
  • 4
  • 9
  • This is not true. Child scopes are prototypically inherited from their parent scope so they can update object properties on parent scope. – T J Apr 28 '16 at 07:20
  • When Angular evaluates {{variable}}, it first looks at the scope associated with the given element for the name property. If no such property is found, it searches the parent scope and so on until the root scope is reached. In JavaScript this behavior is known as prototypical inheritance, and child scopes prototypically inherit from their parents. But this is not the case here. When inside a controller, $scope refers to the local copy. If the controllers are nested then writing $scope.$parent.sidePanelButtons would allow the child controller to access parent controller $scope.sidePanelButton – Avantika Saini Apr 28 '16 at 07:35
  • *"But this is not the case here"* - why? It is the case here. *"If the controllers are nested then writing $scope.$parent.sidePanelButtons would allow the child controller to access parent controller $scope.sidePanelButton*. " of course. But that is totally unnecessary here. – T J Apr 28 '16 at 09:35