blob: 8cbe0af99d7f043a2fd2843d66539566cc8fbcba [file] [log] [blame]
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -07001/**
2 * © OpenCORD
3 *
4 * Visit http://guide.xosproject.org/devguide/addview/ for more information
5 *
6 * Created by teone on 3/24/16.
7 */
8
9(function () {
10 'use strict';
11
12 angular.module('xos.uiComponents')
13
14 /**
15 * @ngdoc directive
16 * @name xos.uiComponents.directive:xosSmartTable
Matteo Scandolo71378f92016-04-28 14:16:45 -070017 * @link xos.uiComponents.directive:xosTable xosTable
18 * @link xos.uiComponents.directive:xosForm xosForm
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -070019 * @restrict E
20 * @description The xos-table directive
Matteo Scandolob7dac502016-04-28 13:14:08 -070021 * @param {Object} config The configuration for the component,
22 * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
23 * and an array of fields that shouldn't be printed.
24 * ```
25 * {
26 resource: 'Users',
27 hiddenFields: []
28 }
29 * ```
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -070030 * @scope
31 * @example
Matteo Scandolob7dac502016-04-28 13:14:08 -070032
33 <example module="sampleSmartTable">
34 <file name="index.html">
35 <div ng-controller="SampleCtrl as vm">
36 <xos-smart-table config="vm.config"></xos-smart-table>
37 </div>
38 </file>
39 <file name="script.js">
40 angular.module('sampleSmartTable', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
41 // This is only for documentation purpose
42 .run(function($httpBackend, _){
43 let datas = [{id: 1, name: 'Jhon', surname: 'Doe'}];
44 let count = 1;
45
46 let paramsUrl = new RegExp(/\/test\/(.+)/);
47
48 $httpBackend.whenDELETE(paramsUrl, undefined, ['id']).respond((method, url, data, headers, params) => {
49 data = angular.fromJson(data);
50 let id = url.match(paramsUrl)[1];
51 _.remove(datas, (d) => {
52 return d.id === parseInt(id);
53 })
54 return [204];
55 });
56
57 $httpBackend.whenGET('/test').respond(200, datas)
58 $httpBackend.whenPOST('/test').respond((method, url, data) => {
59 data = angular.fromJson(data);
60 data.id = ++count;
61 datas.push(data);
62 return [201, data, {}];
63 });
64 })
65 .factory('_', function($window){
66 return $window._;
67 })
68 .service('SampleResource', function($resource){
69 return $resource('/test/:id', {id: '@id'});
70 })
71 // End of documentation purpose, example start
72 .controller('SampleCtrl', function(){
73 this.config = {
74 resource: 'SampleResource'
75 };
76 });
77 </file>
78 </example>
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -070079 */
80
81 .directive('xosSmartTable', function(){
82 return {
83 restrict: 'E',
84 scope: {
85 config: '='
86 },
87 template: `
Matteo Scandoloc3c697a2016-04-26 15:56:05 -070088 <div class="row" ng-show="vm.data.length > 0">
89 <div class="col-xs-12 text-right">
90 <a href="" class="btn btn-success" ng-click="vm.createItem()">
91 Add
92 </a>
93 </div>
94 </div>
Matteo Scandoloe2ee2d92016-04-27 15:58:16 -070095 <div class="row">
96 <div class="col-xs-12 table-responsive">
97 <xos-table config="vm.tableConfig" data="vm.data"></xos-table>
98 </div>
99 </div>
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700100 <div class="panel panel-default" ng-show="vm.detailedItem">
101 <div class="panel-heading">
Matteo Scandolof6445352016-04-26 12:15:23 -0700102 <div class="row">
103 <div class="col-xs-11">
Matteo Scandoloe2ee2d92016-04-27 15:58:16 -0700104 <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>
105 <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>
Matteo Scandolof6445352016-04-26 12:15:23 -0700106 </div>
107 <div class="col-xs-1">
108 <a href="" ng-click="vm.cleanForm()">
109 <i class="glyphicon glyphicon-remove pull-right"></i>
110 </a>
111 </div>
112 </div>
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700113 </div>
114 <div class="panel-body">
115 <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>
116 </div>
117 </div>
118 <xos-alert config="{type: 'success', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>
119 <xos-alert config="{type: 'danger', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700120 `,
121 bindToController: true,
122 controllerAs: 'vm',
Matteo Scandoloe2ee2d92016-04-27 15:58:16 -0700123 controller: function($injector, LabelFormatter, _, XosFormHelpers){
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700124
Matteo Scandolo67e79cb2016-04-29 09:14:58 -0700125 // TODO
126 // - Validate the config (what if resource does not exist?)
127
Matteo Scandoloc3c697a2016-04-26 15:56:05 -0700128 // NOTE
129 // Corner case
130 // - if response is empty, how can we generate a form ?
131
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700132 this.responseMsg = false;
133 this.responseErr = false;
134
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700135 this.tableConfig = {
136 columns: [
137 ],
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700138 actions: [
139 {
140 label: 'delete',
141 icon: 'remove',
142 cb: (item) => {
Matteo Scandolo67e79cb2016-04-29 09:14:58 -0700143 console.log(item);
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700144 this.Resource.delete({id: item.id}).$promise
145 .then(() => {
Matteo Scandolob7dac502016-04-28 13:14:08 -0700146 _.remove(this.data, (d) => d.id === item.id);
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700147 this.responseMsg = `${this.config.resource} with id ${item.id} successfully deleted`;
148 })
149 .catch(err => {
150 this.responseErr = err.data.detail || `Error while deleting ${this.config.resource} with id ${item.id}`;
151 });
152 },
153 color: 'red'
154 },
155 {
156 label: 'details',
157 icon: 'search',
158 cb: (item) => {
159 this.detailedItem = item;
160 }
161 }
162 ],
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700163 classes: 'table table-striped table-bordered table-responsive',
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700164 filter: 'field',
165 order: true,
166 pagination: {
167 pageSize: 10
168 }
169 };
170
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700171 this.formConfig = {
172 exclude: this.config.hiddenFields,
Matteo Scandolob7dac502016-04-28 13:14:08 -0700173 fields: {},
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700174 formName: `${this.config.resource}Form`,
175 actions: [
176 {
177 label: 'Save',
178 icon: 'ok',
179 cb: (item) => {
Matteo Scandolo67e79cb2016-04-29 09:14:58 -0700180 let p;
181 let isNew = true;
182
183 if(item.id){
184 p = item.$update();
185 isNew = false;
186 }
187 else {
188 p = item.$save();
189 }
190
191 p.then((res) => {
192 if(isNew){
193 this.data.push(angular.copy(res));
194 }
Matteo Scandolob7dac502016-04-28 13:14:08 -0700195 delete this.detailedItem;
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700196 this.responseMsg = `${this.config.resource} with id ${item.id} successfully saved`;
197 })
198 .catch((err) => {
199 this.responseErr = err.data.detail || `Error while saving ${this.config.resource} with id ${item.id}`;
200 })
201 },
202 class: 'success'
203 }
204 ]
Matteo Scandolof6445352016-04-26 12:15:23 -0700205 };
206
207 this.cleanForm = () => {
208 delete this.detailedItem;
Matteo Scandoloc3c697a2016-04-26 15:56:05 -0700209 };
210
211 this.createItem = () => {
212 this.detailedItem = new this.Resource();
Matteo Scandoloc3c697a2016-04-26 15:56:05 -0700213 };
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700214
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700215 this.Resource = $injector.get(this.config.resource);
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700216
Matteo Scandolob7dac502016-04-28 13:14:08 -0700217 const getData = () => {
218 this.Resource.query().$promise
219 .then((res) => {
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700220
Matteo Scandolob7dac502016-04-28 13:14:08 -0700221 if(!res[0]){
222 return;
223 }
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700224
Matteo Scandolob7dac502016-04-28 13:14:08 -0700225 let item = res[0];
226 let props = Object.keys(item);
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700227
Matteo Scandolob7dac502016-04-28 13:14:08 -0700228 _.remove(props, p => {
Matteo Scandolo67e79cb2016-04-29 09:14:58 -0700229 return p == 'id' || p == 'validators'
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700230 });
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700231
Matteo Scandolob7dac502016-04-28 13:14:08 -0700232 // TODO move out cb
233 if(angular.isArray(this.config.hiddenFields)){
234 props = _.difference(props, this.config.hiddenFields)
235 }
236
237 let labels = props.map(p => LabelFormatter.format(p));
238
239 props.forEach((p, i) => {
240 this.tableConfig.columns.push({
241 label: labels[i],
242 prop: p
243 });
Matteo Scandoloe2ee2d92016-04-27 15:58:16 -0700244 });
Matteo Scandolo6ba12872016-04-27 16:29:33 -0700245
Matteo Scandolob7dac502016-04-28 13:14:08 -0700246 // build form structure
247 props.forEach((p, i) => {
248 this.formConfig.fields[p] = {
249 label: LabelFormatter.format(labels[i]).replace(':', ''),
250 type: XosFormHelpers._getFieldFormat(item[p])
251 };
252 });
253
254 this.data = res;
255 });
256 }
257
258 getData();
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700259 }
260 };
261 });
262})();