AngularJS 1.4迁移 - ngOptions:是否通过破坏对象相等性检查进行跟踪?

时间:2015-10-09 13:16:39

标签: javascript html angularjs ng-options angularjs-ng-model

我希望你们能帮助我阐明自从我们从Angular 1.3迁移到Angular 1.4以来我一直面临的问题。

我创建了一个支持JSFiddle演示,演示了这个

说明

我有一个控制器,其中包含两个MyElement个实例的列表,用户可以使用<select>进行选择。

还有一个按钮,用于将所选===与列表中的第一个元素进行比较(MyElement)。此比较的结果将记录到控制台。

<select>使用track by element.id来区分MyElement - 个实例。

奇怪的是,所选项目从不等于列表的第一个元素(即使选择了第一个元素)。绑定到ctrl.selectedElement的对象是一个不同的对象,但具有相同的属性:

NO!
Object {id: 1, description: "First"}
MyElement {id: 1, description: "First"}

当我删除track by element.id 时,请返回Angular 1.3,此行为将消失(两个元素严格相等,正如我所期望的那样)。

问题

这是一个错误吗?这与fix(ngOptions)有关但我在某种程度上忽略了这些含义吗?发生了什么事?

提前致谢!

2 个答案:

答案 0 :(得分:4)

JavaScript for Objects中的默认相等运算符在引用内存中的相同位置时产生true。更新必须以不尊重先前语句的方式更改对象。查看migration docs以查看是否记录了更改。虽然,我可以看到track by确实正在创建一个新对象 - 这将是虚假===检查的关键

使用angular.equals代替===。如angular.equals docs ...

中所述,此检查有一些细节
  

如果至少一个,则认为两个对象或值是等效的   以下是真的:

     
      
  • 对象或值都通过===比较。
  •   
  • 通过将它们与angular.equals进行比较,两个对象或值都属于同一类型,并且它们的所有属性都相同。
  •   
  • 两个值均为NaN。 (在JavaScript中,NaN == NaN =&gt; false。但我们认为两个NaN相等)
  •   
  • 这两个值代表相同的正则表达式(在JavaScript中,/ abc / == / abc / =&gt; false。但我们将两个正则表达式视为   当他们的文字表示匹配时相等)。
  •   
     

在属性比较期间,函数类型和属性   名称以$开头的属性将被忽略。

     

仅通过标识(===)来比较范围和DOMWindow对象。

// -- 'YES!'
console.log(angular.equals(this.selectedElement, this.elements[0]) ? 'YES!' : 'NO!'); 

JSFiddle Link - 更新了演示

尝试中提供尽可能最佳的答案,我在v1.4.0中挖掘了ngOptions的来源,以下track by的代码似乎正在返回一个新的对象,从而解释了上述所有内容。

// Get the value by which we are going to track the option
// if we have a trackFn then use that (passing scope and locals)
// otherwise just hash the given viewValue
var getTrackByValueFn = trackBy ?
    function(value, locals) { return trackByFn(scope, locals); } :
    function getHashOfValue(value) { return hashKey(value); };

var getTrackByValue = function(value, key) {
    return getTrackByValueFn(value, getLocals(value, key));
};

var locals = {}; // ---------- <<<<<<<<<<<<<<<< ---------- new object
var getLocals = keyName ? function(value, key) {
    locals[keyName] = key;
    locals[valueName] = value;
    return locals;
} : function(value) {
    locals[valueName] = value;
    return locals;
};

答案 1 :(得分:0)

使用JSON.stringify然后进行比较。我不知道使用与否是有效的。

var MyElement = function (id, description) {
    this.id = id;
    this.description = description;
}

var MyController = function () {
    this.elements = [
        new MyElement(1, 'First'),
        new MyElement(2, 'Second')
    ];
};

MyController.prototype.isFirst = function (element) {
    console.log(JSON.stringify(this.selectedElement) === JSON.stringify(this.elements[0]) ? 'YES!' : 'NO!');  
    console.log(this.selectedElement);
    console.log(this.elements[0]);
};

angular
    .module('myApp', [])
    .controller('MyController', MyController);