Angular - 我可以在嵌套的ng-repeat中的多个对象上使用单个函数来触发该对象的ng-show吗?

时间:2022-11-25 17:24:04

SUMMARY
I have a list of brands and a list of products. I am using an ng-repeat to show the list of brands, and an ng-repeat with a filter to show the list of products within their respective brands. I want each brand and each product to have a button that shows more about that brand/product. All of these buttons should use the same function on the controller.

总结我有一个品牌列表和一个产品列表。我使用ng-repeat来显示品牌列表,并使用过滤器的ng-repeat来显示各自品牌的产品列表。我希望每个品牌和每个产品都有一个按钮,可以显示有关该品牌/产品的更多信息。所有这些按钮应在控制器上使用相同的功能。

PROBLEM
The button that shows more about the brand also shows more about each of that brand's products, UNLESS (this is the weird part to me) I click the button of a product within that brand first, in which case it will work correctly.

问题显示关于品牌的更多信息的按钮也显示了该品牌产品的更多信息,除非(这对我来说很奇怪)我首先点击该品牌中的产品按钮,在这种情况下它将正常工作。

CODE
Please see the Plunker here, and note that when you click on 'show type' on a brand, it also shows all the types of the products within that brand: http://plnkr.co/edit/gFnq3O3f0YYmBAB6dcwe?p=preview

代码请在此处查看Plunker,并注意当您点击品牌上的“show type”时,它还会显示该品牌中所有类型的产品:http://plnkr.co/edit/gFnq3O3f0YYmBAB6dcwe?p = preview

HTML

<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>

  <body>
    <div ng-app="myApp">
      <div ng-controller="MyController as vm">
        <div ng-repeat="brand in brands">
          <h1>
              {{brand.name}}
            </h1>
          <button ng-click="showType(brand)">
            Show Brand Type
          </button>
          <div ng-show="show">
            {{brand.type}}
          </div>
          <div ng-repeat="product in products
          | filter:filterProducts(brand.name)">
            <h2>
                  {{product.name}}
                </h2>
            <button ng-click="showType(product)">
              Show Product Type
            </button>
            <div ng-show="show">
              {{product.type}}
            </div>
          </div>
        </div>
      </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>

JAVASCRIPT

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

app.controller('MyController', function($scope) {

  $scope.brands = [{
    name: 'Kewl',
    type: 'Cereal'
  }, {
    name: 'Joku',
    type: 'Toy'
  }, {
    name: 'Loko',
    type: 'Couch'
  }]

  $scope.products = [{
    name: 'Kewlio',
    type: 'Sugar Cereal',
    brand: 'Kewl'
  }, {
    name: 'Kewliano',
    type: 'Healthy Cereal',
    brand: 'Kewl'
  }, {
    name: 'Jokurino',
    type: 'Rattle',
    brand: 'Joku'
  }, {
    name: 'Lokonoko',
    type: 'Recliner',
    brand: 'Loko'
  }, {
    name: 'Lokoboko',
    type: 'Love Seat',
    brand: 'Loko'
  }]

  $scope.showType = function(item) {
    this.show = !this.show;
  }

  $scope.filterProducts = function(brand) {
    return function(value) {
      if(brand) {
        return value.brand === brand;
      } else {
        return true;
      }
    }
  }
});

IMPORTANT NOTE: I realize I could add an attribute to the object (brand.show) and pass the object into the function, then change that attribute to true/false, but I don't want to do this because in my actual application, the button will show a form that edits the brand/product and submits the info to Firebase, and I don't want the object to have a 'show' attribute on it. I would rather not have to delete the 'show' attribute every time I want to edit the info in Firebase.

重要说明:我意识到我可以向对象添加属性(brand.show)并将对象传递给函数,然后将该属性更改为true / false,但我不想这样做,因为在我的实际应用程序中,该按钮将显示一个表单,用于编辑品牌/产品并将信息提交给Firebase,我不希望该对象具有“show”属性。我希望每次要在Firebase中编辑信息时都不必删除“show”属性。

3 个解决方案

#1


0  

ng-repeat directive create own scope, when you do

当你这样做时,ng-repeat指令创建自己的范围

this.show = !this.show

you create/change show property in current scope, if click brand button - for brand scope, that global for product, and when click in product button - for scope concrete product.

您可以在当前范围内创建/更改展示属性,如果单击品牌范围,则为品牌范围,产品全局,以及单击产品按钮时 - 针对范围具体产品。

To avoid this, you should create this property before clicking button, for example with ng-init, like

要避免这种情况,您应该在单击按钮之前创建此属性,例如使用ng-init

ng-init="show=false;"

on element with `ng-repeat" directive

使用`ng-repeat'指令的元素

Sample

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

app.controller('MyController', function($scope) {

  $scope.brands = [{
    name: 'Kewl',
    type: 'Cereal'
  }, {
    name: 'Joku',
    type: 'Toy'
  }, {
    name: 'Loko',
    type: 'Couch'
  }]

  $scope.products = [{
    name: 'Kewlio',
    type: 'Sugar Cereal',
    brand: 'Kewl'
  }, {
    name: 'Kewliano',
    type: 'Healthy Cereal',
    brand: 'Kewl'
  }, {
    name: 'Jokurino',
    type: 'Rattle',
    brand: 'Joku'
  }, {
    name: 'Lokonoko',
    type: 'Recliner',
    brand: 'Loko'
  }, {
    name: 'Lokoboko',
    type: 'Love Seat',
    brand: 'Loko'
  }]

  $scope.showType = function(item) {
    this.show = !this.show;
  }

  $scope.filterProducts = function(brand) {
    return function(value) {
      if (brand) {
        return value.brand === brand;
      } else {
        return true;
      }
    }
  }

});
/* Styles go here */

h1 {
  font-family: impact;
}
h2 {
  font-family: arial;
  color: blue;
  margin-bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<div ng-app="myApp">
  <div ng-controller="MyController as vm">
    <div ng-repeat="brand in brands" ng-init="show=false">
      <h1>
              {{brand.name}}
            </h1>
      <button ng-click="showType(brand)">
        Show Brand Type
      </button>
      <div ng-show="show">
        {{brand.type}}
      </div>
      <div ng-repeat="product in products
          | filter:filterProducts(brand.name)" ng-init="show=false">
        <h2>
           {{product.name}}
        </h2>
        <button ng-click="showType(product)">
          Show Product Type
        </button>
        <div ng-show="show">
          {{product.type}}
        </div>
      </div>
    </div>
  </div>
</div>

#2


0  

The easiest fix for this, if you don't mind putting temporary properties in your data is the following changes:

对此最简单的解决方法是,如果您不介意在数据中放置临时属性,则需要进行以下更改:

<div ng-show="product.show">
   {{product.type}}
</div>

and

<div ng-show="brand.show">
   {{brand.type}}
</div>

and then in your controller

然后在你的控制器中

$scope.showType = function(item) {
    item.show = !item.show;
  }

Alternatively, if you don't want to touch the object properties, you can create an $scope.shownTypes array and have your click either push the object into or remove the object from the shown array. THen you can check for the object's existence in the array and show or not show the type appropriately. Let me know if you need a sample of that.

或者,如果您不想触摸对象属性,则可以创建$ scope.shownTypes数组,然后单击将对象推入或从显示的数组中删除对象。然后,您可以检查对象在数组中是否存在,并显示或不显示相应的类型。如果你需要一个样本,请告诉我。

#3


0  

Your show boolean attribute same for whole tree (is in same scope). Using angular directive with child scope scope:true in ng-repeat helps to isolate each show property. I have forked your plunker code:

整个树的show boolean属性相同(在同一范围内)。使用带有子范围范围的angular指令:ng-repeat中的true有助于隔离每个show属性。我已经分叉你的plunker代码:

http://plnkr.co/edit/cMSvyfeCQOnTKG8F4l55?p=preview

#1


0  

ng-repeat directive create own scope, when you do

当你这样做时,ng-repeat指令创建自己的范围

this.show = !this.show

you create/change show property in current scope, if click brand button - for brand scope, that global for product, and when click in product button - for scope concrete product.

您可以在当前范围内创建/更改展示属性,如果单击品牌范围,则为品牌范围,产品全局,以及单击产品按钮时 - 针对范围具体产品。

To avoid this, you should create this property before clicking button, for example with ng-init, like

要避免这种情况,您应该在单击按钮之前创建此属性,例如使用ng-init

ng-init="show=false;"

on element with `ng-repeat" directive

使用`ng-repeat'指令的元素

Sample

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

app.controller('MyController', function($scope) {

  $scope.brands = [{
    name: 'Kewl',
    type: 'Cereal'
  }, {
    name: 'Joku',
    type: 'Toy'
  }, {
    name: 'Loko',
    type: 'Couch'
  }]

  $scope.products = [{
    name: 'Kewlio',
    type: 'Sugar Cereal',
    brand: 'Kewl'
  }, {
    name: 'Kewliano',
    type: 'Healthy Cereal',
    brand: 'Kewl'
  }, {
    name: 'Jokurino',
    type: 'Rattle',
    brand: 'Joku'
  }, {
    name: 'Lokonoko',
    type: 'Recliner',
    brand: 'Loko'
  }, {
    name: 'Lokoboko',
    type: 'Love Seat',
    brand: 'Loko'
  }]

  $scope.showType = function(item) {
    this.show = !this.show;
  }

  $scope.filterProducts = function(brand) {
    return function(value) {
      if (brand) {
        return value.brand === brand;
      } else {
        return true;
      }
    }
  }

});
/* Styles go here */

h1 {
  font-family: impact;
}
h2 {
  font-family: arial;
  color: blue;
  margin-bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<div ng-app="myApp">
  <div ng-controller="MyController as vm">
    <div ng-repeat="brand in brands" ng-init="show=false">
      <h1>
              {{brand.name}}
            </h1>
      <button ng-click="showType(brand)">
        Show Brand Type
      </button>
      <div ng-show="show">
        {{brand.type}}
      </div>
      <div ng-repeat="product in products
          | filter:filterProducts(brand.name)" ng-init="show=false">
        <h2>
           {{product.name}}
        </h2>
        <button ng-click="showType(product)">
          Show Product Type
        </button>
        <div ng-show="show">
          {{product.type}}
        </div>
      </div>
    </div>
  </div>
</div>

#2


0  

The easiest fix for this, if you don't mind putting temporary properties in your data is the following changes:

对此最简单的解决方法是,如果您不介意在数据中放置临时属性,则需要进行以下更改:

<div ng-show="product.show">
   {{product.type}}
</div>

and

<div ng-show="brand.show">
   {{brand.type}}
</div>

and then in your controller

然后在你的控制器中

$scope.showType = function(item) {
    item.show = !item.show;
  }

Alternatively, if you don't want to touch the object properties, you can create an $scope.shownTypes array and have your click either push the object into or remove the object from the shown array. THen you can check for the object's existence in the array and show or not show the type appropriately. Let me know if you need a sample of that.

或者,如果您不想触摸对象属性,则可以创建$ scope.shownTypes数组,然后单击将对象推入或从显示的数组中删除对象。然后,您可以检查对象在数组中是否存在,并显示或不显示相应的类型。如果你需要一个样本,请告诉我。

#3


0  

Your show boolean attribute same for whole tree (is in same scope). Using angular directive with child scope scope:true in ng-repeat helps to isolate each show property. I have forked your plunker code:

整个树的show boolean属性相同(在同一范围内)。使用带有子范围范围的angular指令:ng-repeat中的true有助于隔离每个show属性。我已经分叉你的plunker代码:

http://plnkr.co/edit/cMSvyfeCQOnTKG8F4l55?p=preview