我希望你们能帮助我阐明自从我们从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)有关但我在某种程度上忽略了这些含义吗?发生了什么事?
提前致谢!
答案 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);