[CORD-2314] Correctly parsing dates when they are formatted as strings

Change-Id: I13b9318d4e20c07a43d3185420cd3a3fab628ee7
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index 80855e5..91db9f2 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -319,13 +319,6 @@
       // remove fields added by the GUI
       item = this.removeExtraFields(item, model);
 
-      _.forEach(Object.keys(item), prop => {
-        // convert dates back to UnixTime
-        if (this.XosFormHelpers._getFieldFormat(item[prop]) === 'date') {
-          item[prop] = new Date(item[prop]).getTime() / 1000;
-        }
-      });
-
       const itemCopy = angular.copy(item);
       const itemName = (angular.isUndefined(itemCopy.name)) ? model.name : itemCopy.name;
 
@@ -341,13 +334,14 @@
           d.resolve(res);
         })
         .catch(err => {
+          const errorMsg = err.specific_error || err.error || 'Internal Server Error';
           formCfg.feedback = {
             show: true,
-            message: `Error while saving ${itemName}: ${err.error}. ${err.specific_error || ''}`,
+            message: `Error while saving ${itemName}: ${errorMsg}.`,
             type: 'danger',
             closeBtn: true
           };
-          this.toastr.error(err.specific_error || '', `Error while saving ${itemName}: ${err.error}`);
+          this.toastr.error(err.specific_error || '', `Error while saving ${itemName}: ${errorMsg}`);
           d.reject(err);
         });
 
diff --git a/src/app/datasources/rest/model.rest.ts b/src/app/datasources/rest/model.rest.ts
index dcec5d4..c63d334 100644
--- a/src/app/datasources/rest/model.rest.ts
+++ b/src/app/datasources/rest/model.rest.ts
@@ -50,10 +50,10 @@
 
     resource.prototype.$save = function() {
 
-      // NOTE converting dates back to timestamp
+      // NOTE converting dates back to timestamp (safety check, dates should not arrive to the client)
       _.forEach(Object.keys(this), (k: string) => {
         if (self.XosFormHelpers._getFieldFormat(this[k]) === 'date') {
-          this[k] = new Date(this[k]).getTime();
+          this[k] = new Date(this[k]).getTime() / 1000;
         }
       });
 
diff --git a/src/app/views/crud/crud.html b/src/app/views/crud/crud.html
index b347c31..596add8 100644
--- a/src/app/views/crud/crud.html
+++ b/src/app/views/crud/crud.html
@@ -54,7 +54,10 @@
                 <xos-debug-model ng-model="vm.model"></xos-debug-model>
             </div>
         </uib-tab>
-        <uib-tab ng-if="vm.getRelatedItemId(r, vm.model)" ng-repeat="r in vm.related.manytoone" heading="{{r.model}} {{vm.getHumanReadableOnField(r)}}">
+        <uib-tab
+          ng-if="vm.getRelatedItemId(r, vm.model) && vm.relatedModels.manytoone[r.model][r.on_field].formConfig"
+          ng-repeat="r in vm.related.manytoone"
+          heading="{{r.model}} {{vm.getHumanReadableOnField(r)}}">
             <div class="panel-body">
                 <xos-form ng-model="vm.relatedModels.manytoone[r.model][r.on_field].model" config="vm.relatedModels.manytoone[r.model][r.on_field].formConfig"></xos-form>
             </div>
diff --git a/src/app/views/crud/crud.ts b/src/app/views/crud/crud.ts
index 0fe9407..2aafe41 100644
--- a/src/app/views/crud/crud.ts
+++ b/src/app/views/crud/crud.ts
@@ -76,6 +76,8 @@
   };
   public debugTab: boolean;
 
+  public getRelatedModels = _.memoize(this._getRelatedModels);
+
   private subscription: Subscription;
 
   constructor(
@@ -109,18 +111,6 @@
     this.tableCfg = this.modelDef.tableCfg;
     this.formCfg = this.modelDef.formCfg;
 
-    // attach a redirect to the $save method
-    const originalSave = this.formCfg.actions[0].cb;
-    this.formCfg.actions[0].cb = (item, form: angular.IFormController) => {
-      originalSave(item, form)
-        .then(res => {
-          this.$state.go(this.$state.current, {id: res.id});
-        })
-        .catch(err => {
-          this.$log.error(`[XosCrud] Error while saving:`, item, err);
-        });
-    };
-
     this.debugTab = this.XosDebug.status.modelsTab;
     this.$scope.$on('xos.debug.status', (e, status: IXosDebugStatus) => {
       this.debugTab = status.modelsTab;
@@ -137,13 +127,21 @@
         const endpoint = this.XosModelDiscovererService.getApiUrlFromModel(this.XosModeldefsCache.get(this.data.model));
         const resource = this.ModelRest.getResource(endpoint);
         this.model = new resource({});
+
+        // attach a redirect to the $save method
+        const originalSave = angular.copy(this.formCfg.actions[0].cb);
+        this.formCfg.actions[0].cb = (item, form: angular.IFormController) => {
+          originalSave(item, form)
+            .then(res => {
+              this.$state.go(this.$state.current, {id: res.id});
+            })
+            .catch(err => {
+              this.$log.error(`[XosCrud] Error while saving:`, item, err);
+            });
+        };
       }
       else {
         this.subscription = this.store.get(this.data.model, $stateParams['id'])
-          .first(val => {
-            // NOTE emit an event only if we have an object, and only the first time we have it
-            return Object.keys(val).length > 0;
-          })
           .subscribe(res => {
             $scope.$evalAsync(() => {
               this.related.onetomany = _.filter($state.current.data.relations, {type: 'onetomany'});
@@ -201,16 +199,6 @@
         description: 'View details of selected item'
       }, 'view');
 
-      // FIXME XosKeyboardShortcut modifiers does not look to work
-      // this.XosKeyboardShortcut.registerKeyBinding({
-      //   key: 'Tab',
-      //   modifiers: ['alt'],
-      //   cb: () => {
-      //     this.tableCfg.selectedRow = -1;
-      //   },
-      //   description: 'Clear selected item'
-      // }, 'view');
-
       this.subscription = this.store.query(this.data.model)
         .subscribe(
           (event) => {
@@ -224,7 +212,9 @@
   }
 
   $onDestroy() {
-    this.subscription.unsubscribe();
+    if (this.subscription) {
+      this.subscription.unsubscribe();
+    }
     this.$log.info(`[XosCrud] Destroying component`);
   }
 
@@ -247,7 +237,7 @@
     return this.XosCrudRelation.getHumanReadableOnField(r, this.data.model);
   }
 
-  public getRelatedModels(relations: {manytoone: IXosModelRelation[], onetomany: IXosModelRelation[]}, item: any) {
+  private _getRelatedModels(relations: {manytoone: IXosModelRelation[], onetomany: IXosModelRelation[]}, item: any) {
     this.$log.debug(`[XosCrud] Managing relation for ${this.data.model}:`, relations);
 
     // loading many to one relations (you'll get a model)