【问题标题】:Knockout mapping nested array with computed property具有计算属性的 Knockout 映射嵌套数组
【发布时间】:2017-11-19 05:26:15
【问题描述】:

我需要计算一组日期时间服务器端,允许更改日期/时间客户端。 下面的代码根据加载服务器数据工作,并将我需要的 iso 字段添加回服务器上。

当用户更改日期/时间输入字段时,如何使 iso 字段可动态计算?

到目前为止淘汰 JS:

var ViewModel = function() {
    var self = this;
    // ...other first-level observables and funct

    function scadenzeNuove(payload) {
    ko.mapping.fromJS(payload, {}, this);

    this.iso = ko.pureComputed( function() {
                var data_re = /^(\d{2})\/(\d{2})\/(\d{4})T(\d{2}):(\d{2})/;
                if (!payload.data) {
                    return false;
                };
                var data_string = payload.data;

                if (!payload.ora) {
                    data_string = data_string + 'T00:00';
                } else {
                    data_string = data_string + 'T' + payload.ora;
                };

                var data_match = data_re.exec(data_string) ? data_re.exec(data_string) : false;
                if (!data_match) { return false; };
                var data = new Date(data_match[3], data_match[2]-1, data_match[1], data_match[4], data_match[5])
                return data;
    }, this);

    };
    var scadenzeNuoveMapping = {
        create: function(options) {
            return new scadenzeNuove(options.data);
        },
    };

    self.scadenzeNuove = ko.observableArray();
    self.compScadenze = function(form) {
    $.getJSON('{{ compute_scadenza }}', $(form).serialize(), function(data){
        ko.mapping.fromJS(data, scadenzeNuoveMapping, self.scadenzeNuove);
    });
    };
};
var vm = new ViewModel()
ko.applyBindings(vm);

HTML:

<div data-bind="if: scadenzeNuove">
      <ul data-bind="foreach: scadenzeNuove">
        <li>
          <span data-bind="text: iso().toLocaleFormat()"></span>
          <input type="text" name="n_data" data-bind="value: data">
          <input type="text" name="n_ora" data-bind="value: ora">
          <input type="text" name="n_desc" data-bind="value: desc">
        </li>
      </ul>
</div>

【问题讨论】:

  • 我想问题是iso属性没有被映射,因为映射调用发生在之前......但我不知道如何应用正确的时间......
  • 我尝试使用this response 中所示的裸 ko.computed 但仍然无法正常工作:iso 字段不会随着组件字段值的变化而更新。

标签: knockout.js knockout-mapping-plugin


【解决方案1】:

我会首先使用默认构造函数从 ISO 字符串转到具有分离的年、月等可观察值的视图模型。

然后,您可以定义一个计算的 isoString 属性,将这些属性重新组合成一个字符串,您可以发送到服务器。

如果您正在使用 Dates...,我强烈建议您编写一些可靠的测试或使用 moment.js...

const DateTimeSelection = function(isoString) {
  const date = new Date(isoString);
  
  this.year = ko.observable(
    date.getFullYear()
  ).extend({ num: true });
  
  this.month = ko.observable(
    date.getMonth()
  ).extend({ num: true });
    
  this.date = ko.observable(
    date.getDate()
  ).extend({ num: true });
 
  this.hour = ko.observable(
    date.getHours()
  ).extend({ num: true });

  this.isoString = ko.pureComputed(() =>
    new Date(
      this.year(), this.month(), this.date(), this.hour()
    ).toISOString()
  );
  
  this.hasChanged = ko.pureComputed(() =>
    this.isoString() !== isoString
  );
};


ko.extenders.numeric = function(target) {
  return ko.computed({
    read: target,
    write: x => target(Number(x))
  });
};

const initialServerData = "2017-06-16T14:00:00.000Z";
const vm = new DateTimeSelection(initialServerData);

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input type="number" data-bind="textInput: year">
<input type="number" data-bind="textInput: month">
<input type="number" data-bind="textInput: date">
<input type="number" data-bind="textInput: hour">



<div data-bind="text: 'output ' + isoString()"></div>
<div data-bind="ifnot: hasChanged" style="color: green">Has not been altered by user</div>
<div data-bind="if: hasChanged" style="color: red">Has been altered by user</div>

【讨论】:

  • 我的问题是关于用 ko.mapping.fromJS 映射一个 json 数组,不要把 js 日期时间弄得比我想的要多
  • 我想我没有很好地解释我的观点......我试图解释的是使用 ISO 日期字符串在视图模型和服务器模型之间进行通信更容易。即:接收DateTime ISO 字符串,为其创建一个视图模型,创建yearmonth 等输入,然后最后转换回 ISO 字符串。另外,我想说使用正则表达式解析 ISO 字符串比使用实际用于解决此类问题的语言功能更“混乱 js 日期时间”......
  • 明白你的意思,谢谢。但是,我的代码坏了,因为我没有管理正确的 javascript 函数范围。
【解决方案2】:

我的错:我引用了静态数据 payload 而不是动态可观察数据 parent

function ScadenzeNuove(payload) {
    var parent = this;
    ko.mapping.fromJS(payload, {}, parent);

    parent.iso = ko.pureComputed( function() {
        var data_re = /^(\d{2})\/(\d{2})\/(\d{4})T(\d{2}):(\d{2})/;
        if (!parent.data()) {
            console.log("Not entered any date");
            return false;
        };
        var data_string = parent.data();

        if (!parent.ora()) {
            data_string = data_string + 'T00:00';
        } else {
            data_string = data_string + 'T' + parent.ora();
        };

        var data_match = data_re.exec(data_string) ? data_re.exec(data_string) : false;
        if (!data_match) {
            console.log('Not a valid date format');
            return false;
        };

        console.log(data_match);

        // Array [ "08/06/2017T23:50:00", "08", "06", "2017", "23", "50" ]
        var data = new Date(data_match[3], data_match[2]-1, data_match[1], data_match[4], data_match[5])
        console.log(data.toLocaleFormat());
        console.log(data.getTimezoneOffset());
        return data;
    }, parent);


    parent.toCal = ko.observable(false);
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-03
    • 2019-05-16
    • 2012-09-24
    • 2013-08-05
    • 1970-01-01
    • 2019-08-13
    • 1970-01-01
    • 2012-06-24
    相关资源
    最近更新 更多