Я написал настраиваемую управляющую директиву, которая обертывает существующие представления в контейнер, который допускает другую директиву, называемую кнопкой collapser, которая по существу пытается скрыть контейнер, предоставленный директивой сбрасывания.
разборный
myApp.directive('collapsable', [
'$compile',
function ($compile) {
return {
scope: {
screenId: '@'
},
restrict: 'E',
controller: [
'$scope',
function ($scope) {
var self = {};
self.GetContainer = function (innerHtml) {
console.log(innerHtml);
var html = "<div id='" + $scope.id + "'>" + innerHtml + "</div>";
return html;
};
self.DoCallBack = function (targetContainerId) {
var container = $('#' + targetContainerId);
if (container.length > 0) {
container.hide("slow");
}
}
// --- //
$scope.GetContainer = self.GetContainer;
$scope.reference = {
doCallBack: self.DoCallBack, // This is a function parameter, DONT use () !!!
screenId: $scope.screenId
}
}
],
link: function ($scope, $elem, $attrs) {
var html = $scope.GetContainer($elem.html());
var linkFn = $compile(html);
var content = linkFn($scope);
$elem.html(content);
}
}
}
]);
CollapserButton
myApp.directive('collapserButton', [
'$compile',
function ($compile) {
return {
restrict: 'E',
scope: {
parent: '='
},
transclude: true,
controller: [
'$scope',
function ($scope) {
var self = {};
self.HandleButtonClick = function () {
$scope.parent.doCallBack($scope.parent.screenId);
}
// --- SCOPE --- //
$scope.HandleButtonClick = self.HandleButtonClick;
}],
link: function($scope, $elem, $attrs) {
var html = '<button class="btn btn-primary" ng-click="HandleButtonClick()">Collapse</button>';
var linkFn = $compile(html);
var content = linkFn($scope);
$elem.html(content);
}
}
}]);
Применение
<collapsable screenid="screen1">
...
...
...
<collapser-button parent="reference"/>
</collapsable>
Это работает в статической тестовой настройке, теперь я хочу применить ее к реальной работе:
У меня есть (одна страница), которая содержит следующее:
<div ng-controller="personController">
<table>
<thead>
<tr>
<th style="width: 33%" translate>Firstname</th>
<th style="width: 33%" translate>Firstname2</th>
<th style="width: 34%" translate>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="person in people">
<td>{{ person.Firstname }}</td>
<td>{{ person.Firstname2 }}</td>
<td>{{ person.Name }}</td>
</tr>
</tbody>
</table>
</div>
Это само по себе прекрасно работает, однако, если я обернуваю вокруг него сворачиваемую директиву, то переводы и ng-повторитель больше не работают.
Возможно, вы заметили, что функция GetContainer для "collapsable" регистрирует innerHtml для консоли, для текущей настройки, которая возвращает эту информацию:
<div ng-controller="personController" class="ng-scope">
<table>
<thead>
<tr>
<th style="width: 33%" translate="" class="ng-scope">Firstname</th>
<th style="width: 33%" translate="" class="ng-scope">Firstname2</th>
<th style="width: 34%" translate="" class="ng-scope">Name</th>
</tr>
</thead>
<tbody>
<!-- ngRepeat: persoon in personen -->
</tbody>
</table>
</div>
Любые идеи о том, как объяснить/исправить это?
Обновить
Это становится очень странным, если я добавлю несуществующую функцию в мою сворачиваемую директивную ссылку, ng-repeat отображается правильно:
link: function($scope, $elem, $attrs) {
var html = '<button class="btn btn-primary" ng-click="HandleButtonClick()">Collapse</button>';
var linkFn = $compile(html);
var content = linkFn($scope);
FunctionThatDoesNotExist();
$elem.html(content);
}
Как я уже сказал, он корректно отображен, но это не значит, что он исправлен, потому что родительская ссылка кнопки collapser не определена, хотя она правильно определена в родительской сворачиваемой директиве.
Я думаю, что действие $ compile не работает на 100%, т.е. не все Угловая логика активирована.
Plunkr
Если я поставлю первый комментарий Blah() (в script.js, строка 76) в комментарии, я получаю [[object HTMLDivElement]]:
link: function ($scope, $elem, $attrs) {
var html = $scope.GetContainer($elem.html());
var linkFn = $compile(html);
var content = linkFn($scope);
//Blah();
$elem.html(content);
}
У вас есть несколько ошибок, и в большинстве случаев с угловым вы не нуждаетесь в ручном манипулировании с DOM.
Итак, во-первых, вы используете неправильный метод html
. angular.element - это элемент jqLite
, который реализует несколько методов из jQuery, поэтому element.html
аналогичен jQuery.html, так что, как вы можете видеть, вы можете передать ему только строку или функцию
.html( htmlString )
.html( function )
но вы пытаетесь передать элемент pass-html, и он неявно преобразуется в строку и показывает [[object HTMLDivElement]]
Вам также не нужно получать контент и вручную добавлять его, потому что встроенный transclude
может сделать это автоматически, вы должны просто добавить шаблон.
Кроме того, вам не нужна ссылка collapserButton
на родительскую, потому что вы можете получить необходимое значение от родительского контроллера напрямую.
Итак, ваши процедуры могут быть сведены к чему-то подобному
angular.module('ngApp', [])
.directive('collapsable', [
'$compile',
function($compile) {
return {
scope: {
screenId: '@'
},
restrict: 'E',
transclude: true,
template: '<div id="{{screenId}}"><ng-transclude></ng-transclude></div>',
controller: function($scope) {
this.DoCallBack = function(targetContainerId) {
var container = $('#' + targetContainerId);
if (container.length > 0) {
container.hide("slow");
}
}
// --- //
this.screenId = $scope.screenId;
}
}
}
])
.directive('collapserButton', [
'$compile',
function($compile) {
return {
restrict: 'E',
require: '^?collapsable',
template: '<button class="btn btn-primary" ng-click="HandleButtonClick()">Collapse</button>',
link: function($scope, $elem, $attrs, $ctrl) {
$scope.HandleButtonClick = function() {
$ctrl.DoCallBack($ctrl.screenId);
}
}
}
}
])
.controller('ngAppController', function($scope) {
var self = {};
self.people = [{
"Firstname": "Jack",
"Firstname2": "William",
"Name": "Sparrow",
}, {
"Firstname": "Charles",
"Firstname2": "Foster",
"Name": "Kane",
}, {
"Firstname": "Hannibal",
"Firstname2": "",
"Name": "Lecter",
}];
// --- //
$scope.people = self.people;
$scope.a = 1;
$scope.b = 2;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<div ng-app="ngApp">
<collapsable screen-id="screen1">
<div ng-controller="ngAppController">
<table style="width: 300px">
<thead>
<tr>
<th style="width: 33%">Firstname</th>
<th style="width: 33%">Firstname2</th>
<th style="width: 34%">Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="person in people">
<td>{{ person.Firstname }}</td>
<td>{{ person.Firstname2 }}</td>
<td>{{ person.Name }}</td>
</tr>
</tbody>
</table>
</div>
<collapser-button parent-reference="reference"></collapser-button>
</collapsable>
</div>
образец с ng-hide
и без анимации
angular.module('ngApp', [])
.directive('collapsable', [
'$compile',
function($compile) {
return {
scope: {
screenId: '@'
},
restrict: 'E',
transclude: true,
template: '<div id="{{screenId}}" ng-hide="hide"><ng-transclude></ng-transclude></div>',
controller: function($scope) {
this.DoCallBack = function(targetContainerId) {
$scope.hide = true;
}
// --- //
this.screenId = $scope.screenId;
}
}
}
])
.directive('collapserButton', [
'$compile',
function($compile) {
return {
restrict: 'E',
require: '^?collapsable',
template: '<button class="btn btn-primary" ng-click="HandleButtonClick()">Collapse</button>',
link: function($scope, $elem, $attrs, $ctrl) {
$scope.HandleButtonClick = function() {
$ctrl.DoCallBack($ctrl.screenId);
}
}
}
}
])
.controller('ngAppController', function($scope) {
var self = {};
self.people = [{
"Firstname": "Jack",
"Firstname2": "William",
"Name": "Sparrow",
}, {
"Firstname": "Charles",
"Firstname2": "Foster",
"Name": "Kane",
}, {
"Firstname": "Hannibal",
"Firstname2": "",
"Name": "Lecter",
}];
// --- //
$scope.people = self.people;
$scope.a = 1;
$scope.b = 2;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<div ng-app="ngApp">
<collapsable screen-id="screen1">
<div ng-controller="ngAppController">
<table style="width: 300px">
<thead>
<tr>
<th style="width: 33%">Firstname</th>
<th style="width: 33%">Firstname2</th>
<th style="width: 34%">Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="person in people">
<td>{{ person.Firstname }}</td>
<td>{{ person.Firstname2 }}</td>
<td>{{ person.Name }}</td>
</tr>
</tbody>
</table>
</div>
<collapser-button parent-reference="reference"></collapser-button>
</collapsable>
</div>