diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 765995a52c511d1c26f5b3d14ab731ac12119573..e8f9083b4d1473ec4c5ed5cb3b62e8512eae785c 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -40,13 +40,23 @@ var ObjectWithListeners = require('./ObjectWithListeners');
  * This object contains methods that will communicate with server.
  */
 var ServerConnector = new ObjectWithListeners();
-ServerConnector.registerListenerType("onDataLoadStart");
-ServerConnector.registerListenerType("onDataLoadStop");
+ServerConnector.init = function() {
+  var self = this;
 
-ServerConnector._configurationParam = [];
-ServerConnector._serverBaseUrl= undefined;
+  self._configurationParam = [];
+  self._projects = [];
+  self._projectsById = [];
+  self._customMap = null;
+  self._sessionData = undefined;
+  self._configuration = undefined;
+  self._loggedUser = undefined;
+  self._serverBaseUrl= undefined;
 
+};
+ServerConnector.registerListenerType("onDataLoadStart");
+ServerConnector.registerListenerType("onDataLoadStop");
 
+ServerConnector.init();
 ServerConnector.getMinOverlayColorInt = function () {
   var self = this;
   var userColor;
@@ -675,7 +685,13 @@ ServerConnector.getProject = function(projectId) {
     queryParams.projectId = result;
     return self.readFile(self.getProjectUrl(queryParams, filterParams));
   }).then(function(content) {
-    project = new Project(content);
+    var downloadedProject = new Project(content);
+    if (self._projectsById[projectId] !== undefined) {
+      self._projectsById[projectId].update(downloadedProject);
+    } else {
+      self._projectsById[projectId] = downloadedProject;
+    }
+    project = self._projectsById[projectId];
     return self.getModels(projectId);
   }).then(function (models) {
     project.setModel(models[0]);
@@ -699,16 +715,22 @@ ServerConnector.getProject = function(projectId) {
   });
 };
 
-ServerConnector.getProjects = function() {
+ServerConnector.getProjects = function(reload) {
   var self = this;
-  if (self._projects !== undefined) {
+  if (self._projects.length > 0 && !reload) {
     return Promise.resolve(self._projects);
   } else {
     return self.readFile(self.getProjectsUrl()).then(function(content) {
       var parsedData = JSON.parse(content);
-      self._projects = [];
+      self._projects.length = 0;
       for (var i = 0; i < parsedData.length; i++) {
-        self._projects.push(new Project(JSON.stringify(parsedData[i])));
+        var project = new Project(JSON.stringify(parsedData[i]));
+        if (self._projectsById[project.getProjectId()] !== undefined) {
+          self._projectsById[project.getProjectId()].update(project);
+        } else {
+          self._projectsById[project.getProjectId()] = project;
+        }
+        self._projects.push(self._projectsById[project.getProjectId()]);
       }
       return self._projects;
     });
diff --git a/frontend-js/src/main/js/map/data/Project.js b/frontend-js/src/main/js/map/data/Project.js
index 386eea1be0154c5dca1d537549fb861db5d0e139..00679b4c0217fe6a9c91c1e5c19756e9c9d9ec97 100644
--- a/frontend-js/src/main/js/map/data/Project.js
+++ b/frontend-js/src/main/js/map/data/Project.js
@@ -23,40 +23,48 @@ Project.prototype = Object.create(ObjectWithListeners.prototype);
 Project.prototype.constructor = Project;
 
 Project.prototype.loadFromData = function(data) {
+  var self = this;
   if (typeof data === "string") {
     // replace is due to some strange problem with serialization
     data = JSON.parse(data.replace(/\n/g, " "));
   }
   if (data instanceof Project) {
-    this.setId(data.getId());
-    this.setProjectId(data.getProjectId());
-    this.setVersion(data.getVersion());
-    this.setName(data.getName());
-    this.setOverviewImages(data.getOverviewImages());
-    this.setTopOverviewImage(data.getTopOverviewImage());
-    this.setDisease(data.getDisease());
-    this.setOrganism(data.getOrganism());
-    this.setStatus(data.getStatus());
-    this.setStatus(data.getProgress());
-
-    this.setModel(new Model(data.getModel()));
-
-    this.callListeners("onreload");
+    self.update(data);
 
   } else {
-    this.setId(parseInt(data.idObject));
-    this.setProjectId(data.projectId);
-    this.setVersion(data.version);
-    this.setName(data.name);
-    this.setOverviewImages(data.overviewImageViews);
-    this.setTopOverviewImage(data.topOverviewImage);
-    this.setDisease(data.disease);
-    this.setOrganism(data.organism);
-    this.setStatus(data.status);
-    this.setProgress(data.progress);
-
-    this.callListeners("onreload");
+    self.setId(parseInt(data.idObject));
+    self.setProjectId(data.projectId);
+    self.setVersion(data.version);
+    self.setName(data.name);
+    self.setOverviewImages(data.overviewImageViews);
+    self.setTopOverviewImage(data.topOverviewImage);
+    self.setDisease(data.disease);
+    self.setOrganism(data.organism);
+    self.setStatus(data.status);
+    self.setProgress(data.progress);
+
+    self.callListeners("onreload");
+  }
+};
+
+Project.prototype.update = function(data) {
+  var self = this;
+  self.setId(data.getId());
+  self.setProjectId(data.getProjectId());
+  self.setVersion(data.getVersion());
+  self.setName(data.getName());
+  self.setOverviewImages(data.getOverviewImages());
+  self.setTopOverviewImage(data.getTopOverviewImage());
+  self.setDisease(data.getDisease());
+  self.setOrganism(data.getOrganism());
+  self.setStatus(data.getStatus());
+  self.setProgress(data.getProgress());
+
+  if (data.getModel() !== undefined) {
+    self.setModel(new Model(data.getModel()));
   }
+
+  self.callListeners("onreload");
 };
 
 Project.prototype.getId = function() {
diff --git a/frontend-js/src/test/js/ServerConnector-mock.js b/frontend-js/src/test/js/ServerConnector-mock.js
index 3b1d098878362c4b7a1fece519c3126a1632ca02..b77bd3b4d42cda4d9312e16230f6baf967a69340 100644
--- a/frontend-js/src/test/js/ServerConnector-mock.js
+++ b/frontend-js/src/test/js/ServerConnector-mock.js
@@ -14,16 +14,6 @@ var request = require('request');
 
 var ServerConnectorMock = OriginalServerConnector;
 
-ServerConnectorMock.init = function() {
-  this._customMap = null;
-  this._sessionData = undefined;
-  this._configuration = undefined;
-  this._loggedUser = undefined;
-
-  // add listener types
-};
-ServerConnectorMock.init();
-
 function replaceAsterisk(str) {
   return str.replace(/\*/g,"all").replace(/\:/g,".");
 }
diff --git a/frontend-js/src/test/js/ServerConnector-test.js b/frontend-js/src/test/js/ServerConnector-test.js
index 99e338c0a9b2dd44e682a16de7bf027a46648ab5..20d0399e149b37aeadfb1d5a629bd94a2eb79c80 100644
--- a/frontend-js/src/test/js/ServerConnector-test.js
+++ b/frontend-js/src/test/js/ServerConnector-test.js
@@ -33,6 +33,16 @@ describe('ServerConnector', function() {
         assert.equal(result, null);
       });
     });
+    it('caching', function() {
+      var project;
+      return ServerConnector.getProject().then(function(result) {
+        project = result;
+        return ServerConnector.getProject();
+
+      }).then(function(result) {
+        assert.ok(result === project);
+      });
+    });
   });
 
   it('getModels', function() {
@@ -202,23 +212,49 @@ describe('ServerConnector', function() {
     });
   });
 
-    describe('login', function() {
-        it('try invalid credentials', function() {
-            var method = ServerConnector.sendPostRequest;
-            ServerConnector.sendPostRequest = function() {
-                return Promise.reject(new NetworkError("xxx", {
-                    statusCode : HttpStatus.FORBIDDEN
-                }));
-            };
-            return ServerConnector.login("blabla", "blablabla").then(function() {
-                ServerConnector.sendPostRequest = method;
-                assert.ok(false);
-            }, function(error) {
-                ServerConnector.sendPostRequest = method;
-                assert.ok(error.message.indexOf("credentials") >= 0);
-            });
-        });
+  describe('getProjects', function() {
+    it('test caching', function() {
+      var projects;
+      return ServerConnector.getProjects().then(function(result) {
+        projects = result;
+        return ServerConnector.getProjects();
+      }).then(function(result) {
+        assert.ok(result === projects);
+      });
+    });
+
+    it('test force reload', function() {
+      var projects;
+      var originalName;
+      return ServerConnector.getProjects().then(function(result) {
+        projects = result;
+        originalName = projects[0].getName();
+        projects[0].setName("test name");
+        return ServerConnector.getProjects(true);
+      }).then(function(result) {
+        assert.ok(result === projects);
+        assert.equal(originalName, projects[0].getName());
+      });
     });
+  });
+
+  describe('login', function() {
+    it('try invalid credentials', function() {
+      var method = ServerConnector.sendPostRequest;
+      ServerConnector.sendPostRequest = function() {
+        return Promise.reject(new NetworkError("xxx", {
+          statusCode : HttpStatus.FORBIDDEN
+        }));
+      };
+      return ServerConnector.login("blabla", "blablabla").then(function() {
+        ServerConnector.sendPostRequest = method;
+        assert.ok(false);
+      }, function(error) {
+        ServerConnector.sendPostRequest = method;
+        assert.ok(error.message.indexOf("credentials") >= 0);
+      });
+    });
+  });
 
     describe('getServerBaseUrl', function() {
         it('url with GET arg that looks similar to original url', function() {
diff --git a/frontend-js/src/test/js/minerva-test.js b/frontend-js/src/test/js/minerva-test.js
index ffbbf905cb60e583301363956442d470437821b5..8849af86e7e16e1898ce236e160aee3cf432e179 100644
--- a/frontend-js/src/test/js/minerva-test.js
+++ b/frontend-js/src/test/js/minerva-test.js
@@ -146,17 +146,9 @@ describe('minerva global', function() {
   });
 
   it('create with layout 2', function() {
-    var layout = helper.createLayout();
-    layout.setInputDataAvailable(true);
-    // disable upload of the data from server
-    layout.setInitialized(true);
-    var layoutName = layout.getName();
-
-    helper.setUrl("http://test/?layout=" + layoutName);
+    helper.setUrl("http://test/?layout=xxx");
 
     return ServerConnectorMock.getProject().then(function(project) {
-      project.getModel().addLayout(layout);
-
       var options = helper.createCustomMapOptions(project);
       return minerva.create(options);
     }).then(function(result) {