秘银 - 在子组件修改父组件数据后重新排序子组件数组

时间:2016-02-28 00:13:51

标签: javascript sorting data-binding 2-way-object-databinding mithril.js

如果有人能想到这个问题的更好的标题,请告诉我。

我在疯狂的时间之后才弄清楚这个问题的答案。我确定其他人会犯同样的错误,所以我会在下面发布答案。

一旦我提供了一些背景信息,这个问题会更有意义。我有一个父组件,它有一个具有匹配键的对象数组(例如ctrl.arrayOfObjects)。我按每个对象共享的一个键的值(例如ctrl.arrayOfObjects[0].keyToSortBy)对此数组进行排序。然后,我将now-sorted数组中的每个元素传递给另一个组件。

此子组件具有onclick方法,该方法更改父级和子级之间共享的数据,即父级ctrl.arrayOfObjects中的一个对象。它会更改用于对父组件ctrl.arrayOfObjects进行排序的键的值(例如sharedObject.keyToSortBy)。

我的问题是,在触发此onclick事件后,父组件重新排序对象数组。 onclick事件确实修改了它应该(sharedObject.keyToSortBy)的数据,我知道这是因为页面 重新呈现sharedObject.keyToSortBy的新值。但它确实重新排序父组件的ctrl.arrayOfObjects

奇怪的是,如果我执行console.log,则会调用sort方法,但页面不会显示任何更改。

以下是代码的外观(ctrl.arrayOfObjectsctrl.jokes):

var JokeWidgetSeries = {
  controller: function() {
    var ctrl = this;
    ctrl.jokes = [{
      text: "I'm a joke",
      votes: 3
    }, {
      text: "This is another joke",
      votes: 1
    }, {
      text: "A third joke",
      votes: 1
    }]
  },
  view: function(ctrl) {
    return m('#jokes-container',
      m('#jokes',
        ctrl.jokes.sort(function(a, b) {
          // Sort by number of votes.
          return (a.votes < b.votes) ? 1 : (a.votes > b.votes) ? -1 : 0;
        }).map(function(joke) {
          // Create a 'JokeWidget' for each object in 'ctrl.jokes'.
          // Share the 'joke' object with the child component.
          return m.component(JokeWidget, joke);
        })
      )
    );
  }
};

var JokeWidget = {
  controller: function(inherited) {
    var ctrl = this;
    ctrl.joke = inherited;
  },
  view: function(ctrl) {
    return m('.joke', [
      m('.joke-text', ctrl.joke.text),
      m('.joke-vote-count', ctrl.joke.votes),
      m('.thumb-up', {
        onclick: function(e) {
          // Here, the page shows that the vote count has changed,
          //   but the array of 'JokeWidget' DOM elements do not re-sort.
          ctrl.joke.votes += 1;
        }
      })
    ]);
  }
};

触发onclick组件的JokeWidget方法后,显示.joke-vote-count的{​​{1}} DOM元素确实会增加1.但它不会在列表中向上移动/页面上的小部件数组就像它应该的那样。

但是,如果我将这两个组件合并为一个,则 数组会像我想要的那样重新排序。像这样:

ctrl.joke.votes

如何分离这些组件并仍然可以使这种重新排序方法起作用?

1 个答案:

答案 0 :(得分:0)

解决方案很简单。在父组件和子组件之间共享对象时,将对象传递给子组件的var JokeWidgetSeries = { controller: function() { var ctrl = this; ctrl.jokes = [{ text: "I'm a joke", votes: 3 }, { text: "This is another joke", votes: 1 }, { text: "A third joke", votes: 1 }] }, view: function(ctrl) { return m('#jokes-container', m('#jokes', ctrl.jokes.sort(function(a, b) { // Sort by number of votes. return (a.votes < b.votes) ? 1 : (a.votes > b.votes) ? -1 : 0; }).map(function(joke) { // Create a 'JokeWidget' component instance for each object in 'ctrl.jokes'. // Share the 'joke' object with the child component. return m('.joke', [ m('.joke-text', joke.text), m('.joke-vote-count', joke.votes), m('.thumb-up', { onclick: function(e) { // Here, the array of 'JokeWidget' DOM elements // DO re-sort. Why? joke.votes += 1; } }) ]); }) ) ); } }; 方法而不是view方法。

在Mithril中创建组件时,您可以将数据传递给 controller 组件的controller方法。此数据将是view方法的第一个参数和controller方法的第二个参数。

不是将共享对象设置为view ctrl.joke方法内的JokeWidget,而是在其controller方法中引用它,只需传递共享对象直接指向view方法。像这样:

view

这也消除了额外的抽象层,使其更易于阅读和理解。