2

我能以某种方式找到与给定 angularjs 模型对应的字段吗?我知道,可能有多个字段与单个变量对应,或者没有,但这不是问题。

例如,有一个input ng-model=users[2].name,我想要一个获取字符串"users[2].name"并返回 DOM 元素的方法。

我不需要很快,因为我希望它用于一种用户输入的演示,例如,如果用户应该填写名称字段,我将一个(模拟鼠标)覆盖移动到它并以编程方式填充它。硅

我可以通过 jquery 来完成,但这相当麻烦,因为它几乎不像 selector 那样简单input[ng-model="user[0].name"]。它通常被埋在ng-repeat="user in users"几层深的地方。或者更糟糕的是,在ng-repeat-startng-repeat-end

改变解决方案users[2].name然后找到更改的 DOM 元素也可能没问题。

我创建了一个plunk希望展示我想要的东西。

4

3 回答 3

1

注意:maaartinus 要求我取消删除此答案,但这是错误的


这是一个结合伪代码和 JavaScript 编写的答案......

function findElem() {
  var originalVal = users[2].name
  var possibleMatches = []

  for each elem in the page:
    ngElem = angular.element(elem);

    var id = 0
    for each watcher in ngElem.scope().$$watchers
      if (watcher.last === originalVal) {
        possibleMatches.push({ngElem: ngElem, watcherId: id})
      }
      id++

  var changedVal = users[2].name = users[2].name + 'changed'
  $scope.$apply()

  for each possibleMatch in possibleMatches
    var s = possibleMatch.ngElem.scope()
    var mid = possibleMatch.watcherId
    if (s.$$watchers[mid].last == changedVal)
      return ngElem; // found

  return null; // not found
}
于 2014-06-26T17:42:32.907 回答
1

我添加这个答案是因为它确实有效,不像我原来的答案。此外,这是一种非常不同的方法,所以我不想只是将它附加到那个方法上。

警告:如果您的 ng-model 表达式有一个点,则此方法有效,否则不存在用于传播临时更改的原型继承链。

>>笨蛋

概述

首先,我们装饰ng-model指令以便跟踪ng-model应用程序中的所有 s。这些模型存储在myModels数组中。然后我们循环myModels查找所有评估为我们正在寻找的值的模型并将它们推送到possibleMatches数组中。最后,我们更改目标值并循环possibleMatches确定实际更改的是哪一个。

编码:

angular.module('find_by_model', [])

.constant('myModels', [])

.config(function($provide, myModels) {
  window.myModels = myModels; // just for debugging

  $provide.decorator('ngModelDirective', function($delegate) {

    var directive = $delegate[0];

    var compile = directive.compile;

    directive.compile = function(tElement, tAttrs) {
      var link = compile.apply(this, arguments);
      tElement.append('<div>Added in the decorator</div>');
      return function(scope, elem, attrs) {
        link.apply(this, arguments);
        v = scope.$eval(tAttrs.ngModel);
        myModels.push({scope: scope, elem:elem,
          val: function() {
            return scope.$eval(tAttrs.ngModel);
          },
        }); 
      }; 
    };

    return $delegate;
  });
})

.factory('finder', function (myModels) {
  function findElem($scope, path) {
    var originalVal = $scope.$eval(path),
        possibleMatches = [],
        result = null;

    angular.forEach(myModels, function (model) {
      if (angular.equals(model.val(), originalVal)) possibleMatches.push(model);
    });

    // temp change: the blah property is arbitrary
    try {
      var newVal = $scope.$eval(path + " = " + JSON.stringify({ val: path, blah: 'changed'}) );
    } catch(e) {
      return null;
    } 

    // find it: note: this could be made more efficient with a breaking loop
    angular.forEach(possibleMatches, function (model) {
      if (angular.equals(model.val(),newVal)) result = model;
    });

    // reset
    $scope.$eval(path + " = " + JSON.stringify(originalVal));

    return result && result.elem;
  }

  return {
    findElem: findElem
  }
})

这里是你如何使用它(假设你已经注入finder):

  $scope.expressionToFind = "m.top[0].name";

  var el = finder.findElem($scope, $scope.expressionToFind);
  if (el) 
    angular.element(el).css('outline', '1px solid red');
  else
    alert('not found');
于 2014-06-28T05:15:52.853 回答
0

这是一个访问指令中元素的简单示例:

http://plnkr.co/edit/2gU3d7UMYG1D7nWMjbvo?p=preview

如果由于某种原因您无法修改 html,这是 Angular 之外的一种方式:

window.onload=function(){
  var ele=getElementsByModel(document,'name');
  for(var i=0;i<ele.length;i++){
    ele[i].style.border='solid 1px green';
  }
}
function getElementsByModel(baseElement,modelName){
  var nodes = baseElement.getElementsByTagName('*');
  var targetNodes=[];
  for(var i=0;i<nodes.length;i++){
    var ngModel=nodes[i].getAttribute('ng-model');
    if(ngModel&&ngModel===modelName){ 
      targetNodes.push(nodes[i]);
    }
  }
  return targetNodes;
}    
于 2014-06-25T21:48:50.360 回答