在刷新之前,Knockout不会渲染客户端选择框(Breeze.js)

时间:2013-09-01 15:57:22

标签: javascript knockout.js breeze

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

我想要一个客户端选择框,当选择一个选项时,将更新实体上的单独属性。更改选择框时的含义,调用一个函数,然后适当地更新另一个属性。我遇到的问题是,当在客户端创建实体时,选择框不会呈现。

在图片中:

Step One:页面已加载。该实体不存在子项:

Step Two:单击“添加子项”,并创建子实体。如您所见,选择框没有选项。使用Chrome Knockout插件,我可以看到包含应该呈现的选项的属性是正确的。

Step Three:点击“保存”,然后刷新页面。选择框正确呈现,但重要的是填充此选择框的值与第二步相同(通过knockout chrome plugin验证)。

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正在创建一个breeze实体初始化器:

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

在阅读this表现后,我添加了:

parent().children.valueHasMutated();

到addChild方法的结尾并且事情有所改进,那就是一个子选择框确实渲染,但正确的子项下面有一个幻影子:Updated Step Two

1 个答案:

答案 0 :(得分: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);
  }

这对我来说总是有用的。