将子作用域的数据用于父作用域的 ng-repeat(英语:gram)



更新2添加,见下文

首先,这是我正在使用(并且需要修复)的框架的起点:

// index.html
<!doctype html>
<html ng-app="myApp">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
  <script src="index.js"></script>
  <body>
    <div ng-controller="outerController">
      <div id="copy"></div>
      <hr>
      <div id="src" ng-controller="innerController">
        <table>
          <th>Name</th>
          <th>Type</th>
          <tbody>
            <tr ng-repeat="poke in pokemon">
              <td>{{ poke.name }}</td>
              <td>{{ poke.type }}</td>
            </tr>
            <tr>
              <td>Pikachu</td>
              <td>Electric</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </body>
</html>
// index.js
var app = angular.module("myApp", []);
app.controller("innerController", function($scope) {
  $scope.pokemon = [{
    name: "Bulbasaur",
    type: "Grass/Poison"
  }, {
    name: "Charmander",
    type: "Fire"
  }, {
    name: "Squirtle",
    type: "Water"
  }];
});
app.controller("outerController", function($scope) {
  $("#copy").html($("#src").html());
});
因此,正如您所看到的,子控制器将通过ng-repeat从其作用域的数据生成一个表。这一步成功。下一步是父控制器复制粘贴内部HTML从srccopy。目的是让copysrc中包含一个完全由angularJS生成的完整表的副本。

此步骤失败。只有表头和静态皮卡丘行是可见的。在做了一些研究之后,我确信这是因为pokemon在父控制器无法访问的子控制器范围内。复制到copy容器中的HTML包含了整个ng-repeat指令。这个复制的指令在父作用域内,其中$scope.pokemon不存在/不包含任何数据,这就是为什么copy中的ng-repeat没有生成任何内容。

我不能把数据放在父控制器中。在我的实际应用中,系统采用了模块化设计。每个内部控制器代表一个模块,它从服务器提取自己的一组数据。有多个与模块有多对多关系的网页(由外部控制器表示),每个网页中的模块组成需要修改。这意味着模块所使用的数据必须包含在其自身中。

我该如何纠正这个问题?

Update 1:已编辑。我发布了一个使用$emit$on的例子,但罗伯特的例子应该被认为是正确的,因为我对这个还很陌生。参考他的回答

更新2:在测试Alvaro Vazquez的&罗伯特的解决方案,我已经确定了具体的根本原因。当$("#copy").html($("#src").html());被执行时,要么复制的ng-repeat在任何数据传输到outerController之前执行,要么它从未被执行。最后,修改我最初上面所做的使其完全工作:

var app = angular.module("myApp", []);
$(function() {
  $("#copy").html($("#src").html());
});
app.controller("innerController", function($scope) {
  $scope.pokemon = [{
    name: "Bulbasaur",
    type: "Grass/Poison"
  }, {
    name: "Charmander",
    type: "Fire"
  }, {
    name: "Squirtle",
    type: "Water"
  }];
});
app.controller("outerController", function($scope) {
  $scope.pokemon = [{
    name: "Bulbasaur",
    type: "Grass/Poison"
  }, {
    name: "Charmander",
    type: "Fire"
  }, {
    name: "Squirtle",
    type: "Water"
  }];
});

改变了特定语句的位置后,剩下的就是将数据传输到outerController,此时Alvaro和Robert的解决方案都有效。

作为题外话,我认为有些人建议不要使用$("#copy").html($("#src").html());。正如我在评论中部分描述的那样,我正在开发的实际应用程序由多个网页组成,每个网页都包含自己的outerController。每个innerController都在自己单独的HTML文件中,通过include指令添加到src中。outerController复制src的内部HTML,将其传递给第三方库,第三方库将其粘贴到copy中并控制其视觉布局。$("#copy").html($("#src").html());实际上是第三方库实现的一部分,所以我不能改变它。因此,使用这个语句是必需的。

当我回到家,有了电脑键盘的便利,我会把上面的解决方案贴出来。同时,如果你有更好的解决方案,请随时推荐,谢谢!

我认为你应该利用angular的服务。

声明服务

首先,你应该声明一个服务,它将为应用程序的其余部分"提供"数据。为了简单起见,我将只展示一个返回预定义数组的方法,但是您可以在这里从服务器获取数据。

app.service('pokemonService', function () {
    return {
        getPokemon: function () {
            return [{
                  name: "Bulbasaur",
                  type: "Grass/Poison"
              }, {
                  name: "Charmander",
                  type: "Fire"
              }, {
                  name: "Squirtle",
                  type: "Water"
              }];
        }
    };
});

在控制器中使用服务

然后,你可以在任何控制器上使用该服务,把它像其他预定义的angular服务一样注入:

app.controller('innerController', function($scope, pokemonService) {
    $scope.pokemon = pokemonService.getPokemon();
});
app.controller('outerController', function($scope, pokemonService) {
    $scope.outerPokemon = pokemonService.getPokemon();
});

显示视图中的数据

最后,你可以在你想要的模板的任何模板/部分中列出所有的poksammon:

<!doctype html>
<html ng-app="myApp">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
  <script src="index.js"></script>
  <body>
    <div ng-controller="outerController">
      <div id="copy">
          <!-- Here you can also list the pokémon from your outerController, maybe this time in a list -->
          <ul>
              <li ng-repeat="poke in pokemonOuter">
                  {{ poke.name }} - <span class="type">{{ poke.type }}</span>
              </li>
          </ul>
      </div>
      <hr>
      <div id="src" ng-controller="innerController">
        <table>
          <th>Name</th>
          <th>Type</th>
          <tbody>
            <tr ng-repeat="poke in pokemon">
              <td>{{ poke.name }}</td>
              <td>{{ poke.type }}</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </body>
</html>

结束

正如您所看到的,根本不需要乱弄DOM。如果你使用AngularJS,你应该用Angular的方式做事,而直接使用DOM根本不是Angular的方式。相反,您应该将所有数据和业务逻辑放入服务中,然后在控制器中使用这些服务来检索数据并将其传递给视图。

Angular中的作用域使用原型继承,所以子作用域可以访问父作用域的属性,但父作用域不能访问子控制器的属性。

你可以使用一个服务来共享数据,或者使用$emit来向上发送事件(向上直到根范围)。

我为您创建了一个plnkr,向您展示如何使用emit(您可以在这里找到它)

var app = angular.module("myApp", []);
app.controller("outerController", ['$scope', function($scope) {
  console.log('aici');
  $scope.$on('pokemonEvent', function(event, mass) { console.log(mass); });
}]); 
app.controller("innerController", ['$scope', function($scope) {
  $scope.pokemon = [{
    name: "Bulbasaur",
    type: "Grass/Poison"
  }, {
    name: "Charmander",
    type: "Fire"
  }, {
    name: "Squirtle",
    type: "Water"
  }];
  $scope.$emit('pokemonEvent', $scope.pokemon);
}]);

最新更新