From 7906ac66bbbda870f0e36a780db92ecc8c8f6287 Mon Sep 17 00:00:00 2001 From: Mina Nagy Zaki Date: Tue, 13 Jun 2017 22:42:25 +0200 Subject: [PATCH 1/3] add sf-array deletion failing tests related to json-schema-form/angular-schema-form#870 and json-schema-form/angular-schema-form#874 --- src/directives/sf-array.directive.spec.js | 42 +++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/directives/sf-array.directive.spec.js b/src/directives/sf-array.directive.spec.js index 31c89ddd9..9a463ee47 100644 --- a/src/directives/sf-array.directive.spec.js +++ b/src/directives/sf-array.directive.spec.js @@ -22,9 +22,14 @@ describe('sf-array.directive.js', function() { "type": "array", "description": "foobar", "items": { - "title": "Name", - "type": "string", - "default": 6 + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string", + "default": 6 + } + } } } } @@ -63,4 +68,35 @@ describe('sf-array.directive.js', function() { }); }); + + it('should not delete innocent items on delete', function(done) { + + tmpl = angular.element('
'); + + inject(function($compile, $rootScope) { + var scope = $rootScope.$new(); + scope.model = {names: [{name: "0"}, {name: "1"}, {name: "2"}, {name: "3"}]}; + + scope.schema = exampleSchema; + + scope.form = ["*"]; + + $compile(tmpl)(scope); + runSync(scope, tmpl); + + tmpl.find('div.help-block').text().should.equal('foobar'); + + var close = tmpl.find('button.close'); + close.eq(1).click(); + + $rootScope.$apply(); + + setTimeout(function() { + scope.model.names[0].name.should.equal("0"); + scope.model.names[1].name.should.equal("2"); + scope.model.names[2].name.should.equal("3"); + done(); + }, 0) + }); + }); }); From 1675fe3594140abcd4415ac6840dabc56d624696 Mon Sep 17 00:00:00 2001 From: Mina Nagy Zaki Date: Wed, 14 Jun 2017 00:51:42 +0200 Subject: [PATCH 2/3] fix array deletion issue When an array item is deleted from the model, the fields get destroyed. The destroy handler was trying to delete the item again. --- src/directives/sf-array.directive.js | 4 -- src/directives/sf-field.directive.js | 56 +++++++++++++++------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/directives/sf-array.directive.js b/src/directives/sf-array.directive.js index fdfe4ed67..d5743f92f 100644 --- a/src/directives/sf-array.directive.js +++ b/src/directives/sf-array.directive.js @@ -186,10 +186,6 @@ export default function(sfSelect, sfPath, schemaForm) { model.splice(index, 1); } - if(item.$$hashKey) { - scope.destroyed = item.$$hashKey; - } - return model; }; diff --git a/src/directives/sf-field.directive.js b/src/directives/sf-field.directive.js index e68ff0995..daa5bcba8 100644 --- a/src/directives/sf-field.directive.js +++ b/src/directives/sf-field.directive.js @@ -292,7 +292,6 @@ sfPath, sfSelect) { // in the form definition. scope.$on('$destroy', function() { let key = scope.getKey(); - let arrayIndex = (typeof scope.arrayIndex == 'number') ? scope.arrayIndex + 1: 0; // If the entire schema form is destroyed we don't touch the model if (!scope.externalDestructionInProgress) { @@ -301,36 +300,43 @@ sfPath, sfSelect) { // No key no model, and we might have strategy 'retain' if (key && destroyStrategy !== 'retain') { - // Get the object that has the property we wan't to clear. - var obj = scope.model; - if (key.length > 1) { - obj = sfSelect(key.slice(0, key.length - 1), obj); - } - - if(obj && scope.destroyed && obj.$$hashKey && obj.$$hashKey !== scope.destroyed) { - return; - } - - // We can get undefined here if the form hasn't been filled out entirely - if (obj === undefined) { - return; - } - // Type can also be a list in JSON Schema var type = (form.schema && form.schema.type) || ''; // Empty means '',{} and [] for appropriate types and undefined for the rest - //console.log('destroy', destroyStrategy, key, type, obj); - if (destroyStrategy === 'empty' && type.indexOf('string') !== -1) { - obj[key.slice(-1)] = ''; - } else if (destroyStrategy === 'empty' && type.indexOf('object') !== -1) { - obj[key.slice(-1)] = {}; - } else if (destroyStrategy === 'empty' && type.indexOf('array') !== -1) { - obj[key.slice(-1)] = []; + let value; + if (destroyStrategy === 'empty') { + value = type.indexOf('string') !== -1 ? '' : + type.indexOf('object') !== -1 ? {} : + type.indexOf('array') !== -1 ? [] : undefined; } else if (destroyStrategy === 'null') { - obj[key.slice(-1)] = null; + value = null; + } + + if (value !== undefined) { + sfSelect(key, scope.model, value); } else { - delete obj[key.slice(-1)]; + // Get the object parent object + let obj = scope.model; + if (key.length > 1) { + obj = sfSelect(key.splice(0, key.length - 1), obj) + } + + // parent can be undefined if the form hasn't been filled out + // entirely + if (obj === undefined) { + return; + } + + // if parent is an array, then we have already been removed. + // set flag to all children (who are about to recieve a $destroy + // event as well) that we have already been destroyed + if (angular.isArray(obj)) { + scope.externalDestructionInProgress = true; + return; + } + + delete obj[key[0]]; } } } From 4615c14f449d77b6228f8c554928637ba98e3262 Mon Sep 17 00:00:00 2001 From: Mina Nagy Zaki Date: Wed, 14 Jun 2017 03:11:03 +0200 Subject: [PATCH 3/3] don't splice the key, messes with other things --- src/directives/sf-field.directive.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/directives/sf-field.directive.js b/src/directives/sf-field.directive.js index daa5bcba8..54e69cc77 100644 --- a/src/directives/sf-field.directive.js +++ b/src/directives/sf-field.directive.js @@ -319,7 +319,7 @@ sfPath, sfSelect) { // Get the object parent object let obj = scope.model; if (key.length > 1) { - obj = sfSelect(key.splice(0, key.length - 1), obj) + obj = sfSelect(key.slice(0, key.length - 1), obj) } // parent can be undefined if the form hasn't been filled out @@ -336,7 +336,7 @@ sfPath, sfSelect) { return; } - delete obj[key[0]]; + delete obj[key[key.length-1]]; } } }