Различные ng-include на одной странице: как отправлять разные переменные каждому?

У меня есть страница в моем приложении AngularJS, в котором я хотел бы включить один и тот же html файл, но с разными переменными. Если я сделаю это в своем главном html:

<div id="div1" ng-include src="partials/toBeIncluded.html onload="var='A'">
<div id="div2" ng-include src="partials/toBeIncluded.html onload="var='B'">

И toBeIncluded.html выглядит как

<div>{{var}}</div>

Оба div будут выглядеть как

<div id="div1"><div>B</div></div>
<div id="div2"><div>B</div></div>

Я предполагаю, что это связано с тем, что тот же самый onload вызывается для al-ng-includes. Итак, как мне отправлять разные переменные для каждого из них?

Ответ 1

Выражение, переданное в onload, оценивается каждый раз при загрузке новой частичной части. В этом случае вы дважды меняете значения var, поэтому к тому времени, когда будут загружены обе частичные данные, текущее значение будет B

Вы хотите передать разные данные каждому частичному/шаблону (при этом базовый html файл будет таким же). Чтобы достичь этого, как упоминает Тиаго, вы можете сделать это с помощью разных контроллеров. Например, рассмотрим следующие

<body ng-controller='MainCtrl'>    
  <div ng-include src='"toBeIncluded.html"' ng-controller='ctrlA' onload="hi()"></div>
  <div ng-include src='"toBeIncluded.html"' ng-controller='ctrlB' onload="hi()"></div>
</body>

Здесь у нас есть две частичные части, каждая из которых имеет свою собственную область действия, управляемую их собственным контроллером (ctrlA и ctrlB), как для дочерних областей MainCtrl. Функция hi() принадлежит области MainCtrl и будет выполняться дважды.

Если у нас есть следующие контроллеры

app.controller('MainCtrl', function($scope) {
  $scope.msg = "Hello from main controller";
  $scope.hi= function(){console.log('hi');};
});

app.controller('ctrlA', function($scope) {
  $scope.v = "Hello from controller A";
});

app.controller('ctrlB', function($scope) {
  $scope.v = "Hello from controller B";
});

И содержимое toBeIncluded.html

<p>value of msg = {{msg}}</p>
<p>value of v = {{v}} </p>

Получаемый html будет состоять из следующих строк

<p>value of msg = Hello from main controller</p>
<p>value of v = Hello from main controller A </p>

и

<p>value of msg = Hello from main controller</p>
<p>value of v = Hello from controller B </p>

Пример здесь: http://plnkr.co/edit/xeloFM?p=preview

Ответ 2

Точно так же, как сказал Марк, но чтобы немного упростить его и сделать более "на лету", нужно использовать следующее:

<div ng-repeat="name in ['John']" ng-include="'name-template.html'"></div>
<div ng-repeat="name in ['Jack']" ng-include="'name-template.html'"></div>

<script type="text/ng-template" id="name-template.html">
   <div>The name is {{ name }}</div>
<script>

Пример здесь: http://jsfiddle.net/Cndc6/4/

Ответ 3

В своем комментарии к @jm- answer вы указываете, что хотите загрузить частичный внутри ng-repeat. Для этого создайте массив в своей области $scope и задайте уникальные значения в этом массиве:

$scope.partialStuff = [ 'p1', 'p2', 'p3' ];

Где-то в частичном:

{{partialVar}}

HTML:

<div ng-repeat="partialVar in partialStuff">
   <div ng-include src="'partials/toBeIncluded.html'"></div>
</div>

Fiddle.

Ответ 4

Я мог ошибаться, но лучше ли было бы использовать директиву?

.directive('foobar', [function factory() {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: '/toBeIncluded.html',
        scope: {
            "var": "="
        }
    };
}]);

И ваш HTML

<div ng-repeat="var in data">
    <foobar var="var"></foobar>
</div>

Теперь элемент foobar должен быть заменен вашим шаблоном. Каждый из них имеет свой собственный охват.

Ответ 5

В частности, выражения ng-init и onload оцениваются в области parent, а не в области дочерних объектов, созданной nginclude. Таким образом, вы дважды назначаете значения var в родительской области, оба из которых происходят до того, как содержимое внутри этих ng-включений загружается скомпилированным и оцененным. Когда создается каждая дочерняя область, она наследует родительскую область, где var = 'B'.

Ответ 6

считают, что у вас есть переменная foo внутри вашего частичного,

то вы пройдете foo следующим образом:

<ng-include src="'partials/foo-part.html'" onLoad="foo='bar'"></ng-include>

для большей совместимости с браузером вы можете передать это следующим образом:

<div ng-include src="'partials/foo-part.html'" onLoad="foo='bar'"></div>

вы также можете использовать onInclude="foo='bar'" вместо onLoad

plnkr.co/edit/GHRNyAMBKLvgtf3NFSRu?p=info

Ответ 7

Тот же "onLoad" не вызывается для всех ng-includes. Скорее всего, var установлен в A, а затем на B. Дело в том, что он разделяется между обоими включениями, потому что они находятся в одной области. 'var ', как модель в угловом JS, зависит от объема.

Чтобы ваши частичные части имели отдельные значения, у каждого из них должны быть свои собственные области. Самый простой способ сделать это можно было бы установить контроллер или директиву и назначить его элементу Dom, где находится ng-include, и установить значение в пределах этой области.

Ответ 8

У меня была такая же проблема, и я нашел способ добиться того, что хотел конечно, это выглядит не очень красиво, но все же.

Я использовал ng-repeat, который создаст новую область для включения одного и того же шаблона дважды с разными значениями, подобными этому (фиктивный пример):

<script type="text/ng-template" id="mod-edito.html">
<div class="mod-edito__media">
    <img ng-src="{{ edito.cover.src }}" />
</div>
</script>

<div>
    <ng-include ng-repeat="edito in [edito_object]" src="'mod-edito.html'"></ng-include>
    ...
    <ng-include ng-repeat="edito in [edito_other]" src="'mod-edito.html'"></ng-include>
</div>

Это приемлемо? Я так думаю.

Ответ 9

Я искал альтернативу, я хотел, чтобы объект js отправил несколько параметров во включенную часть. Это развитая версия того, что сделал @denis-pshenov. Вы можете использовать контроллер для заполнения данных или ng-init.

В принципе, что-то вроде этого,

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

myApp.controller('Controller', function($scope) {
    $scope.ourData = [ { name : 'John', address : 'Paradise' } ];
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="Controller">
    <div ng-repeat="data in ourData" ng-include="'partial.html'"></div>
    
    <div ng-init="ourData2 = [ { name : 'Jack', address : 'Paradise' } ]" />
    <div ng-repeat="data in ourData2" ng-include="'partial.html'"></div>
    
</div>

<script type="text/ng-template" id="partial.html">
   <div>The name is {{ data.name }} and the address is {{ data.address }} </div>
</script>

Ответ 10

Существует способ создания универсальной директивы многократного использования.

Вот что мой коллега придумал (вдохновленный Knockout.js).

Директива

(function () {
    'use strict';

    angular
        .module('directives')
        .directive('ngWith', ngWith);

    function ngWith() {
        return {
            restrict: 'A',
            replace: true,
            scope: {
                model: '=',
                template: '@'
            },
            template: '<div data-ng-include="template"></div>',
        };
    }
})();

Использование:

<div data-ng-with="" data-model="parentObj.childObj.whatEver" data-template='my-template.html'></div>

Ответ 11

Просто голова, если вы включите частичное в ng-repeat, вы все равно можете получить доступ к родительскому объекту $index. Просто включите {{$ index}} в частичное.

Ответ 12

Использование onload не является чистым решением, поскольку оно помещает глобальную область. Если у вас есть что-то более сложное, оно начнет сбой.

Использование новой директивы вместо ng-include является более чистым решением.

Идеальное использование выглядит следующим образом:

<div ng-include-template="partials/toBeIncluded.html" ng-include-variables="{ var: 'A' }"></div>
<div ng-include-template="partials/toBeIncluded.html" ng-include-variables="{ var: 'B' }"></div>

Директива:

.directive(
  'ngIncludeTemplate'
  () ->
    {
      templateUrl: (elem, attrs) -> attrs.ngIncludeTemplate
      restrict: 'A'
      scope: {
        'ngIncludeVariables': '&'
      }
      link: (scope, elem, attrs) ->
        vars = scope.ngIncludeVariables()
        for key, value of vars
          scope[key] = value
    }
)

Вы можете видеть, что директива не использует глобальную область действия. Вместо этого он считывает объект из ng-include-variables и добавляет эти члены в свою собственную локальную область.

ng-include не является повторным, поскольку он имеет доступ к глобальной области. Это немного странно.

Надеюсь, это то, что вам хотелось бы; он чистый и общий.

Ответ 13

Вы можете обратиться к функциям одиночных значений типа $scope.a = 'test' и для объектов типа $scope.a = {a.test}; и использовать разную область для определения области видимости.

Из документации ng-if.

Обратите внимание, что при удалении элемента с помощью ngIf его область уничтожается и создается новая область, когда элемент восстанавливается.

Решение Simpe состоит в том, чтобы включить ng-if и определить статическую контентификацию в директиве ng-init.

<div ng-if="<any-true-expression>" ng-init="val='First'" ng-include="'html/common.html'"</div>

<div ng-if="<any-true-expression>" ng-init="val='Second'" ng-include="'html/common.html'"</div>

В этом случае он будет отображаться с различными значениями, например

{{val}} shows >>
First
Second

Этот контент является статическим, поскольку val является ссылкой simpe на значение.

Если вы хотите иметь динамически изменяемые страницы, которые зависят от некоторых общих значений области, вам необходимо уничтожить и воссоздать область действия, созданную при использовании директивы ng-if. Вот так:

<div id="wrapper" ng-if="orders_client">
       <div id="client-orders" ng-init="orders = orders_client" ng-include="'html/pages/parts/orders-view.html'"></div>
</div>

и

$scope.orders_client = null;
   /*recreate content table*/
     $timeout(function () {
        $rootScope.general.showPreloader = false;
        $scope.orders_client = $scope.baseData.clients[newClient];
     }, 500);

В этом случае область с ранее данными будет уничтожена, и будет создана новая область с новыми данными. Необходимо время для воссоздания новой области 500 мс. Пожалуйста, напишите, если существует какой-то лучший улов.

Ответ 14

Просто поместите каждый ng-include под свой собственный <div> следующим образом:

<div>
  <div id="div1" ng-include src="partials/toBeIncluded.html onload="var='A'"/>
</div>
<div>
  <div id="div2" ng-include src="partials/toBeIncluded.html onload="var='B'"/>
</div>

Каждый включенный HTML будет иметь свой собственный var в своей области.