【问题标题】:Inject variables into ngRepeat将变量注入 ngRepeat
【发布时间】:2016-08-14 22:28:05
【问题描述】:

我有一个递归 ng-repeat 用于创建一个可能有无限子节点的分支思维导图树(运行下面的代码 sn-p 以更好地理解我的意思)。

我的$scope 中有一个remove() 函数,它打算自行删除。但是,要做到这一点,我需要访问父级。我尝试通过使用 ng-init 在名为 parent 的变量中设置父节点来实现这一点。问题是,parent 变量似乎是指节点本身而不是其父节点。如何将父级注入循环?

除了前面提到的$scope.remove()之外的所有东西都在下面的sn-p中工作:

(function(){
	angular
	.module('createTree',[])
	.controller('CreateTreeController', function($scope){
		$scope.tree=[{
			title:'node 1',
			subNodes:[
				{
					title:'node 1.1',
					subNodes:[]
				},
				{
					title:'node 1.2',
					subNodes:[
						{
							title:'node 1.2.1',
							subNodes:[]
						},
						{
							title:'node 1.2.2',
							subNodes:[]
						}
					]
				},
				{
					title:'node 1.3',
					subNodes:[]
				}
			]
		}];
		$scope.addTo=function(node){
			node.subNodes.push({
				title: node.title+"."+(node.subNodes.length+1),
				subNodes:[]
			});
		}
		$scope.remove=function(node,parent){
			var index=parent.subNodes.indexOf(node)
			if(index>-1) parent.subNodes.splice(index,1);
		}
	});
})();
*{
	position: relative;
	box-sizing: border-box;
}

.node{
	padding: 1px 0;
}

.node>.subNodes{
	margin-left: 10px;
}

.node>.subNodes::before{
	content: '';
	display: block;
	width: 5px;
	height: 1px;
	background-color: black;
	position: absolute;
	top: 50%;
	left: -10px;
}
.node>.subNodes::after{
	content:'';
	display: block;
	width: 1px;
	height: 100%;
	background-color: black;
	position: absolute;
	top: 0;
	left: -5px;
	z-index: 1;
}
.node>.subNodes>.node::before{
	content:'';
	display: block;
	width: 5px;
	height: 1px;
	background-color: black;
	position: absolute;
	top: 50%;
	left:-5px;
	z-index: 3;
}

.node>.subNodes>.node:first-child::after{
	content:'';
	display: block;
	width: 1px;
	height: 50%;
	background-color: white;
	position: absolute;
	top: 0;
	left:-5px;
	z-index: 2;
}
.node>.subNodes>.node:last-child:not(:first-child)::after{
	content:'';
	display: block;
	width: 1px;
	height: calc(50% - 1px);
	background-color: white;
	position: absolute;
	bottom: 0;
	left:-5px;
	z-index: 2;
}

.node>.subNodes>.node:only-child::after{
	height: 100%;
}


.node>*{
	display: inline-block;
	vertical-align: middle;
}

.node [type=text]{
	width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
	
<div ng-app="createTree" ng-controller="CreateTreeController as createTree">
	
	<script type="text/ng-template" id="treeNode.html">
		<span>
			<input
				type="button"
				value="x"
				ng-click="remove(node,parent)"
			>
			<a href="#">{{node.title}}</a>, parent: {{parent.title}}
			<input 
				type="button" 
				value="+" 
				ng-click="addTo(node)"
			>
		</span><div class="subNodes" ng-show="node.subNodes.length>0">
			<div 
				class="node" 
				ng-init="parent=node"
				ng-repeat="node in node.subNodes" 
				ng-include="'treeNode.html'"
			></div>
		</div>
	</script>

	<div 
		class="node"
		ng-init="parent=tree"
		ng-repeat="node in tree" 
		ng-include="'treeNode.html'"
	></div>

</div>

【问题讨论】:

  • 范围内只有一个parent 变量。因此,您在每个循环中都会覆盖它。
  • @SimonSchüpbach 我打算将变量设为循环私有 - 我该如何实现?即便如此,为什么打印parent.title 打印节点本身的标题而不是其父节点的标题? ng-init 会在 {{}} 语法中的内容之前执行吗?

标签: javascript angularjs angularjs-ng-repeat angularjs-ng-model


【解决方案1】:

父节点不能是节点,需要为每个节点设置真正的父节点。

我已经解决了

(function(){
	angular
	.module('createTree',[])
	.controller('CreateTreeController', function($scope){
		$scope.tree=[{
			title:'node 1',
            parent: null,
			subNodes:[]
		}];
		$scope.addTo=function(node){
			node.subNodes.push({
				title: node.title+"."+(node.subNodes.length+1),
                parent: node,
				subNodes:[]
			});
		}
		$scope.remove=function(node,parent){
			var index=node.parent.subNodes.indexOf(node)
			if(index>-1 && node.parent != null) node.parent.subNodes.splice(index,1);
		}
	});
})();
*{
	position: relative;
	box-sizing: border-box;
}

.node{
	padding: 1px 0;
}

.node>.subNodes{
	margin-left: 10px;
}

.node>.subNodes::before{
	content: '';
	display: block;
	width: 5px;
	height: 1px;
	background-color: black;
	position: absolute;
	top: 50%;
	left: -10px;
}
.node>.subNodes::after{
	content:'';
	display: block;
	width: 1px;
	height: 100%;
	background-color: black;
	position: absolute;
	top: 0;
	left: -5px;
	z-index: 1;
}
.node>.subNodes>.node::before{
	content:'';
	display: block;
	width: 5px;
	height: 1px;
	background-color: black;
	position: absolute;
	top: 50%;
	left:-5px;
	z-index: 3;
}

.node>.subNodes>.node:first-child::after{
	content:'';
	display: block;
	width: 1px;
	height: 50%;
	background-color: white;
	position: absolute;
	top: 0;
	left:-5px;
	z-index: 2;
}
.node>.subNodes>.node:last-child:not(:first-child)::after{
	content:'';
	display: block;
	width: 1px;
	height: calc(50% - 1px);
	background-color: white;
	position: absolute;
	bottom: 0;
	left:-5px;
	z-index: 2;
}

.node>.subNodes>.node:only-child::after{
	height: 100%;
}


.node>*{
	display: inline-block;
	vertical-align: middle;
}

.node [type=text]{
	width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
	
<div ng-app="createTree" ng-controller="CreateTreeController as createTree">
	
	<script type="text/ng-template" id="treeNode.html">
		<span>
			<input
				type="button"
				value="x"
				ng-click="remove(node)"
			>
			<a href="#">{{node.title}}</a>, parent: {{node.parent.title}}
			<input 
				type="button" 
				value="+" 
				ng-click="addTo(node)"
			>
		</span><div class="subNodes" ng-show="node.subNodes.length>0">
			<div 
				class="node"
				ng-repeat="node in node.subNodes" 
				ng-include="'treeNode.html'"
			></div>
		</div>
	</script>

	<div 
		class="node"
		ng-repeat="node in tree" 
		ng-include="'treeNode.html'"
	></div>

</div>

【讨论】:

  • 赞成,因为这解决了问题,但我接受了@PratikBhattacharya 的回答,因为他解释了实际发生的事情。
【解决方案2】:

您在每个循环中更新父级的方式存在问题。基本上发生的事情是,在第一级之后,您的父级值变得与节点的值相同。这实际上是一个角度特性,再次调用 ng-init 以更新 parent 的值,因为它看到 node 的值在 ng-repeat 中发生了变化。所以最终结果是 parent 的值将始终是 node.subNodes 中的最后一个元素。因此,当您调用 remove 时,节点的父级并没有真正被传递。为了克服这个问题,我添加了第三个变量,它将保存父级(或更确切地说是下一个父级)的值。我创建了一个提琴手here
我只更改了您的 HTML 如下(ng-init 表达式已更改):

<div ng-controller="CreateTreeController">
  <script type="text/ng-template" id="treeNode.html">
    <span>
            <input
                type="button"
                value="x"
                ng-click="remove(node,parent)"
            >
            <a href="#">{{node.title}}</a>, parent: {{parent.title}}
            <input 
                type="button" 
                value="+" 
                ng-click="addTo(node)"
            >
        </span>
    <div class="subNodes" ng-show="node.subNodes.length>0">
      <div class="node" ng-init="parent=oldParent;oldParent=node;" ng-repeat="node in node.subNodes" ng-include="'treeNode.html'"></div>
    </div>
  </script>

  <div class="node" ng-init="parent=tree;oldParent=parent[0];" ng-repeat="node in tree" ng-include="'treeNode.html'"></div>
</div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-24
    • 2022-08-19
    • 2019-10-21
    • 2013-07-08
    • 2017-12-22
    • 2019-02-10
    • 2020-03-11
    • 2016-06-04
    相关资源
    最近更新 更多