1

我有一个奇怪的问题。当我尝试选择日期时,该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()尝试以某种顺序选择值。IE 它首先尝试按值选择选项,然后尝试按模型值或类似的方式选择它。

4

2 回答 2

2

所以我查找了该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;
    };
});

这可以解决问题。

于 2013-12-04T11:45:32.483 回答
1

当源模型是一个列表时, 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

于 2013-12-02T16:45:36.993 回答