New subscriber view
diff --git a/views/ngXosLib/bower.json b/views/ngXosLib/bower.json
index 08a02e3..d2c7744 100644
--- a/views/ngXosLib/bower.json
+++ b/views/ngXosLib/bower.json
@@ -21,7 +21,8 @@
"angular-animate": "1.4.7",
"lodash": "~4.11.1",
"angular-chart.js": "~0.10.2",
- "d3": "~3.5.17"
+ "d3": "~3.5.17",
+ "angular-recursion": "~1.0.5"
},
"devDependencies": {
"angular-mocks": "1.4.7",
diff --git a/views/ngXosLib/generator-xos/app/templates/bower.json b/views/ngXosLib/generator-xos/app/templates/bower.json
index 9dafc2b..0abca60 100644
--- a/views/ngXosLib/generator-xos/app/templates/bower.json
+++ b/views/ngXosLib/generator-xos/app/templates/bower.json
@@ -27,6 +27,7 @@
"lodash": "~4.11.1",
"bootstrap-css": "3.3.6",
"angular-chart.js": "~0.10.2",
- "d3": "~3.5.17"
+ "d3": "~3.5.17",
+ "angular-recursion": "~1.0.5"
}
}
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
index 18c6f6f..9d880a0 100644
--- a/views/ngXosLib/karma.conf.js
+++ b/views/ngXosLib/karma.conf.js
@@ -94,7 +94,7 @@
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'PhantomJS',
- 'Chrome'
+ // 'Chrome'
],
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
new file mode 100644
index 0000000..4c90cd6
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
@@ -0,0 +1,225 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+ 'use strict';
+
+ describe('The xos.helper module', function(){
+
+ describe('The XosFormHelper service', () => {
+ let service;
+
+ let fields = [
+ 'id',
+ 'name',
+ 'mail',
+ 'active',
+ 'created',
+ 'custom'
+ ];
+
+ let modelField = {
+ id: {},
+ name: {},
+ mail: {},
+ active: {},
+ created: {},
+ custom: {}
+ };
+
+ let model = {
+ id: 1,
+ name: 'test',
+ mail: 'test@onlab.us',
+ active: true,
+ created: '2016-04-18T23:44:16.883181Z',
+ custom: 'MyCustomValue'
+ };
+
+ let customField = {
+ custom: {
+ label: 'Custom Label',
+ type: 'number',
+ validators: {}
+ }
+ };
+
+ let formObject = {
+ id: {
+ label: 'Id:',
+ type: 'number',
+ validators: {}
+ },
+ name: {
+ label: 'Name:',
+ type: 'text',
+ validators: {}
+ },
+ mail: {
+ label: 'Mail:',
+ type: 'email',
+ validators: {}
+ },
+ active: {
+ label: 'Active:',
+ type: 'boolean',
+ validators: {}
+ },
+ created: {
+ label: 'Created:',
+ type: 'date',
+ validators: {}
+ },
+ custom: {
+ label: 'Custom Label:',
+ type: 'number',
+ validators: {}
+ }
+ };
+
+ // load the application module
+ beforeEach(module('xos.helpers'));
+
+ // inject the cartService
+ beforeEach(inject(function (_XosFormHelpers_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ service = _XosFormHelpers_;
+ }));
+
+ describe('the _isEmail method', () => {
+ it('should return true', () => {
+ expect(service._isEmail('test@onlab.us')).toEqual(true);
+ });
+ it('should return false', () => {
+ expect(service._isEmail('testonlab.us')).toEqual(false);
+ expect(service._isEmail('test@onlab')).toEqual(false);
+ });
+ });
+
+ describe('the _getFieldFormat method', () => {
+ it('should return text', () => {
+ expect(service._getFieldFormat('a random text')).toEqual('text');
+ expect(service._getFieldFormat(null)).toEqual('text');
+ expect(service._getFieldFormat('1')).toEqual('text');
+ });
+ it('should return mail', () => {
+ expect(service._getFieldFormat('test@onlab.us')).toEqual('email');
+ });
+ it('should return number', () => {
+ expect(service._getFieldFormat(1)).toEqual('number');
+ });
+ it('should return boolean', () => {
+ expect(service._getFieldFormat(false)).toEqual('boolean');
+ expect(service._getFieldFormat(true)).toEqual('boolean');
+ });
+
+ it('should return date', () => {
+ expect(service._getFieldFormat('2016-04-19T23:09:1092Z')).toEqual('text');
+ expect(service._getFieldFormat(new Date())).toEqual('date');
+ expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
+ });
+
+ it('should return array', () => {
+ expect(service._getFieldFormat([])).toEqual('array');
+ expect(service._getFieldFormat(['a', 'b'])).toEqual('array');
+ });
+
+ it('should return object', () => {
+ expect(service._getFieldFormat({})).toEqual('object');
+ expect(service._getFieldFormat({foo: 'bar'})).toEqual('object');
+ });
+ });
+
+ it('should convert the fields array in an empty form object', () => {
+ expect(service.parseModelField(fields)).toEqual(modelField);
+ });
+
+ describe('when modelField are provided', () => {
+ it('should combine modelField and customField in a form object', () => {
+ expect(service.buildFormStructure(modelField, customField, model)).toEqual(formObject);
+ });
+ });
+
+ describe('when model field is an empty array', () => {
+ let empty_modelField = {
+ // 5: {}
+ };
+ let empty_customFields = {
+ id: {
+ label: 'Id',
+ type: 'number'
+ },
+ name: {
+ label: 'Name',
+ type: 'text'
+ },
+ mail: {
+ label: 'Mail',
+ type: 'email'
+ },
+ active: {
+ label: 'Active',
+ type: 'boolean'
+ },
+ created: {
+ label: 'Created',
+ type: 'date'
+ },
+ custom: {
+ label: 'Custom Label',
+ type: 'number'
+ }
+ };
+
+ let empty_formObject = {
+ id: {
+ label: 'Id:',
+ type: 'number',
+ validators: {}
+ },
+ name: {
+ label: 'Name:',
+ type: 'text',
+ validators: {}
+ },
+ mail: {
+ label: 'Mail:',
+ type: 'email',
+ validators: {}
+ },
+ active: {
+ label: 'Active:',
+ type: 'boolean',
+ validators: {}
+ },
+ created: {
+ label: 'Created:',
+ type: 'date',
+ validators: {}
+ },
+ custom: {
+ label: 'Custom Label:',
+ type: 'number',
+ validators: {}
+ }
+ };
+
+ let empty_model = {5: 'Nan'}
+
+ it('should create a form object', () => {
+ let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model)
+ expect(res.id).toEqual(empty_formObject.id);
+ expect(res.name).toEqual(empty_formObject.name);
+ expect(res.mail).toEqual(empty_formObject.mail);
+ expect(res.active).toEqual(empty_formObject.active);
+ expect(res.created).toEqual(empty_formObject.created);
+ expect(res.custom).toEqual(empty_formObject.custom);
+ expect(res).toEqual(empty_formObject);
+ });
+ });
+ });
+ });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/field.test.js b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
index 9e7a7f2..c308417 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/field.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
@@ -40,9 +40,7 @@
type: 'number',
validators: {}
};
- scope.ngModel = {
- label: 1
- };
+ scope.ngModel = 1;
compileElement();
}
expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field name'));
@@ -53,9 +51,7 @@
// setup the parent scope
scope = $rootScope.$new();
scope.name = 'label';
- scope.ngModel = {
- label: 1
- };
+ scope.ngModel = 1;
compileElement();
}
expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field definition'));
@@ -75,6 +71,121 @@
}
expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide an ng-model'));
}));
+
+ describe('when a text input is passed', () => {
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.name = 'label';
+ scope.field = {
+ label: 'Label',
+ type: 'text',
+ validators: {}
+ };
+ scope.ngModel = 'label';
+ compileElement();
+ });
+
+ it('should print a text field', () => {
+ expect($(element).find('[name="label"]')).toHaveAttr('type', 'text');
+ });
+ });
+
+ describe('when a number input is passed', () => {
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.name = 'label';
+ scope.field = {
+ label: 'Label',
+ type: 'number',
+ validators: {}
+ };
+ scope.ngModel = 10;
+ compileElement();
+ });
+
+ it('should print a number field', () => {
+ expect($(element).find('[name="label"]')).toHaveAttr('type', 'number');
+ });
+ });
+
+ describe('when a boolean input is passed', () => {
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.name = 'label';
+ scope.field = {
+ label: 'Label',
+ type: 'boolean',
+ validators: {}
+ };
+ scope.ngModel = true;
+ compileElement();
+ });
+
+ let setFalse, setTrue;
+
+ beforeEach(() => {
+ setFalse= $(element).find('.boolean-field > button:first-child');
+ setTrue = $(element).find('.boolean-field > button:last-child');
+ });
+
+ it('should print two buttons', () => {
+ expect($(element).find('.boolean-field > button').length).toEqual(2)
+ });
+
+ it('should change value to false', () => {
+ expect(isolatedScope.ngModel).toEqual(true);
+ setFalse.click()
+ expect(isolatedScope.ngModel).toEqual(false);
+ });
+
+ it('should change value to true', () => {
+ isolatedScope.ngModel = false;
+ scope.$apply();
+ expect(isolatedScope.ngModel).toEqual(false);
+ setTrue.click()
+ expect(isolatedScope.ngModel).toEqual(true);
+ });
+ });
+
+ describe('when an object input is passed', () => {
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.name = 'label';
+ scope.field = {
+ label: 'Label',
+ type: 'object',
+ validators: {}
+ };
+ scope.ngModel = {
+ baz: true,
+ foo: 'bar',
+ foz: 1,
+ };
+ compileElement();
+ });
+
+ it('should print a panel to contain object property field', () => {
+ expect($(element).find('.panel.object-field')).toExist()
+ });
+
+ it('should print the right input type for each property', () => {
+ expect($(element).find('input').length).toBe(2);
+ expect($(element).find('.boolean-field > button').length).toEqual(2);
+ });
+
+ describe('and the model is empty', () => {
+ beforeEach(() => {
+ scope.ngModel = {
+ };
+ compileElement();
+ });
+
+ it('should not print the panel', () => {
+ console.log($(element).find('.panel.object-field'));
+ expect($(element).find('.panel.object-field')).not.toExist()
+ });
+ });
+ });
});
});
})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/form.test.js b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
index 7673fc8..5f73f30 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/form.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
@@ -9,221 +9,6 @@
describe('The xos.helper module', function(){
- // TODO move in separate file
- describe('The XosFormHelper service', () => {
- let service;
-
- let fields = [
- 'id',
- 'name',
- 'mail',
- 'active',
- 'created',
- 'custom'
- ];
-
- let modelField = {
- id: {},
- name: {},
- mail: {},
- active: {},
- created: {},
- custom: {}
- };
-
- let model = {
- id: 1,
- name: 'test',
- mail: 'test@onlab.us',
- active: true,
- created: '2016-04-18T23:44:16.883181Z',
- custom: 'MyCustomValue'
- };
-
- let customField = {
- custom: {
- label: 'Custom Label',
- type: 'number',
- validators: {}
- }
- };
-
- let formObject = {
- id: {
- label: 'Id:',
- type: 'number',
- validators: {}
- },
- name: {
- label: 'Name:',
- type: 'string',
- validators: {}
- },
- mail: {
- label: 'Mail:',
- type: 'email',
- validators: {}
- },
- active: {
- label: 'Active:',
- type: 'boolean',
- validators: {}
- },
- created: {
- label: 'Created:',
- type: 'date',
- validators: {}
- },
- custom: {
- label: 'Custom Label:',
- type: 'number',
- validators: {}
- }
- };
-
- // load the application module
- beforeEach(module('xos.helpers'));
-
- // inject the cartService
- beforeEach(inject(function (_XosFormHelpers_) {
- // The injector unwraps the underscores (_) from around the parameter names when matching
- service = _XosFormHelpers_;
- }));
-
- describe('the _isEmail method', () => {
- it('should return true', () => {
- expect(service._isEmail('test@onlab.us')).toEqual(true);
- });
- it('should return false', () => {
- expect(service._isEmail('testonlab.us')).toEqual(false);
- expect(service._isEmail('test@onlab')).toEqual(false);
- });
- });
-
- describe('the _getFieldFormat method', () => {
- it('should return string', () => {
- expect(service._getFieldFormat('string')).toEqual('string');
- expect(service._getFieldFormat(null)).toEqual('string');
- });
- it('should return mail', () => {
- expect(service._getFieldFormat('test@onlab.us')).toEqual('email');
- });
- it('should return number', () => {
- expect(service._getFieldFormat(1)).toEqual('number');
- // this is skipped because not realistic and js Date sucks
- // expect(service._getFieldFormat('1')).toEqual('number');
- });
- it('should return boolean', () => {
- expect(service._getFieldFormat(false)).toEqual('boolean');
- expect(service._getFieldFormat(true)).toEqual('boolean');
- });
-
- it('should return date', () => {
- expect(service._getFieldFormat('2016-04-19T23:09:1092Z')).toEqual('string');
- expect(service._getFieldFormat(new Date())).toEqual('date');
- expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
- });
-
- it('should return array', () => {
- expect(service._getFieldFormat([])).toEqual('array');
- expect(service._getFieldFormat(['a', 'b'])).toEqual('array');
- });
-
- it('should return object', () => {
- expect(service._getFieldFormat({})).toEqual('object');
- expect(service._getFieldFormat({foo: 'bar'})).toEqual('object');
- });
- });
-
- it('should convert the fields array in an empty form object', () => {
- expect(service.parseModelField(fields)).toEqual(modelField);
- });
-
- describe('when modelField are provided', () => {
- it('should combine modelField and customField in a form object', () => {
- expect(service.buildFormStructure(modelField, customField, model)).toEqual(formObject);
- });
- });
-
- describe('when model field is an empty array', () => {
- let empty_modelField = {
- // 5: {}
- };
- let empty_customFields = {
- id: {
- label: 'Id',
- type: 'number'
- },
- name: {
- label: 'Name',
- type: 'string'
- },
- mail: {
- label: 'Mail',
- type: 'email'
- },
- active: {
- label: 'Active',
- type: 'boolean'
- },
- created: {
- label: 'Created',
- type: 'date'
- },
- custom: {
- label: 'Custom Label',
- type: 'number'
- }
- };
-
- let empty_formObject = {
- id: {
- label: 'Id:',
- type: 'number',
- validators: {}
- },
- name: {
- label: 'Name:',
- type: 'string',
- validators: {}
- },
- mail: {
- label: 'Mail:',
- type: 'email',
- validators: {}
- },
- active: {
- label: 'Active:',
- type: 'boolean',
- validators: {}
- },
- created: {
- label: 'Created:',
- type: 'date',
- validators: {}
- },
- custom: {
- label: 'Custom Label:',
- type: 'number',
- validators: {}
- }
- };
-
- let empty_model = {5: 'Nan'}
-
- it('should create a form object', () => {
- let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model)
- expect(res.id).toEqual(empty_formObject.id);
- expect(res.name).toEqual(empty_formObject.name);
- expect(res.mail).toEqual(empty_formObject.mail);
- expect(res.active).toEqual(empty_formObject.active);
- expect(res.created).toEqual(empty_formObject.created);
- expect(res.custom).toEqual(empty_formObject.custom);
- expect(res).toEqual(empty_formObject);
- });
- });
- });
-
describe('The xos-form component', () => {
let element, scope, isolatedScope;
@@ -304,7 +89,7 @@
expect(isolatedScope.excludedField).toEqual(expected);
});
- xit('should render 8 input field', () => {
+ it('should render 10 input field', () => {
// boolean are in the form model, but are not input
expect(Object.keys(isolatedScope.formField).length).toEqual(9);
var field = element[0].getElementsByTagName('input');
@@ -312,7 +97,6 @@
});
it('should render 1 boolean field', () => {
- // console.log($(element).find('.boolean-field'));
expect($(element).find('.boolean-field > button').length).toEqual(2)
});
@@ -410,10 +194,6 @@
expect(isolatedScope.testForm.age.$error.min).toBeTruthy();
});
});
-
- describe('the object field', () => {
-
- });
});
});
});
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
index ce52272..c850f48 100644
--- a/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
@@ -53,19 +53,14 @@
return 'boolean';
}
- // check if a string is a number
- if(!isNaN(value) && value !== null){
- return 'number';
- }
-
// check if a string is an email
if(this._isEmail(value)){
return 'email';
}
// if null return string
- if(value === null){
- return 'string';
+ if(typeof value === 'string' || value === null){
+ return 'text';
}
return typeof value;
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
index 923def6..c2aa62d 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
@@ -27,7 +27,7 @@
* ```
* @param {mixed} ngModel The field value
*/
- .directive('xosField', function(){
+ .directive('xosField', function(RecursionHelper){
return {
restrict: 'E',
scope: {
@@ -36,7 +36,7 @@
ngModel: '='
},
template: `
- <label>{{vm.field.label}}</label>
+ <label ng-if="vm.field.type !== 'object'">{{vm.field.label}}</label>
<input
ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object'"
type="{{vm.field.type}}"
@@ -62,27 +62,41 @@
</span>
<div
class="panel panel-default object-field"
- ng-if="vm.field.type == 'object' "
+ ng-if="vm.field.type == 'object' && !vm.isEmptyObject(vm.ngModel)"
>
- <div class="panel-heading">Panel heading without title</div>
+ <div class="panel-heading">{{vm.field.label}}</div>
<div class="panel-body">
- Panel content
+ <div ng-repeat="(k, v) in vm.ngModel">
+ <xos-field
+ name="k"
+ field="{label: k, type: vm.getType(v)}"
+ ng-model="v">
+ </xos-field>
+ </div>
</div>
</div>
`,
bindToController: true,
controllerAs: 'vm',
- controller: function(){
- // console.log('Field: ', this.name, this.field.type, this.ngModel);
+ // the compile cicle is needed to support recursion
+ compile: function (element) {
+ return RecursionHelper.compile(element);
+ },
+ controller: function(XosFormHelpers){
+ // console.log('Field: ', this.name, this.field, this.ngModel);
if(!this.name){
throw new Error('[xosField] Please provide a field name');
}
if(!this.field){
throw new Error('[xosField] Please provide a field definition');
}
- if(!this.ngModel){
+ if(!angular.isDefined(this.ngModel)){
throw new Error('[xosField] Please provide an ng-model');
}
+
+ this.getType = XosFormHelpers._getFieldFormat;
+
+ this.isEmptyObject = o => Object.keys(o).length === 0;
}
}
});
diff --git a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
index 4af3680..4ffc99d 100644
--- a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
+++ b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
@@ -25,6 +25,7 @@
'ngAnimate',
'bugSnag',
'xos.uiComponents',
+ 'RecursionHelper'
])
.config(config)