我遇到了一个奇怪的问题。当我尝试选择日期时,select()
函数选择了错误的选项。
Ng型号:
days = ['01', '02', '03', '04', ..., '31'];
标记:
<select ng-model="day" id="day" name="day" ng-options="day for day in days">
<option value="" disabled="disabled"></option>
</select>
e2e测试:
it('should select correct date', function () {
select('day').option('30');
expect(element('#day option:selected').text()).toEqual('30');
});
所以我的问题是:为什么select('day').option('30')
会选择select('day').option('02')
正常工作的第31天?
所以我想知道它的目标价值是什么,因为它在其他地方运行良好。文档非常稀疏,所以它要么是一个功能,要么是一种错误:)
我认为select()
试图按某种顺序选择值。也就是说,它首先尝试按价值选择选项,然后尝试按模型价值或类似的东西来选择。
所以我查找了select
函数的实现。
来自github:
/**
* Usage:
* select(name).option('value') select one option
* select(name).options('value1', 'value2', ...) select options from a multi select
*/
angular.scenario.dsl('select', function() {
var chain = {};
chain.option = function(value) {
return this.addFutureAction("select '" + this.name + "' option '" + value + "'",
function($window, $document, done) {
var select = $document.elements('select[ng\:model="$1"]', this.name);
var option = select.find('option[value="' + value + '"]');
if (option.length) {
select.val(value);
} else {
option = select.find('option').filter(function(){
return _jQuery(this).text() === value;
});
if (!option.length) {
option = select.find('option:contains("' + value + '")');
}
if (option.length) {
select.val(option.val());
} else {
return done("option '" + value + "' not found");
}
}
select.trigger('change');
done();
});
};
return function(name) {
this.name = name;
return chain;
};
});
因此,"问题"是select
试图从DOM元素中的值中进行选择,即<option value="THIS VALUE">
,然后它试图通过显示的<option>THIS VALUE</option>
找到值,然后它尝试对该值执行contains
。它实际上在任何时候都没有使用模型值。
所以select('day').option('02')
起作用是因为它与显示的文本匹配,其中select('day').option('30')
与具有偏移的选项值匹配。
请记住,生成的HTML是:
<select ng-model="day" id="day" name="day" ng-options="day for day in days">
<option value="" disabled="disabled"></option>
<option value="0">01</option> <-- note it starts at 0 not 1
<option value="1">02</option> <-- select('day').option('02') matches display text '02' as no value 02 exists.
<option value="2">03</option>
<option value="29">30</option>
<option value="30">31</option> <-- select('day').option('30') matches value 30 before display text 30 with value 29.
</select>
为了"解决"这个问题,需要创建一个新功能(或更改现有功能)。
angular.scenario.dsl('selectModel', function() {
var chain = {};
chain.option = function(value) {
return this.addFutureAction("select '" + this.name + "' option '" + value + "'",
function($window, $document, done) {
var $ = $window.$; // jQuery inside the iframe
var select = $document.elements('select[ng\:model="$1"]', this.name);
var option = select.find('option').filter(function(){
return $(this).text() === value;
});
if (!option.length) {
option = select.find('option:contains("' + value + '")');
}
if (option.length) {
select.val(option.val());
} else {
return done("option '" + value + "' not found");
}
select.trigger('change');
done();
});
};
return function(name) {
this.name = name;
return chain;
};
});
这就奏效了。
Angular创建的option
标记具有索引作为值,当源模型为列表时:
$scope.listItems = [
"day 1",
"day 2",
"day 3",
"day 4",
"day 5"
];
和
<select ng-model="listItem" ng-options="item for item in listItems"></select>
创建以下HTML:
<select ng-options="item for item in listItems" ng-model="listItem"
class="ng-pristine ng-valid">
<option value="?" selected="selected"></option>
<option value="0">day 1</option>
<option value="1">day 2</option>
<option value="2">day 3</option>
<option value="3">day 4</option>
<option value="4">day 5</option>
</select>
当option
标签的值为键时,当源模型为映射时:
$scope.objItems = {
"day 1":"1",
"day 2":"2",
"day 3":"3",
"day 4":"4",
"day 5":"5"
};
和
<select ng-model="objItem2" ng-options="value as key for (key, value)
in objItems"></select>
创建:
<select ng-options="value as key for (key, value) in objItems"
ng-model="objItem2" class="ng-valid ng-dirty">
<option value="day 1" selected="selected">day 1</option>
<option value="day 2">day 2</option>
<option value="day 3">day 3</option>
<option value="day 4">day 4</option>
<option value="day 5">day 5</option>
</select>
然而,这从来不会带来问题,因为当用户选择一个选项时,Angular会查找源内的索引位置,并将该值分配给模型。
我不太熟悉e2e测试,但我认为每次选择选项时都会得到不同的值的原因是,您试图访问存储在option
标记中的值,而不是Angular为您存储在模型中的值。
Fiddle