将子范围的数据用于父范围&n重复

时间:2016-09-06 13:37:00

标签: javascript jquery angularjs

添加了更新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从src复制粘贴到copy。意图是copy包含由src内的angularJS完全生成的完整表的副本。

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

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

我该如何纠正这个?

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

更新2 :在测试Alvaro Vazquez&amp; amp;&amp;罗伯特的解决方案,我已经确定了具体的根本原因。执行$("#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());实际上是第三方图书馆实施的一部分,所以我无法改变这一点。因此,使用此声明是必需的。

当我回到家中并且具有PC键盘的便利性时,我会将上述内容作为解决方案发布。在此期间,如果你有一个,可以随意推荐更好的解决方案,谢谢!

2 个答案:

答案 0 :(得分:2)

我认为你应该使用角度服务。

声明服务

首先,您应该声明一个服务,该服务将“提供”给您应用程序的其余部分的数据。为简单起见,我只会显示一个返回预定义数组的方法,但您可以在此处从服务器获取数据。

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

使用控制器中的服务

然后,您可以在任何控制器上使用该服务,将其作为任何其他预定义的角度服务注入:

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

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

在视图中显示数据

最后,您可以在所需模板的任何模板/部分中列出所有神奇宝贝:

<!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方式。相反,您应该将所有数据和业务逻辑放入服务中,然后在控制器中使用这些服务来检索该数据并将其传递给视图。

答案 1 :(得分:0)

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

您可以使用服务共享数据或使用$ emit向上发送事件(向上直到根范围)。

我为你创建了一个plnkr来向你展示如何使用emit(你可以找到它here

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);
}]);