Как показать spinner в ожидании запроса AJAX в Mithril JS?

Я использую Mithril JS в проекте, и мне трудно понять, как подключиться к жизненному циклу Ajax. Например, если у меня есть запрос Ajax, я хочу показать spinner. Довольно простой, но я не могу понять, как это может произойти.

Я хочу использовать тот же контейнер для счетчика, что и контент, который ищет запрос 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.

Любая помощь приветствуется!

Спасибо,

Ответ 1

Один из способов заключается в переносе m.request в другую функцию, которая возвращает как состояние завершения (на основе флага, установленного через цепочку обещаний m.request), так и данные, а затем использовать параметр background: true для предотвратить отсрочку перерисовки, а также привязать m.redraw к цепочке обещаний, чтобы после запроса выполнить перерисовку.

Это изначально было описано здесь: 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

Я нашел то, что, по моему мнению, является изящным способом сделать это на основе принципа, что Mithril повторно отображает весь пользовательский интерфейс (с разницей) при обновлении модели. Следующий пример предназначен для сохранения встроенного обновления.

Когда у меня есть часть модели, которая меняется с помощью 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:

Normal

Редактирование:

Editing

Сохранение:

Saving