select(name).option(value)选择了错误的选项



我遇到了一个奇怪的问题。当我尝试选择日期时,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

相关内容

最新更新