2

First off, I'm aware of this question, Display online and offline (e.g. airplane) mode in an Ember.js App but that does not solve all the issues I'm having. The answer to that question uses Heyoffline.js, which is a great library (it's what JSbin uses), but it does not check the connection status on "startup" of an Ember app, only if I turn off my wifi while I'm using the app. I am creating an offline/online compatible Ember app, I just need to know what the status is on startup and I need full control of the "guts", meaning UI, views, etc...Heyoffline.js does too much of that for you.

Very simply put, I need to fire up an Ember app:

window.App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_VIEW_LOOKUPS: true,
service: null,
isOffline: function() {
    var networkCheck = navigator.onLine ? true : false;
    return networkCheck;
},
ready: function() {
    this.set('service', App.HeyOffline.create());
    Ember.debug("App ready!");
}
});

App.HeyOffline = Ember.Object.extend({
service: null,
init: function() {
    this.set('service', new Heyoffline({
        noStyles: true,
        prefix: "network",
        text: {
            title: "No Internet Connection",
            content: "Your experience will be limited, it's suggested that you connect to the internet",
            button: "Continue Anyway."
        }
    }));
    this.set('service.options.onOnline', this.offline);
    this.set('service.options.onOffline', this.online);
},
online: function() {
    App.set('isOffline', false);
    Ember.debug('Online');
},
offline: function() {
    App.set('isOffline', true);
    Ember.debug('Offline');
}
});

App.ApplicationRoute = Ember.Route.extend();

view.js

App.NetworkView = Ember.View.extend({
layoutName: "_network_error",
classNames: ['network-error', 'flash-message'],
classNameBindings: ['isHidden:hide:show'],
isHidden: true,
networkFail: function() {
    var self = this;
    console.log("Network Failure");
    this.set('isHidden', false);
    Ember.run.next(function() {
        setTimeout(function(){
            self.set('isHidden', true);
        }, 3000);
    });
},
didInsertElement: function() {
    var self = this;
    Ember.run.next(function() {
        if(App.isOffline) { // <--- THIS ALWAYS RETURNS TRUE, doh
            self.networkFail();
        }
    });
}
});

application.hbs

{{outlet}}
{{outlet modal_dialog}}
{{outlet modal_status}}
{{outlet debug}}

{{#view App.NetworkView }} {{/view }}

There is a lot more to my application than that, but I think I've pulled out all the pertinent parts. I'm not saying it has to be done like this at all, the only requirements I have are:

  1. Has to check and set "something" at startup so I can show a message if needed. I'm not saying it has to deferReadiness or anything, from a UX/UI perspective the message can pop up once the App is "ready" or the run loop has finished.
  2. I have to have control over the message UI and it has to be "Emberized", (I'm thinking a view or component), it's going to be a slide-down from the top element (like Facebook mobile connection warning).
  3. Has to have some sort of listener (if I lose my connection, I can pop up the little message) - Heyoffline.js does this wonderfully
  4. Has to be Emberized - must work "the ember way", maybe Ember.Evented or some Pub/Sub setup. I can hack it in, trying not to do that.
  5. Would love it to be a little more foolproof than window.onLine - that only really checks if you are connected to a LAN or router, not "really" checking internet
  6. I am in a very specific environment, Webkit specifically, I don't need IE or old browser support.
  7. I have no other pre-reqs, I'd be fine trashing my current setup entirely.

Any thoughts, suggestions or nuggets anyone wants to share would be greatly appreciated.

4

1 回答 1

1

一个问题是:

if(App.isOffline) { // <--- 这总是返回 TRUE,doh

您应该将其作为函数调用,而不仅仅是访问它。函数是一个真值,但你想要的是函数的结果。

现在,对于其余的功能。将其封装在服务中并使其可供您的其余控制器/视图使用是有意义的。为简单起见,我会将其作为 ApplicationController 的一部分。

App.ApplicationController = Ember.Controller.extend( {
  isOnline: true,  // assume we're online until proven wrong
  init: function () {
    updateNetworkStatus();
  },

  updateNetworkStatus: function () {
    var appController = this;
    if (!navigator.onLine) {
      this.set('isOnline', false);
      return; // return early, no point in pinging the server if we have no LAN
    }
    Ember.$.get('myserver.com/status').done(function () {
      // todo: consider checking the result
      appController.set('isOnline', true);
    }).fail(function () {
      appController.set('isOnline', false);    
    }).always(function () {
      Ember.run.later(appController, 'updateNetworkStatus', 60000);
    });
  } 
});

我们仍然检查 navigator.online,但如果它是真的,我们不会假设我们一直连接到服务器。我们检查一下。一旦我们得到响应,我们就会更新标志并每分钟不断更新该标志。

从其他控制器,我们可以简单地向应用程序控制器添加一个依赖项。

App.OtherController = Ember.Controller.extend( {
  needs: ['application'],
});

然后在属性中使用它或在执行某些操作之前作为检查:

App.OtherController = Ember.Controller.extend( {
  needs: ['application'],
  canEdit: function () {
    return this.get('controllers.application.isOnline');
  }.property('controllers.application.isOnline')
});

或者在你看来

{{controllers.application.isOnline}}

希望这可以帮助。正如我所说,我通常会将其封装成一个service,然后可以将其注入到控制器中,只是为了将这种类型的问题从应用程序中移开,但这可能需要回答第二个问题。

希望这可以帮助

于 2014-03-02T18:34:25.930 回答