blob: 5f2443be5b5c9e66129e3a568cf4a7d1c03acd9d [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 Scandoloc3c697a2016-04-26 15:56:05 -0700125 // NOTE
126 // Corner case
127 // - if response is empty, how can we generate a form ?
128
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700129 this.responseMsg = false;
130 this.responseErr = false;
131
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700132 this.tableConfig = {
133 columns: [
134 ],
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700135 actions: [
136 {
137 label: 'delete',
138 icon: 'remove',
139 cb: (item) => {
140 this.Resource.delete({id: item.id}).$promise
141 .then(() => {
Matteo Scandolob7dac502016-04-28 13:14:08 -0700142 _.remove(this.data, (d) => d.id === item.id);
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700143 this.responseMsg = `${this.config.resource} with id ${item.id} successfully deleted`;
144 })
145 .catch(err => {
146 this.responseErr = err.data.detail || `Error while deleting ${this.config.resource} with id ${item.id}`;
147 });
148 },
149 color: 'red'
150 },
151 {
152 label: 'details',
153 icon: 'search',
154 cb: (item) => {
155 this.detailedItem = item;
156 }
157 }
158 ],
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700159 classes: 'table table-striped table-bordered table-responsive',
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700160 filter: 'field',
161 order: true,
162 pagination: {
163 pageSize: 10
164 }
165 };
166
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700167 this.formConfig = {
168 exclude: this.config.hiddenFields,
Matteo Scandolob7dac502016-04-28 13:14:08 -0700169 fields: {},
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700170 formName: `${this.config.resource}Form`,
171 actions: [
172 {
173 label: 'Save',
174 icon: 'ok',
175 cb: (item) => {
176 item.$save()
Matteo Scandolob7dac502016-04-28 13:14:08 -0700177 .then((res) => {
178 this.data.push(angular.copy(res));
179 delete this.detailedItem;
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700180 this.responseMsg = `${this.config.resource} with id ${item.id} successfully saved`;
181 })
182 .catch((err) => {
183 this.responseErr = err.data.detail || `Error while saving ${this.config.resource} with id ${item.id}`;
184 })
185 },
186 class: 'success'
187 }
188 ]
Matteo Scandolof6445352016-04-26 12:15:23 -0700189 };
190
191 this.cleanForm = () => {
192 delete this.detailedItem;
Matteo Scandoloc3c697a2016-04-26 15:56:05 -0700193 };
194
195 this.createItem = () => {
196 this.detailedItem = new this.Resource();
Matteo Scandoloc3c697a2016-04-26 15:56:05 -0700197 };
Matteo Scandolodc249eb2016-04-26 11:44:36 -0700198
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700199 this.Resource = $injector.get(this.config.resource);
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700200
Matteo Scandolob7dac502016-04-28 13:14:08 -0700201 const getData = () => {
202 this.Resource.query().$promise
203 .then((res) => {
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700204
Matteo Scandolob7dac502016-04-28 13:14:08 -0700205 if(!res[0]){
206 return;
207 }
Matteo Scandoloba1d35c2016-04-26 10:10:54 -0700208
Matteo Scandolob7dac502016-04-28 13:14:08 -0700209 let item = res[0];
210 let props = Object.keys(item);
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700211
Matteo Scandolob7dac502016-04-28 13:14:08 -0700212 _.remove(props, p => {
213 return p == 'id' || p == 'password' || p == 'validators'
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700214 });
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700215
Matteo Scandolob7dac502016-04-28 13:14:08 -0700216 // TODO move out cb
217 if(angular.isArray(this.config.hiddenFields)){
218 props = _.difference(props, this.config.hiddenFields)
219 }
220
221 let labels = props.map(p => LabelFormatter.format(p));
222
223 props.forEach((p, i) => {
224 this.tableConfig.columns.push({
225 label: labels[i],
226 prop: p
227 });
Matteo Scandoloe2ee2d92016-04-27 15:58:16 -0700228 });
Matteo Scandolo6ba12872016-04-27 16:29:33 -0700229
Matteo Scandolob7dac502016-04-28 13:14:08 -0700230 // build form structure
231 props.forEach((p, i) => {
232 this.formConfig.fields[p] = {
233 label: LabelFormatter.format(labels[i]).replace(':', ''),
234 type: XosFormHelpers._getFieldFormat(item[p])
235 };
236 });
237
238 this.data = res;
239 });
240 }
241
242 getData();
Matteo Scandolo8b55d9f2016-04-25 17:50:28 -0700243 }
244 };
245 });
246})();