2014-05-12 8 views
5

Ho un'app Web a pagina singola scritta utilizzando AngularJS. Usa PouchDB per replicare su un server CouchDB e funziona perfettamente.L'applicazione AngularJS/PouchDB interrompe la sincronizzazione su CouchDB quando cache.manifest ha aggiunto

Il problema si presenta quando provo a convertire la pagina Web in modo che sia disponibile offline aggiungendo cache.manifest. Improvvisamente TUTTE le attività di replica generano errori e smettono di funzionare, sia in modalità offline che online.

In Chrome si dice solo "GET ... myCouchIP/myDB/_ nonce = CxVFIwnEJeGFcyoJ Net :: ERR_FAILED?"

In Firefox getta anche un errore, ma afferma che la richiesta è bloccata - provare CORS abilitazione.

CORS è abilitato sul CouchDB remoto come da istruzioni dalla pagina di configurazione di PouchDB. Inoltre funziona bene senza usare cache.manifest (vale a dire è abbastanza soddisfatto di tutti i diversi indirizzi IP tra la mia scrivania, il server e una VM - è un prototipo quindi non ci sono nomi di dominio in questo momento).

Per inciso, attualmente non utilizzo alcun tipo di autenticazione. L'amministratore è attivo.

Quindi cosa cambia quando si aggiunge il cache.manifest? Gli indizi sono grati e accolti. Grazie in anticipo.

app.js

var app = angular.module('Assets', ['assets.controllers', 'ngRoute']); 

app.config(['$routeProvider', function($routeProvider) { 
    $routeProvider. 
    when('/', { 
     controller: 'OverviewCtrl', 
     templateUrl: 'views/overview.html' 
    }). 
    when('/new', { 
     controller: 'NewMachineCtrl', 
     templateUrl: 'views/machineForm.html' 
    }). 
    otherwise({redirectTo: '/'}); 
}]); 

controller.js

var _control = angular.module('assets.controllers', ['assets.services']); 

_control.controller('OverviewCtrl', ['$scope', 'Machine', function($scope, Machine) { 
    var promise = Machine.getAll(); 

    promise.then(function(machineList) { 
     $scope.machines = machineList; 
    }, function(reason) { 
     alert('Machine list is empty: ' + reason); 
    }); 
}]); 

_control.controller('UpdateMachineCtrl', ['$scope', '$routeParams', 'Machine', 
              function($scope, $routeParams, Machine) { 
    $scope.title = "Update Installation Details"; 
    var promise = Machine.getSingle($routeParams.docId); 

    promise.then(function(machine) { 
     $scope.machine = machine; 
    }, function(reason) { 
     alert('Record could not be retrieved'); 
    }); 

    $scope.save = function() { 
     Machine.update($scope.machine); 
    }; 
}]); 

_control.controller('SyncCtrl', ['$scope', 'Machine', function($scope, Machine) { 
    $scope.syncDb = function() { 
     Machine.sync(); 
     Machine.checkConflicts(); 
    }; 

    $scope.checkCors = function() { 
     // Check CORS is supported 
     var corsCheck = function(method, url) { 
      var xhr = new XMLHttpRequest(); 

      if ("withCredentials" in xhr) { 
      // XHR for Chrome/Firefox/Opera/Safari. 
      xhr.open(method, url, true); 
      } else if (typeof XDomainRequest != "undefined") { 
      // XDomainRequest for IE. 
      xhr = new XDomainRequest(); 
      xhr.open(method, url); 
      } else { 
      // CORS not supported. 
      console.log('CORS not supported by browser'); 
      } 

      xhr.onload = function() { 
       console.log('Response from CORS ' + method + ' request to ' + url + ': ' + xhr.responseText); 
      }; 
      xhr.onerror = function() { 
       console.log('Error response from CORS ' + method + ' request to ' + url + ': ' + xhr.responseText); 
      }; 

      xhr.send(); 
     }; 

     var server = 'http://10.100.3.21:5984/ass_support'; 

     corsCheck('GET', server); 
     corsCheck('PUT', server); 
     corsCheck('POST', server); 
     corsCheck('HEAD', server); 
//  corsCheck('DELETE', server); 
    }; 
}]); 

service.js

var _service = angular.module('assets.services', []); 

_service.constant('dbConfig',{ 
    dbName: 'assets', 
    dbServer: 'http://myCouchServerIp:5984/' 
}); 

/** 
* Make PouchDB available in AngularJS. 
*/ 
_service.factory('$db', ['dbConfig', function(dbConfig) { 
    PouchDB.enableAllDbs = true; 
    var localDb = new PouchDB(dbConfig.dbName); 
    var remoteDb = dbConfig.dbServer + dbConfig.dbName; 
    var options = {live: true}; 
    var syncError = function() { 
     console.log('Problem encountered during database synchronisation'); 
    }; 

    console.log('Replicating from local to server'); 
    localDb.replicate.to(remoteDb, options, syncError); 

    console.log('Replicating from server back to local'); 
    localDb.replicate.from(remoteDb, options, syncError); 

    return localDb; 
}]); 

_service.factory('Machine', ['$q', '$db', '$rootScope', 'dbConfig', 
        function($q, $db, $rootScope, dbConfig) { 
    return { 
     update: function(machine) { 
      var delay = $q.defer(); 

      var doc = { 
       _id: machine._id, 
       _rev: machine._rev, 
       type: machine.type, 
       customer: machine.customer, 
       factory: machine.factory, 
       lineId: machine.lineId, 
       plcVersion: machine.plcVersion, 
       dateCreated: machine.dateCreated, 
       lastUpdated: new Date().toUTCString() 
      }; 

      $db.put(doc, function(error, response) { 
       $rootScope.$apply(function() { 
        if (error) { 
         console.log('Update failed: '); 
         console.log(error); 
         delay.reject(error); 
        } else { 
         console.log('Update succeeded: '); 
         console.log(response); 
         delay.resolve(response); 
        } 
       }); 
      }); 

      return delay.promise; 
     }, 
     getAll: function() { 
      var delay = $q.defer(); 

      var map = function(doc) { 
       if (doc.type === 'machine') { 
        emit([doc.customer, doc.factory], 
          { 
           _id: doc._id, 
           customer: doc.customer, 
           factory: doc.factory, 
           lineId: doc.lineId, 
           plcVersion: doc.plcVersion, 
          } 
        ); 
       } 
      }; 

      $db.query({map: map}, function(error, response) { 
       $rootScope.$apply(function() { 
        if (error) { 
         delay.reject(error); 
        } else { 
         console.log('Query retrieved ' + response.rows.length + ' rows'); 
         var queryResults = []; 

         // Create an array from the response 
         response.rows.forEach(function(row) { 
          queryResults.push(row.value); 
         }); 

         delay.resolve(queryResults); 
        } 
       }); 
      }); 

      return delay.promise; 
     }, 
     sync: function() { 
      var remoteDb = dbConfig.dbServer + dbConfig.dbName; 
      var options = {live: true}; 
      var syncError = function(error, changes) { 
       console.log('Problem encountered during database synchronisation'); 
       console.log(error); 
       console.log(changes); 
      }; 
      var syncSuccess = function(error, changes) { 
       console.log('Sync success'); 
       console.log(error); 
       console.log(changes); 
      }; 

      console.log('Replicating from local to server'); 
      $db.replicate.to(remoteDb, options, syncError). 
       on('error', syncError). 
       on('complete', syncSuccess); 

      console.log('Replicating from server back to local'); 
      $db.replicate.from(remoteDb, options, syncError);  
     } 
    }; 
}]); 

_service.factory('dbListener', ['$rootScope', '$db', function($rootScope, $db) { 
    console.log('Registering a onChange listener'); 
    $db.info(function(error, response) { 
     $db.changes({ 
      since: response.update_seq, 
      live: true, 
     }).on('change', function() { 
      console.log('Change detected by the dbListener'); 
      // TODO work out why this never happens 
     }); 
    }); 
}]); 

cache.manifest

CACHE MANIFEST 

# views 
views/machineForm.html 
views/overview.html 

# scripts 
scripts/vendor/pouchdb-2.2.0.min.js 
scripts/vendor/angular-1.2.16.min.js 
scripts/vendor/angular-route-1.2.16.min.js 

scripts/app.js 
scripts/controllers/controller.js 
scripts/services/service.js 

index.html

<!DOCTYPE html> 
<html lang="en" manifest="cache.manifest" data-ng-app="Assets"> 
<head> 
<meta charset="UTF-8"> 
<meta name="viewport" content="width=device-width, initial-scale=1"> 
<title>Asset Management</title> 

<script src="scripts/vendor/angular-1.2.16.min.js" type="text/javascript"></script> 
<script src="scripts/vendor/angular-route-1.2.16.min.js" type="text/javascript></script> 
<script src="scripts/vendor/pouchdb-2.2.0.min.js" type="text/javascript"></script> 

<script src="scripts/app.js" type="text/javascript"></script> 
<script src="scripts/services/service.js" type="text/javascript"></script> 
<script src="scripts/controllers/controller.js" type="text/javascript"></script> 
</head> 
<body> 
    <div id="content"> 
    <nav class="sidebar"> 
    <h3>Options</h3> 
    <div> 
     <a class="active" data-ng-href="#/">Overview</a> 
     <a data-ng-href="#" data-ng-controller="SyncCtrl" data-ng-click="syncDb()">Synchronise</a> 
     <a data-ng-href="" data-ng-controller="SyncCtrl" data-ng-click="checkCors()">Check CORS</a> 
    </div> 
    </nav> 

    <section class="main"> 
     <div data-ng-view></div> 
    </section> 
    </div> 
</body> 
</html> 

overview.html

<h3>Installation Overview</h3> 
<table> 
    <tr> 
     <th>Customer</th> 
     <th>Factory</th> 
     <th>Line Id</th> 
     <th>PLC Version</th> 
    </tr> 
    <tr data-ng-repeat="machine in machines"> 
     <td>{{machine.customer}}</td> 
     <td>{{machine.factory}}</td> 
     <td><a data-ng-href="#/view/{{machine._id}}">{{machine.lineId}}</a></td> 
     <td>{{machine.plcVersion}}</td> 
    </tr> 
</table> 

machineForm.html

<h3>{{title}}</h3> 
<form name="machineForm" data-ng-submit="save()"> 
    <div> 
    <label for="customer">Customer:</label> 
<div><input data-ng-model="machine.customer" id="customer" required></div> 
    </div> 

    <div> 
    <label for="factory">Factory:</label> 
    <div><input data-ng-model="machine.factory" id="factory" required></div> 
    </div> 

    <div> 
<label for="lineId">Line ID:</label> 
    <div><input data-ng-model="machine.lineId" id="lineId" required></div> 
    </div> 

    <div> 
<label for="plcVersion">PLC Version:</label> 
    <div><input data-ng-model="machine.plcVersion" id="plcVersion"></div> 
    </div> 

    <div><button data-ng-disabled="machineForm.$invalid">Save</button></div> 
</form> 
+0

Se si dispone di un jsfiddle o qualcosa che può riprodurre questo, sarebbe davvero utile. Sentiti libero di presentare un problema sulla pagina [PouchDB GitHub] (https://github.com/pouchdb/pouchdb/issues). – nlawson

+0

Mai usato jsfiddle, ma non penso che funzionerà perché non ho server di database disponibili pubblicamente. Ho pubblicato il codice più pertinente qui. Scusate se questo post è ora pazzesco a lungo. –

risposta

10

provare a cambiare il file cache.manifest a questo:

CACHE MANIFEST 

CACHE: 
# views 
views/machineForm.html 
views/overview.html 

# scripts 
scripts/vendor/pouchdb-2.2.0.min.js 
scripts/vendor/angular-1.2.16.min.js 
scripts/vendor/angular-route-1.2.16.min.js 

scripts/app.js 
scripts/controllers/controller.js 
scripts/services/service.js 

NETWORK: 
* 

Quando si utilizza un file manifesto, tutti risorse non memorizzati nella cache verranno a mancare in una pagina memorizzata nella cache, anche quando sei online. La sezione NETWORK indica al browser di consentire le richieste alle risorse non memorizzate nella cache (continueranno comunque a fallire mentre offline, ovviamente).

+1

Quello era quello. Confermato lavorando ora. Grazie molto –

Problemi correlati