1

毫无疑问,我在这里遗漏了一些明显的东西。这是我创建的第一个前端应用程序。

I'd like to have a client side select box which when an option is chosen, a separate property on the entity will be updated. 含义当更改选择框时,调用一个函数,然后将适当地更新其他属性。我遇到的问题是,在客户端创建实体时,选择框不会呈现。

在图片中:

第一步:页面加载完毕。实体存在,没有孩子:

第二步:点击Add Child,创建一个子实体。如您所见,选择框没有选项。使用 Chrome Knockout 插件,我可以看到包含应该呈现的选项的属性是正确的。

第三步:我点击保存,然后刷新页面。选择框正确呈现,但重要的是填充此选择框的值与第二步相同(通过敲除 chrome 插件验证)。

HTML:

<section data-bind="with: parent">
  <div data-bind="foreach: children">
    <select name="propertyOne" 
      data-bind="options: propertyOneOptions, value: propertyOne, optionsText: 'description', optionsCaption: 'Select a Property'">
    </select>
    <br />
  </div>
  <button data-bind="click: $root.addChild">Add Child</button>
</section>
<button data-bind="click: save">Save</button>

查看型号:

如您所见,在 initVm 方法和 addChild 方法中,我都在填充 child.propertyOneOptions。

app.viewModel = (function (logger, dataservice) {

  var parent = ko.observable(null);
  var propertyOneValues = ko.observableArray([]);

  var vm = {
    addChild: addChild,
    parent: parent,
    save: save,
  };

  initVm();

  return vm;

  function initVm() {
    propertyOneValues.push({
      key: 'key 1',
      description: 'value 1'
    });
    propertyOneValues.push({
      key: 'key 2',
      description: 'value 2'
    });
    dataservice.getAllParents()
      .then(function (data) {
        console.log('Number of parents = ' + data.results.length);
        if (data.results.length > 0) {
          parent(data.results[0]);
        } else {
          parent(dataservice.createParent());
          dataservice.saveChanges().fail(queryFailed);
        }
        ko.utils.arrayForEach(parent().children(), function (child) {
          console.log('Populating Child ' + child.propertyOneOptions().length);
          ko.utils.arrayForEach(propertyOneValues(), function (value) {
            child.propertyOneOptions.push(value);
          });
          console.log('Populated Child ' + child.propertyOneOptions().length);
        });
      }).fail(queryFailed);
  }
  function queryFailed(error) {
    console.log('Query failed: ' + error.message);
  }
  function save() {
    dataservice.saveChanges().fail(queryFailed);
  }
  function addChild() {
    var child = dataservice.createChild(parent);
    console.log('Creating Child ' + child.propertyOneOptions().length);
    ko.utils.arrayForEach(propertyOneValues(), function (value) {
      child.propertyOneOptions.push(value);
    });
    console.log('Populated Child ' + child.propertyOneOptions().length);
  }
})(app.logger, app.dataservice);

// Bind viewModel to view in index.html
ko.applyBindings(app.viewModel);

子初始化器:

propertyOne 和 propertyOneOptions 正在创建一个轻而易举的实体初始化器:

function childInitializer(child) {
  child.propertyOne = ko.observable();
  child.propertyOneOptions = ko.observableArray();
}

数据模型:

public class Parent
{
  public Parent()
  {
    Children = new List<Child>();
  }
  [Key]
  public int Id { get; set; }

  public String OtherProperty { get; set; }

  public IList<Child> Children { get; set; }

}
public class Child
{
  [Key]
  public int Id { get; set; }

  public int ParentId { get; set; }

  [ForeignKey("ParentId")]
  public Parent Parent { get; set; }
}

更新 1

在阅读了这篇关于性能的文章后,我补充道:

parent().children.valueHasMutated();

到 addChild 方法和事情的末尾有所改进,即子选择框确实渲染,但正确子下面有一个幻像子:更新了第二步

4

1 回答 1

0

您永远不必调用 valueHasMutated。我从来没有遇到过真正需要它的情况。问题很可能是您在通知 Knockout 添加的实体之前尚未加载所有属性,并且当它尝试绑定时绑定被破坏。

function addChild() {
    // Don't pass a parent into createChild yet
    var child = dataservice.createChild();
    // After the entity is created, then assign the parent property
    child().parent(parent());
    console.log('Creating Child ' + child.propertyOneOptions().length);
    ko.utils.arrayForEach(propertyOneValues(), function (value) {
      child.propertyOneOptions.push(value);
    });
    console.log('Populated Child ' + child.propertyOneOptions().length);
  }

这总是对我有用。

于 2013-09-01T21:12:13.787 回答