1

I've spent the night on trying to figure this out and have finally decided to give up and ask for help.

I'm building a web-app with AngularJS that is designed to work with flakey connections (mobiles).

I'm trying to implement the functionality for a user to add a object (whether that's an appointment, book, etc is irrelevant) to the server.

Service that handles syncing objects with the server:

angular.module('App')
  .service('syncUp', function syncUp($http, $q, app) {

    this.addObject = function addObject(object) {
      var deferred = $q.defer();
      app.inSync = false;

      var httpConfig = {
        method: 'POST',
        url: 'http://myurl.dev/app_dev.php/api/add-object',
        data: object
      }

      function persist() { setTimeout(function() {
          $http(httpConfig).
              success(function(data, status) {
                  app.inSync = true;
                  deferred.resolve(data.id);
              }).
              error(function(data, status) {
                  app.inSync = false;
                  persist();
              });
      }, 3000);
      };

      persist();

      return deferred.promise;
    }
  });

'app' service that the status bar is bound to:

'use strict';

angular.module('App')
  .service('app', function app($http, $q) {
    this.inSync = true;
  });

Template binding to the 'app' service inSync property:

<div class="status" ng-class="{'insync':inSync}"></div>

Specific object service that sends data from the controller to the syncUp service:

this.addBook = function(book)
      {
        var tempId = syncUp.generateUid();
        this.books[tempId] = book;
        this.books[tempId].tempId = tempId;
        syncUp.addObject({
          'type': 'book',
          'data': this.books[tempId]
        }).then(function(newId) {
            booksRef[newId] = book;
            delete booksRef[tempId];
          }, function() {});
      }

Everything is working as it should (data is being persisted to the server and the ID is being returned and replacing the tempId just fine. The problem is, when the inSync key on the 'app' service is updated, the class isn't added/removed from the div as it should be with ng-class in the template. If I load another route, that will force iterate through whatever internal cycle angular is doing and update the class on the template.

I've tried all manner of $apply() solutions, moving where the app.inSync key is set back to true, looping a function watching it. It's being set in all the right places (from debugging I know it's set back to true correctly), I just can't figure out how to make the change appear on the UI.

I tried: $rootScope.$apply(function() { app.inSync = true; });

Which gave me an error (already running a digest, or something).

So I tried the 'safeApply' version that has been circulated on many answers/blogs, which didn't throw the error, but didn't work either.

As far as I can figure out, the UI should be updated when promises are resolved (both the http and my syncUp.addObject promise are resolved, so I'm not sure why it's not working.

Any ideas? I need to keep the current implementation of promises to be able to set the returned ID from the server on the added object, to avoid a circular-dependency issue between the syncUp and object angular services.

Edit:

And the status bar directive:

angular.module('App')
  .directive('navigation', function (app) {
    return {
      templateUrl: '/app/views/navigation.html',
      restrict: 'E',
      link: function (scope, element, attrs) {
          scope.inSync = app.inSync;
      }
    }
  });
4

2 に答える 2

1

テンプレートで行う参照は、現在の 上のオブジェクトを参照します$scope。通常、サービスは に何も作成または追加しないため$scope、サービスにプロパティを配置しても、それらをテンプレートで使用できるようにはなりません。で何かを取得$scopeするには、コントローラーを使用する必要があります。ng-controllerディレクティブを使用してコントローラーを参照できます。この例は、最初の AngularJS チュートリアルにあります。

すべきことは、コントローラーを作成し、サービスからのイベントをリッスンすることです。これを行う方法の例を次に示します。

それは良い方法です。また、 inSync = true をそのように設定することで、それを回避できる場合もあり$rootScopeます。

service('syncUp', function syncUp($http, $q, app, $rootScope) {
    // (...)
    $rootScope.inSync = true;
于 2014-01-22T21:49:20.883 に答える
0

サービス (「アプリ」) とテンプレートの間でバインディングが動作することを期待しているようです。全体像が見えていないかどうかを判断するのは困難です。その仮定に基づいて、コントローラーでバインディングをセットアップするようにリファクタリングする必要があります。

コントローラーのセットアップは次のようになると思います。

angular.module('App')
.controller('app', function app($http, $q, $scope) {
    $scope.inSync = true;
});

これで、「inSync」プロパティに双方向バインディングが接続されました。

それ以外の場合、テンプレートは正常に見えます。

私がベースから外れている場合は、より多くのコンテキストで質問を更新するか、問題を煮詰めるためにフィドルを作成してください。

于 2014-01-22T21:49:05.367 に答える