Added callback to applyEdits() and custom event to indicate success/failure of updates, adds, deletes

This commit is contained in:
andygup 2013-12-02 16:32:24 -07:00
parent ab7c164c01
commit e29b520ea8
2 changed files with 114 additions and 25 deletions

View File

@ -16,14 +16,14 @@
padding: 0;
overflow:hidden;
}
#header {
#header, #info {
border:solid 2px #462d44;
background:#fff;
color:#444;
-moz-border-radius: 4px;
border-radius: 4px;
font-family: sans-serif;
font-size: 1.1em
font-size: 1.1em;
padding-left:20px;
}
#map {
@ -98,6 +98,8 @@
map.on("layers-add-result", initEditing);
var headerDiv = document.getElementById("info");
var landusePointLayer = new FeatureLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Military/FeatureServer/6", {
mode: FeatureLayer.MODE_SNAPSHOT,
outFields: ["*"]
@ -127,17 +129,39 @@
//////////
offlineStore = new OfflineStore(map);
console.log("Storage used : " + offlineStore.getlocalStorageUsed());
headerDiv.innerHTML = "Storage Used: " + offlineStore.getlocalStorageUsed() + " MBs";
try{
document.addEventListener("editEvent",function(evt){
if(evt.type == "editEvent" && evt.detail.message == true){
console.log("editEvent: All edits successfully pushed");
}
else if(evt.type == "editEvent" && evt.detail.message == false){
alert("Not all edits were successfully pushed to the server");
}
headerDiv.innerHTML = "Storage Used: " + offlineStore.getlocalStorageUsed() + " MBs";
},
false);
}
catch(err){
console.log("test that event object is valid: " + err);
}
//////////
var editToolbar = new Edit(map);
editToolbar.on("deactivate", function(evt) {
if(updateFlag == true){
offlineStore.applyEdits(vertices.graphic,vertices.layer,offlineStore.enum().UPDATE);
offlineStore.applyEdits(vertices.graphic,vertices.layer,offlineStore.enum().UPDATE,function(count,success,id){
headerDiv.innerHTML = "Storage Used: " + offlineStore.getlocalStorageUsed() + " MBs";
});
updateFlag = false;
}
else{
offlineStore.applyEdits(evt.graphic,currentLayer,offlineStore.enum().UPDATE);
offlineStore.applyEdits(evt.graphic,currentLayer,offlineStore.enum().UPDATE,function(count,success,id){
headerDiv.innerHTML = "Storage Used: " + offlineStore.getlocalStorageUsed() + " MBs";
});
}
});
@ -168,7 +192,9 @@
event.stop(evt);
if (evt.ctrlKey === true || evt.metaKey === true) { //delete feature if ctrl key is depressed
try{
offlineStore.applyEdits(evt.graphic,layer,offlineStore.enum().DELETE);
offlineStore.applyEdits(evt.graphic,layer,offlineStore.enum().DELETE,function(count,success,id){
headerDiv.innerHTML = "Storage Used: " + offlineStore.getlocalStorageUsed() + " MBs";
});
}
catch(err){
console.log("error " + err.stack);
@ -218,7 +244,9 @@
var newAttributes = lang.mixin({}, selectedTemplate.template.prototype.attributes);
var newGraphic = new Graphic(evt.geometry, null, newAttributes);
//selectedTemplate.featureLayer.applyEdits([newGraphic], null, null);
offlineStore.applyEdits(newGraphic,selectedTemplate.featureLayer,offlineStore.enum().ADD);
offlineStore.applyEdits(newGraphic,selectedTemplate.featureLayer,offlineStore.enum().ADD,function(count,success,id){
headerDiv.innerHTML = "Storage Used: " + offlineStore.getlocalStorageUsed() + " MBs";
});
});
}
@ -253,6 +281,7 @@
<body class="claro">
<div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="gutters:true, design:'headline'" style="width:100%;height:100%;">
<div data-dojo-type="dijit/layout/ContentPane" id="header" data-dojo-props="region:'top'">Use ctrl or cmd + click on graphic to delete. Double click on graphic to edit vertices. </div>
<div id="info" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">Storage used: 0 MBs</div>
<div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div>
<div id="rightPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'right'">
<div id="templatePickerDiv"></div>

View File

@ -55,14 +55,24 @@ var OfflineStore = function(/* Map */ map) {
*/
this._localEnum = (function(){
var values = {
VALIDATION_URL : "http://localhost/offline/test.html", /* Change this to a remote server for testing! */
TIMER_URL : "./src/Timer.js", /* For use within a child process only */
STORAGE_KEY : "___EsriOfflineStore___", /* Unique key for setting/retrieving values from localStorage */
INDEX_KEY : "___EsriOfflineIndex___", /* Index for tracking each action (add, delete, update) in local store */
VALIDATION_TIMEOUT : 10 * 1000, /* HTTP timeout when trying to validate internet on/off */
LOCAL_STORAGE_MAX_LIMIT : 4.75 /* MB */, /* Most browsers offer default storage of ~5MB */
TOKEN : "|||", /* A unique token for tokenizing stringified localStorage values */
/* Change this to a remote server for testing! */
VALIDATION_URL : "http://localhost/offline/test.html",
/* For use within a child process only */
TIMER_URL : "./src/Timer.js",
/* Unique key for setting/retrieving values from localStorage */
STORAGE_KEY : "___EsriOfflineStore___",
/* Index for tracking each action (add, delete, update) in local store */
INDEX_KEY : "___EsriOfflineIndex___",
/* HTTP timeout when trying to validate internet on/off */
VALIDATION_TIMEOUT : 10 * 1000,
/* Most browsers offer default storage of ~5MB */
LOCAL_STORAGE_MAX_LIMIT : 4.75 /* MB */,
/* A unique token for tokenizing stringified localStorage values */
TOKEN : "|||",
TIMER_TICK_INTERVAL : 10 * 1000 /* ms */,
EDIT_EVENT: "editEvent",
EDIT_EVENT_SUCCESS: true,
EDIT_EVENT_FAILED: false,
REQUIRED_LIBS : [
"./src/Hydrate.js",
"./src/Poller.js"
@ -102,10 +112,12 @@ var OfflineStore = function(/* Map */ map) {
* @param graphic Required
* @param layer Required
* @param enumValue Required
* @param callback Recommended. Returns true if offline condition detected otherwise returns false.
*/
this.applyEdits = function(/* Graphic */ graphic,/* FeatureLayer */ layer, /* String */ enumValue){
this.applyEdits = function(/* Graphic */ graphic,/* FeatureLayer */ layer, /* String */ enumValue, callback){
var internet = this._checkInternet();
this._applyEdits(internet,graphic,layer,enumValue);
this._applyEdits(internet,graphic,layer,enumValue, callback);
//this._sendEvent("Halllooo","test");
}
/**
@ -145,6 +157,8 @@ var OfflineStore = function(/* Map */ map) {
/**
* Determines total storage used for this domain.
* NOTE: The index does take up storage space. Even if the offlineStore
* is deleted, you will still see some space taken up by the index.
* @returns Number MB's
*/
this.getlocalStorageUsed = function(){
@ -152,20 +166,32 @@ var OfflineStore = function(/* Map */ map) {
//IE hack
if(window.localStorage.hasOwnProperty("remainingspace")){
//http://msdn.microsoft.com/en-us/library/ie/cc197016(v=vs.85).aspx
return window.localStorage.remainingSpace/1024/1024;
return (window.localStorage.remainingSpace/1024/1024).round(4);
}
else{
var mb = 0;
for(var x in localStorage){
//Uncomment out console.log to see *all* items in local storage
console.log(x+"="+((localStorage[x].length * 2)/1024/1024)+" MB");
//console.log(x+"="+((localStorage[x].length * 2)/1024/1024).toFixed(4)+" MB");
mb += localStorage[x].length
}
return Math.round(((mb * 2)/1024/1024) * 100)/100;
//return Math.round(((mb * 2)/1024/1024) * 100)/100;
return ((mb *2)/1024/1024).round(4);
}
}
/**
* A Global prototype that provides rounding capabilities.
* TODO reevaluate if this should be local in scope or global.
* @param places
* @returns {number}
*/
Number.prototype.round = function(places){
places = Math.pow(10, places);
return Math.round(this * places)/places;
}
//////////////////////////
///
/// PRIVATE methods
@ -180,20 +206,23 @@ var OfflineStore = function(/* Map */ map) {
* @param graphic
* @param layer
* @param enumValue
* @param callback Returns true if offline condition detected otherwise returns false.
* Format: {count, success, id}
* @private
*/
this._applyEdits = function(/* Boolean */ internet, /* Graphic */ graphic,/* FeatureLayer */ layer, /* String */ enumValue){
this._applyEdits = function(/* Boolean */ internet, /* Graphic */ graphic,/* FeatureLayer */ layer, /* String */ enumValue, callback){
//TODO Need to add code to determine size of incoming graphic
var mb = this.getlocalStorageUsed();
console.log("getlocalStorageUsed = " + mb + " MBs");
if(mb > this._localEnum().LOCAL_STORAGE_MAX_LIMIT /* MB */){
alert("You are almost over the local storage limit. No more data can be added.")
callback(0,false,0);
return;
}
if(internet === false){
this._addToLocalStore(graphic,layer,enumValue);
this._addToLocalStore(graphic,layer,enumValue,callback);
if(this.isTimer == null){
this._startTimer(function(err){
throw ("unable to start background timer. Offline edits won't work. " + err.stack);
@ -202,11 +231,12 @@ var OfflineStore = function(/* Map */ map) {
}
else if(internet == null || typeof internet == "undefined"){
console.log("applyEdits: possible error.");
callback(0,false,0);
}
else{
//No need for a callback because this is an online request and it's immediately
//pushed to Feature Service. The only thing updated in the library is the Index.
this._layerEditManager(graphic,layer,enumValue,this.enum(),null,null);
this._layerEditManager(graphic,layer,enumValue,this.enum(),0,callback);
}
}
@ -305,17 +335,20 @@ console.log(localStore.toString());
}
}
this._addToLocalStore = function(/* Graphic */ graphic, /* FeatureLayer */ layer, /* String */ enumValue){
this._addToLocalStore = function(/* Graphic */ graphic, /* FeatureLayer */ layer, /* String */ enumValue,callback){
var arr = this._getLocalStorage();
var geom = this._serializeGraphic(graphic,layer,enumValue);
var setItem = null;
//If localStorage does NOT exist
if(arr === null){
this._setItemInLocalStore(geom);
setItem = this._setItemInLocalStore(geom);
callback(0,setItem,0);
}
else{
this._updateExistingLocalStore(geom);
setItem = this._updateExistingLocalStore(geom);
callback(0,setItem,0);
}
layer.add(graphic);
@ -365,6 +398,10 @@ console.log(localStore.toString());
if(evt == true){
this._stopTimer();
this._deleteStore();
this._sendEvent(true,this._localEnum().EDIT_EVENT);
}
else{
this._sendEvent(false,this._localEnum().EDIT_EVENT);
}
}.bind(this));
}
@ -395,6 +432,23 @@ console.log(localStore.toString());
}
}
this._sendEvent = function(msg,event){
//this.preventDefault();
if (msg && window.CustomEvent) {
var event = new CustomEvent(event, {
detail: {
message: msg,
time: new Date()
},
bubbles: true,
cancelable: true
});
document.dispatchEvent(event);
}
}
this._handleRestablishedInternet = function(callback){
var graphicsArr = this.getStore();
@ -418,6 +472,7 @@ console.log(localStore.toString());
else{
console.log("_handleRestablishedInternet: there were errors. LocalStore still available.");
this._stopTimer();
callback(false);
}
}
else if(success == true && check.length < graphicsArr.length){
@ -427,6 +482,7 @@ console.log(localStore.toString());
this._setItemLocalStoreIndex(obj1.layer,objectId,obj1.enumValue,false);
console.log("_handleRestablishedInternet: error sending edit on " + objectId);
this._stopTimer();
callback(false);
}
else if(success == false && check.length < graphicsArr.length){
this._setItemLocalStoreIndex(obj1.layer,objectId,obj1.enumValue,false);
@ -761,6 +817,10 @@ console.log(localStore.toString());
if(evt == true){
this._stopTimer();
this._deleteStore();
this._sendEvent(true,this._localEnum().EDIT_EVENT);
}
else{
this._sendEvent(false,this._localEnum().EDIT_EVENT);
}
}.bind(this));
}