Salal Aslam
Salal Aslam

Reputation: 1377

AngularJS ui-bootstrap accordion cannot access variable outside accordion in filtered ng-repeat

I am using AngularJS UI Bootstrap's accordion. I am using ng-repeat with filter inside the accordion. Now the problem is that I cannot access the filtered variable outside <accordion>. If I ditch the accordion and use simple HTML it works fine.

<div ng-app="myApp">
  <div ng-controller="AccordionCtrl">
    <div>outside accordion{{filteredCampaigns}}</div>
    <input type="text" ng-model="q" placeholder="filter" />
    <accordion class="accordion" close-others="true">
      <div>inside accordion{{filteredCampaigns}}</div>
      <accordion-group  ng-repeat="campaign in filteredCampaigns=(campaigns | filter:q)">
        <accordion-heading>
          <h3>{{campaign.title}}</h3>
        </accordion-heading>
        <p>{{campaign.content}}</p>
      </accordion-group>
    </accordion>
  </div>
</div>
<script>
  var app = angular.module('myApp', ['ui.bootstrap']);
  app.controller('AccordionCtrl', ['$scope',
  function ($scope) {
      $scope.campaigns = [{
          title: "Test1",
          content: "file1.html"
      }, {
          title: "Test2",
          content: "file2.html"
      }, {
          title: "Test3",
          content: "file3.html"
      }];
  }]);
</script>

I have also created the fiddle here

Upvotes: 2

Views: 1674

Answers (3)

Jossef Harush Kadouri
Jossef Harush Kadouri

Reputation: 34217

This is becuase the sub-directives comes with angular-ui have child scopes that does not reflect this new filteredCampaigns variable to the controller's scope.

1st option - Hack it,

1) define an object to contain the filteredCampaigns dynamic variable

$scope.context = {};   

2) change your accordion-group to:

<accordion-group ng-repeat="campaign in context.filteredCampaigns=(campaigns | filter:q)">

http://jsfiddle.net/Lryuvm9m/1/

<script>
    var app = angular.module('myApp', ['ui.bootstrap']);
    app.controller('AccordionCtrl', ['$scope',
    function ($scope) {

        $scope.context = {};
        $scope.campaigns = [{
            title: "Test1",
            content: "file1.html"
        }, {
            title: "Test2",
            content: "file2.html"
        }, {
            title: "Test3",
            content: "file3.html"
        }];
    }]);
</script>

<div ng-app="myApp">
    <div ng-controller="AccordionCtrl">
        <div>outside accordion {{context.filteredCampaigns}} </div>
        <input type="text" ng-model="q" placeholder="filter" />      
        <accordion class="accordion" close-others="true">
            <div>inside accordion{{context.filteredCampaigns}}</div>
            <accordion-group  ng-repeat="campaign in context.filteredCampaigns=(campaigns | filter:q)">
                <accordion-heading>
                    <h3>{{campaign.title}}</h3>
                </accordion-heading>
                <p>{{campaign.content}}</p>
            </accordion-group>
        </accordion>
    </div>
</div>

2nd option - use Controller as,

i would recommend using Controller as since it will give you more controll of what's defined on the controller's scope and what's not

http://jsfiddle.net/gntt6h5b/

<script>
    var app = angular.module('myApp', ['ui.bootstrap']);
    app.controller('AccordionCtrl', ['$scope',
    function () {
        var vm = this;
        vm.campaigns = [{
            title: "Test1",
            content: "file1.html"
        }, {
            title: "Test2",
            content: "file2.html"
        }, {
            title: "Test3",
            content: "file3.html"
        }];
    }]);
</script>

<div ng-app="myApp">
    <div ng-controller="AccordionCtrl as vm">
        <div>outside accordion {{vm.filteredCampaigns}} </div>
        <input type="text" ng-model="q" placeholder="filter" />      
        <accordion class="accordion" close-others="true">
            <div>inside accordion{{vm.filteredCampaigns}}</div>
            <accordion-group  ng-repeat="campaign in vm.filteredCampaigns=(vm.campaigns | filter:q)">
                <accordion-heading>
                    <h3>{{campaign.title}}</h3>
                </accordion-heading>
                <p>{{campaign.content}}</p>
            </accordion-group>
        </accordion>
    </div>
</div>

Upvotes: 4

Numyx
Numyx

Reputation: 1758

<accordion> creates an isolated scope and the filteredCampaigns are only available in that scope, not in the parent scope. To add it to the parent scope, you use $parent:

ng-repeat="campaign in $parent.filteredCampaigns=(campaigns | filter:q)">

Another solution would be creating an creating an object an object in the parent scope with a parameter for the filteredCampaings:

// AccordionCtrl
$scope.filteredValues = {
    filteredCampaings: []
};

ng-repeat="campaign in filteredValues.filteredCampaigns=(campaigns | filter:q)"

Upvotes: 1

Omri Aharon
Omri Aharon

Reputation: 17064

Since you're using it outside of the ng-repeat, you can't see that variable as ng-repeat creates its own scope.

You can use the controller and use the filter manually to retrieve the filtered objects:

$scope.getFilteredCampaings = function () {
        $scope.filteredCampaigns = $filter('filter')($scope.campaigns, $scope.q);
        return $scope.filteredCampaigns;
}

Fiddle

Upvotes: 0

Related Questions