如何在文本框模糊事件中检查递归数组结构中的重复值?

时间:2017-05-19 12:28:03

标签: javascript angularjs

我正在尝试在递归树中为我的节点添加唯一标题。

因此,当我为节点提供标题时,它应该检查该标题是否已被其他节点使用。如果采用它,它应该警告用户,它应该将该节点值重置为先前的值。

没有两个节点应该具有相同的标题。

但是这里结构是递归的,所以我不知道如何做到这一点。

注意:我想在文本框失去焦点时立即执行此操作。

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>

2 个答案:

答案 0 :(得分:3)

您可以使用类似于clearDivSelection方法的递归方法:

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;
}

或(以记忆为代价),您可以维护标题列表:

$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
    }
  });
};

我不确定你的意思

  

应该将该节点值重置为之前的值。

如果你“添加”新对象,你将没有“以前的价值” - 但我会把这一点留给你。无论如何,这应该让你开始。

答案 1 :(得分:3)

我的解决方案

  1. 在模糊上存储经过验证的名称副本(意思是有3个名字,但我不知道myObj.name的重点,所以我保留原样,你可以清理)
  2. 递归找到dupes,先停在true。如果有欺骗行为,请使用最后一个有效名称,否则更新最后一个有效名称。
  3. 个为什么

    1. 您只想在模糊时验证名称。 angular提供了对每个更改通过解析器和格式化程序验证ng-model的方法,这将彻底限制用户持久化欺骗名称。有很多方法可以处理这个问题(验证器,编辑而不会持久),并且都需要不同类型的解决方案。探索并选择最适合您的方式
    2. 使用hashMap(我的第一个想法)需要对重命名和删除进行清理逻辑,这会使代码进一步复杂化
    3. 如果您只想在节点树中搜索dupes,则需要存储对父节点的引用,并使用getTree方法确定要搜索的根节点。 / p>

      &#13;
      &#13;
      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;
        }
      });
      &#13;
      ul {
        list-style: circle;
      }
      
      li {
        margin-left: 20px;
      }
      
      .active {
        background-color: #ccffcc;
      }
      &#13;
      <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>
      &#13;
      &#13;
      &#13;