如何在 Mithril JS 中等待 AJAX 请求时显示“Spinner”?

11

我在一个项目中使用Mithril JS,但我不太清楚如何连接Ajax生命周期。比如说,如果我的Ajax请求需要一段时间,我想显示一个加载图标。这很基础,但我似乎不知道该怎么做。

我希望将加载图标放在与Ajax请求内容相同的容器中。

以下是我的设置:

var Thing = function (data) {
  var p = m.prop;
  this.title = p(data.title);
  this.timestamp = p(moment.unix(data.timestamp));
}

Thing.list = function(options) {
  m.request({method: "GET", url: "/things.json", type: Thing, background: true});
};

MyApp.components.thingsList = {
  controller: function ThingListController() {
    this.things = m.prop([]);
    Thing.list().then(this.things).then(m.redraw);
  },

  view: function thingListView(ctrl) {
    return m('div#thing-tab', [
      m('ul#things', [
        ctrl.things().map(thingView)
      ])
    ]);
  }
};

function thingView(thing) {
  ...some view stuff...
}

我已经按照自己想要的方式使它工作了,但是我无法弄清楚如何钩入ajax生命周期。再次强调,我只想在请求开始时显示一个旋转图标,然后用ajax请求的结果替换它。

非常感谢任何帮助!

谢谢,

2个回答

11

一种方法是将m.request包装在另一个函数中,该函数返回完成状态(基于您通过m.request promise链设置的标志)和数据,然后使用background: true选项来防止重绘延迟,并将m.redraw绑定到promise链中,以便在请求后进行重绘。

这最初是在这里描述的:https://github.com/lhorie/mithril.js/issues/192

var requestWithFeedback = function(args) {
  var completed = m.prop(false)
  var complete = function(value) {
    completed(true)
    return value
  }
  args.background = true
  return {
    data: m.request(args).then(complete, complete).then(function(value) {
      m.redraw()
      return value
    }),
    ready: completed
  }
}

var MyController = function() {
  this.things = requestWithFeedback({method: "GET", url: "/things"})
}
var myView = function(ctrl) {
  return !ctrl.things.ready() ? m("img[src=loading.gif]") : m("ul", [
    ctrl.things.data().map(function(thing) {
      return m("li", thing.name)
    })
  ]) 
}

m.module(document.body, {controller: MyController, view: myView})

2
谢谢Leo!那正是我所需要的。顺便说一下,我到目前为止真的很喜欢Mithril :) - Jeff Miller
为什么要两次传入 completem.request(args).then(complete, complete)... - Eric Majerus

3

我发现了一种优雅的方法来实现这个,基于Mithril在模型更新时重新渲染整个UI(使用差分算法)。下面的示例是用于保存内联更新。

当我有一些通过AJAX变化的模型部分时,我在模型中设置一个临时标记(如果您想保持其分离,也可以在视图状态模型中轻松完成),并在完成后删除标记并调用m.redraw():

function updateRecord(ctl,evt,row,idx,rcd) {
    rcd._action="save";
    apiSender({ method: "PATCH", url: apiUrl, data: dropFlags(rcd) }).then(done,fail).then(null,logObject);

    function done(rspdta) {
        delete rcd._action;
        m.redraw();
        };

    function fail(rspdta) {
        ajaxError(ctl,rspdta,"Update customer "+rcd.CustomerId+" ("+rcd.ContactName+")");
        rcd._action="edit";
        m.redraw();
        };
    }

在从模型数据重建的视图中,我会根据标志进行条件筛选:

if     (rcd._action=="edit"   ) { con=crtListRecordView_Edit   (rcd,idx             ); }
else if(rcd._action=="save"   ) { con=crtListRecordView_Waiting(rcd,idx,"Saving"    ); }
else if(rcd._action=="delete" ) { con=crtListRecordView_Waiting(rcd,idx,"Deleting"  ); }
else if(rcd._action=="merge"  ) { con=crtListRecordView_Waiting(rcd,idx,"Merging"   ); }
else if(rcd._action=="refresh") { con=crtListRecordView_Waiting(rcd,idx,"Refreshing"); }
else                            { con=crtListRecordView_Normal (rcd,idx             ); }
return m("tr", con);

这允许在不同记录上进行多个并发操作,给用户提供了优美、清晰且不显眼的反馈界面。
以下是它的展示效果:
正常状态:

Normal

编辑状态:

Editing

保存状态:

Saving


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接