Angular 追加父属性值
Angular appends parent attribute value
我有这样的分层数据:
[
{
"children":[
{
"children":[...],
[...]
},
{
"children":[...],
[...]
},
],
[...]
}
]
我想通过展平该数据来构建树状网格。我正在使用以下指令:
app.directive('tree', function (hierarchyService, logger, $timeout) {
return {
scope: {
data: '='
},
restrict: 'E',
replace: true,
template: '<div>' +
'<table class="table table-striped table-hover">' +
' <thead>' +
' <tr>' +
' <th class="col-md-6">Account name</th>' +
' </tr>' +
' </thead>' +
' <tbody><tr collection data="data" /></tbody>' +
' </table>' +
'</div>'
};
});
app.directive('collection', function() {
return {
restrict: "A",
replace: true,
scope: {
data: '=',
depth: '@'
},
template: '<member ng-repeat="member in data" member="member" depth="{{depth}}" />',
link: function (scope, element, attrs) {
scope.depth = parseInt(scope.depth || 0);
}
}
});
app.directive('member', function($compile) {
return {
restrict: "E",
replace: true,
scope: {
depth: '@',
member: '='
},
template: '<tr ng-class="{selected: member.selected}">' +
'<td>' +
' <span ng-show="depth > 0" style="width: {{depth * 16}}px; display: inline-block;"></span> {{member.name}}' +
'</td>' +
'</tr>',
link: function (scope, element, attrs) {
scope.depth = parseInt(scope.depth || 0);
if (angular.isArray(scope.member.children) && scope.member.children.length > 0) {
var el = angular.element('<tr collection data="member.children" depth="{{newDepth}}" />');
scope.depth = parseInt(scope.depth || 0);
scope.newDepth = scope.depth + 1;
$compile(el)(scope);
// Flatten hierarchy, by appending el to parent
element.parent().append(el);
}
}
}
});
问题是,在从 link
方法添加的集合中,父范围的 depth
附加到 newDepth
。结果,级别 3 节点的 depth
的值为 depth="3 2 1 "
.
如何禁用 depth
的继承?
我还注意到,当我在 collection
和 member
指令中将 replace
更改为 false 时,深度按预期工作,但 HTML 无效。
有时更简单的解决方案更好。最好将服务中的树状结构展平,然后使用 ng-repeat 迭代新结构。 https://plnkr.co/edit/CiFGZYi6NdH8ZFDiAyPz?p=preview
代码更简单。不需要所有那些难以理解的指令。此外,您不应该使用 replace with 指令,因为它是 deprecated.
要动态设置样式,您应该使用 ng-style 指令。
var app = angular.module('app', []);
app.factory('treeFlatting', function () {
function flattenTree(tree, depth) {
depth = depth || 0;
return tree.reduce(function (rows, node) {
var row = {
name: node.name,
depth: depth,
};
var childrenRows = angular.isArray(node.children) ?
flattenTree(node.children, depth + 1) : [];
return rows.concat(row, childrenRows);
}, []);
}
return flattenTree;
});
app.directive('tree', function (treeFlatting) {
return {
restrict: 'E',
replace: true,
template: '<div>' +
'<table class="table table-striped table-hover">' +
' <thead>' +
' <tr>' +
' <th class="col-md-6">Account name</th>' +
' <th class="col-md-1">Depth</th>' +
' </tr>' +
' </thead>' +
' <tbody>'+
' <tr ng-repeat="row in rows">'+
' <td ng-style="{\'padding-left\': (16 * row.depth) + \'px\'}">{{row.name}}</td>'+
' <td>{{row.depth}}</td>'+
' </tr>'+
' </tbody>' +
' </table>' +
'</div>',
link: function (scope, element, attrs) {
scope.data = [
{
name: 'Root',
children: [
{
name: 'Level 1',
children: [
{
name: 'Level 2'
}
]
}
]
}
];
scope.rows = treeFlatting(scope.data).filter(function (row) {
return row.depth > 0;
});
}
};
});
看来,对 child 个节点使用相同的范围会导致这种奇怪的连接。解决这个问题非常简单,事实证明 - 每个 child 都需要新的 child 作用域。 Link 函数将如下所示:
link: function (scope, element, attrs) {
if (angular.isArray(scope.member.children) && scope.member.children.length > 0) {
// Create isolated child scope, pass `scope` as parent
var childScope = scope.$new(true, scope);
childScope.depth = parseInt(scope.depth || 0) + 1;
childScope.member = scope.member;
var el = angular.element('<tr collection data="member.children" depth="{{depth}}" />');
// use child scope
$compile(el)(childScope);
// Flatten hierarchy, by appending el to parent
element.after(el);
}
}
笨蛋:https://plnkr.co/edit/xhJwfV?p=preview
我还在 SO 和 API 的其他地方发现 replace
已被弃用,因此实际上不应使用它。所以如果不替换它可以看起来像这样:
app.directive('tree', function () {
return {
restrict: 'E',
template: '<div>' +
'<table class="table table-striped table-hover">' +
' <thead>' +
' <tr>' +
' <th class="col-md-6">Account name</th>' +
' <th class="col-md-1">Depth</th>' +
' </tr>' +
' </thead>' +
' <tbody row data="data"></tbody>' +
' </table>' +
'</div>',
link: function (scope, element, attrs) {
scope.data = [
{
name: 'Root',
children: [
{
name: 'Level 1',
children: [
{
name: 'Level 2',
children: [
{name: "Level 3"},
{name: "Level 3 -1"}
]
}
]
},
{
"name": "Level 1-1"
}
]
}
];
}
};
});
app.directive('row', function() {
return {
restrict: "A",
scope: {
data: '=',
depth: '@'
},
template: '<tr cells ng-repeat="member in data" member="member" />',
link: function (scope, element, attrs) {
scope.depth = parseInt(scope.depth || 0);
}
}
});
app.directive('cells', function($compile) {
return {
restrict: "A",
scope: {
data: '=',
depth: '@',
member: '='
},
template: //'<tr ng-class="{selected: member.selected}">' +
'<td>' +
' <span ng-show="depth > 0" style="width: {{depth * 16}}px; display: inline-block;"></span> {{member.name}}' +
'</td>' +
'<td>{{depth}}</td>',
//'</tr>',
link: function (scope, element, attrs) {
if (scope.member && angular.isArray(scope.member.children) && scope.member.children.length > 0) {
var childScope = scope.$new(true);
childScope.depth = parseInt(scope.depth || 0) + 1;
childScope.data = scope.member.children;
var el = angular.element('<tr cells ng-repeat="member in data" member="member" depth="{{depth}}" />');
$compile(el)(childScope);
// Flatten hierarchy, by appending el to parent
element.after(el);
}
}
}
});
我有这样的分层数据:
[
{
"children":[
{
"children":[...],
[...]
},
{
"children":[...],
[...]
},
],
[...]
}
]
我想通过展平该数据来构建树状网格。我正在使用以下指令:
app.directive('tree', function (hierarchyService, logger, $timeout) {
return {
scope: {
data: '='
},
restrict: 'E',
replace: true,
template: '<div>' +
'<table class="table table-striped table-hover">' +
' <thead>' +
' <tr>' +
' <th class="col-md-6">Account name</th>' +
' </tr>' +
' </thead>' +
' <tbody><tr collection data="data" /></tbody>' +
' </table>' +
'</div>'
};
});
app.directive('collection', function() {
return {
restrict: "A",
replace: true,
scope: {
data: '=',
depth: '@'
},
template: '<member ng-repeat="member in data" member="member" depth="{{depth}}" />',
link: function (scope, element, attrs) {
scope.depth = parseInt(scope.depth || 0);
}
}
});
app.directive('member', function($compile) {
return {
restrict: "E",
replace: true,
scope: {
depth: '@',
member: '='
},
template: '<tr ng-class="{selected: member.selected}">' +
'<td>' +
' <span ng-show="depth > 0" style="width: {{depth * 16}}px; display: inline-block;"></span> {{member.name}}' +
'</td>' +
'</tr>',
link: function (scope, element, attrs) {
scope.depth = parseInt(scope.depth || 0);
if (angular.isArray(scope.member.children) && scope.member.children.length > 0) {
var el = angular.element('<tr collection data="member.children" depth="{{newDepth}}" />');
scope.depth = parseInt(scope.depth || 0);
scope.newDepth = scope.depth + 1;
$compile(el)(scope);
// Flatten hierarchy, by appending el to parent
element.parent().append(el);
}
}
}
});
问题是,在从 link
方法添加的集合中,父范围的 depth
附加到 newDepth
。结果,级别 3 节点的 depth
的值为 depth="3 2 1 "
.
如何禁用 depth
的继承?
我还注意到,当我在 collection
和 member
指令中将 replace
更改为 false 时,深度按预期工作,但 HTML 无效。
有时更简单的解决方案更好。最好将服务中的树状结构展平,然后使用 ng-repeat 迭代新结构。 https://plnkr.co/edit/CiFGZYi6NdH8ZFDiAyPz?p=preview
代码更简单。不需要所有那些难以理解的指令。此外,您不应该使用 replace with 指令,因为它是 deprecated.
要动态设置样式,您应该使用 ng-style 指令。
var app = angular.module('app', []);
app.factory('treeFlatting', function () {
function flattenTree(tree, depth) {
depth = depth || 0;
return tree.reduce(function (rows, node) {
var row = {
name: node.name,
depth: depth,
};
var childrenRows = angular.isArray(node.children) ?
flattenTree(node.children, depth + 1) : [];
return rows.concat(row, childrenRows);
}, []);
}
return flattenTree;
});
app.directive('tree', function (treeFlatting) {
return {
restrict: 'E',
replace: true,
template: '<div>' +
'<table class="table table-striped table-hover">' +
' <thead>' +
' <tr>' +
' <th class="col-md-6">Account name</th>' +
' <th class="col-md-1">Depth</th>' +
' </tr>' +
' </thead>' +
' <tbody>'+
' <tr ng-repeat="row in rows">'+
' <td ng-style="{\'padding-left\': (16 * row.depth) + \'px\'}">{{row.name}}</td>'+
' <td>{{row.depth}}</td>'+
' </tr>'+
' </tbody>' +
' </table>' +
'</div>',
link: function (scope, element, attrs) {
scope.data = [
{
name: 'Root',
children: [
{
name: 'Level 1',
children: [
{
name: 'Level 2'
}
]
}
]
}
];
scope.rows = treeFlatting(scope.data).filter(function (row) {
return row.depth > 0;
});
}
};
});
看来,对 child 个节点使用相同的范围会导致这种奇怪的连接。解决这个问题非常简单,事实证明 - 每个 child 都需要新的 child 作用域。 Link 函数将如下所示:
link: function (scope, element, attrs) {
if (angular.isArray(scope.member.children) && scope.member.children.length > 0) {
// Create isolated child scope, pass `scope` as parent
var childScope = scope.$new(true, scope);
childScope.depth = parseInt(scope.depth || 0) + 1;
childScope.member = scope.member;
var el = angular.element('<tr collection data="member.children" depth="{{depth}}" />');
// use child scope
$compile(el)(childScope);
// Flatten hierarchy, by appending el to parent
element.after(el);
}
}
笨蛋:https://plnkr.co/edit/xhJwfV?p=preview
我还在 SO 和 API 的其他地方发现 replace
已被弃用,因此实际上不应使用它。所以如果不替换它可以看起来像这样:
app.directive('tree', function () {
return {
restrict: 'E',
template: '<div>' +
'<table class="table table-striped table-hover">' +
' <thead>' +
' <tr>' +
' <th class="col-md-6">Account name</th>' +
' <th class="col-md-1">Depth</th>' +
' </tr>' +
' </thead>' +
' <tbody row data="data"></tbody>' +
' </table>' +
'</div>',
link: function (scope, element, attrs) {
scope.data = [
{
name: 'Root',
children: [
{
name: 'Level 1',
children: [
{
name: 'Level 2',
children: [
{name: "Level 3"},
{name: "Level 3 -1"}
]
}
]
},
{
"name": "Level 1-1"
}
]
}
];
}
};
});
app.directive('row', function() {
return {
restrict: "A",
scope: {
data: '=',
depth: '@'
},
template: '<tr cells ng-repeat="member in data" member="member" />',
link: function (scope, element, attrs) {
scope.depth = parseInt(scope.depth || 0);
}
}
});
app.directive('cells', function($compile) {
return {
restrict: "A",
scope: {
data: '=',
depth: '@',
member: '='
},
template: //'<tr ng-class="{selected: member.selected}">' +
'<td>' +
' <span ng-show="depth > 0" style="width: {{depth * 16}}px; display: inline-block;"></span> {{member.name}}' +
'</td>' +
'<td>{{depth}}</td>',
//'</tr>',
link: function (scope, element, attrs) {
if (scope.member && angular.isArray(scope.member.children) && scope.member.children.length > 0) {
var childScope = scope.$new(true);
childScope.depth = parseInt(scope.depth || 0) + 1;
childScope.data = scope.member.children;
var el = angular.element('<tr cells ng-repeat="member in data" member="member" depth="{{depth}}" />');
$compile(el)(childScope);
// Flatten hierarchy, by appending el to parent
element.after(el);
}
}
}
});