I am trying have unique title to my node in recursive tree.
So when I give title to my nodes it should check that this title is already taken by some other nodes or not. If taken then it should alert user and it should reset that node value to previous value.
No two nodes should have same title.
But here as structure is recursive so I am not getting how do to do this.
Note : I want to do this as soon as textbox loses its focus.
var app = angular.module("myApp", []);
app.controller("TreeController", function ($scope) {
$scope.delete = function (data) {
data.nodes = [];
};
$scope.add = function (data) {
var post = data.nodes.length + 1;
var newName = data.name + '-' + post;
data.nodes.push({ name: newName, nodes: [],selected : false, myObj: { name: newName} });
};
$scope.tree = [{ name: "Node", nodes: [], selected: false }];
$scope.setActive = function ($event, data) {
$event.stopPropagation();
$scope.selectedData = data;
clearDivSelection($scope.tree);
data.selected = true;
};
function clearDivSelection(items) {
items.forEach(function (item) {
item.selected = false;
if (item.nodes) {
clearDivSelection(item.nodes);
}
});
}
$scope.checkDuplicateNodeName = function () {
alert()
}
});
ul {
list-style: circle;
}
li {
margin-left: 20px;
}
.active { background-color: #ccffcc;}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="TreeController">
<li ng-repeat="data in tree" ng-include="'tree_item_renderer.html'"></li>
<script type="text/ng-template" id="tree_item_renderer.html">
<div ng-class="{'active': data.selected}" > {{data.myObj.name}}</div>
<button ng-click="add(data)">Add node</button>
<button ng-click="delete(data)" ng-show="data.nodes.length > 0">Delete nodes</button>
<ul>
<li ng-repeat="data in data.nodes" ng-include="'tree_item_renderer.html'" ng-click="setActive($event, data)"></li>
</ul>
</script>
<div style="margin-left:100px;">
Title : <input type="text" ng-model="selectedData.myObj.name" ng-blur="checkDuplicateNodeName()" />
Location : <input type="text" ng-model="selectedData.myObj.location" />
</div>
</ul>
true
. if there's a dupe, use last valid name, else update last valid name.If you wish to search for dupes only in the node's tree, you need to store a reference to the parent node, and use the getTree
method to determine the root node to search from.
var app = angular.module("myApp", []);
app.controller("TreeController", function($scope) {
$scope.delete = deleteNodes;
$scope.add = add;
$scope.setActive = setActive;
$scope.checkDuplicateNodeName = checkDuplicateNodeName;
$scope.trees = [{
name: "Node",
nodes: [],
selected: false
},{
name: "Node2",
nodes: [],
selected: false
}];
function deleteNodes(data) {
data.nodes = [];
}
function add(data) {
var post = data.nodes.length + 1;
var newName = data.name + '-' + post;
data.nodes.push({
name: newName,
nodes: [],
selected: false,
validatedName: newName
});
}
function setActive($event, data) {
$event.stopPropagation();
if($scope.selectedData) {
$scope.selectedData.selected = false;
}
$scope.selectedData = data;
data.selected = true;
}
function checkDuplicateNodeName() {
if(!$scope.selectedData)
return;
var dupe = false;
for(var idx = 0; idx < $scope.trees.length; idx++) {
if(isDuplicateName($scope.trees[idx], $scope.selectedData)) {
dupe = true;
break;
}
}
if(dupe){
alert('The name "' + $scope.selectedData.name + '" already exists');
$scope.selectedData.name = $scope.selectedData.validatedName;
} else {
$scope.selectedData.validatedName = $scope.selectedData.name;
}
}
function getTree(node){
while(node.parent) {
node = node.parent;
}
return node;
}
function isDuplicateName(node, nodeToCheck) {
var dupeName = node != nodeToCheck && node.name && nodeToCheck.name && node.name == nodeToCheck.name;
if(dupeName) return true;
if(node.nodes){
for(var idx=0; idx< node.nodes.length; idx++) {
if(isDuplicateName(node.nodes[idx], nodeToCheck)){
return true;
}
}
}
return false;
}
});
ul {
list-style: circle;
}
li {
margin-left: 20px;
}
.active {
background-color: #ccffcc;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="TreeController">
<li ng-repeat="data in trees" ng-include="'tree_item_renderer.html'"></li>
<script type="text/ng-template" id="tree_item_renderer.html">
<div ng-class="{'active': data.selected}"> {{data.name}}</div>
<button ng-click="add(data)">Add node</button>
<button ng-click="delete(data)" ng-show="data.nodes.length > 0">Delete nodes</button>
<ul>
<li ng-repeat="data in data.nodes" ng-include="'tree_item_renderer.html'" ng-click="setActive($event, data)"></li>
</ul>
</script>
<div style="margin-left:100px;">
Title : <input type="text" ng-model="selectedData.name" ng-blur="checkDuplicateNodeName()" /> Location : <input type="text" ng-model="selectedData.myObj.location" />
</div>
</ul>
You could use a recursive approach similar to your clearDivSelection
method:
function isDuplicated (node, title) {
var result = false;
if (node.nodes && node.nodes.length > 0) result = node.nodes.reduce(function (result, node) {
return isDuplicated(node, title);
}, false);
return result && node.name === title;
}
Or (at a cost of memory), you could maintain a list of titles:
$scope.titles = {};
$scope.add = function (data) {
var post = data.nodes.length + 1;
var newName = data.name + '-' + post;
if ($scope.titles[newName]) return; // refuse to add
$scope.titles[newName] = true;
data.nodes.push({
name: newName,
nodes: [],
selected : false,
myObj: {
name: newName
}
});
};
I'm not sure exactly what you mean by
should reset that node value to previous value.
if you are "add"ing new objects, you won't have a "previous value" - but I'll leave that bit up to you. This should get you started, anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With