md-crud
Version:
Angular material directive to create customizable CRUD forms.
788 lines (711 loc) • 57.6 kB
JavaScript
/**
* md-crud - Angular material directive to create customizable CRUD forms.
* @version v1.0.0
* @link https://github.com/ClassHP/md-crud
* @license MIT
*/
angular.module('mdCrudTemplates', []).run(['$templateCache', function($templateCache) {$templateCache.put('/views/crud.html','<div class="md-default" layout="row" layout-align="start center"><md-button class="md-raised md-primary" ng-click="table.create($event)" ng-if="!options.noCreate" ng-disabled="isLoading">{{translate(text.createOption)}}</md-button><div ng-if="options.templateTools" ng-include="options.templateTools" flex layout="row"></div><div flex></div><div layout="row" ng-if="!options.noSearch" style="margin-bottom:5px"><md-button class="md-icon-button md-primary" ng-disabled="true"><md-icon></md-icon></md-button><md-autocomplete md-search-text="searchText" type="search" placeholder="" md-items="item in []" md-search-text-change="onSearchTextChange(searchText)" md-delay="searchDelay"></md-autocomplete></div></div><div ng-if="formType == \'inline\' && rowCreate"><md-card flex layout-fill style="background-color: white"><md-crud-form options="options" ng-model="rowCreate" on-open="onOpen" on-edit="onEdit" on-detail="onDetail" on-cancel="onCancel" on-sussces="onSussces" on-submit="onSubmit" template-url="templateUrl" editable="true"></md-crud-form></md-card><br></div><md-table-container md-whiteframe="1"><table data-md-table md-progress="table.promise"><thead md-head data-md-order="table.order" md-on-reorder="table.refresh" style="background-color: white"><tr md-row><th md-column ng-repeat="field in fields" ng-if="!field.columnHiden && !field.columnHidden">{{translate(field.columnHeader || field.label)}}</th><th md-column style="min-width:132px;width:132px" ng-if="!options.noDelete && !options.noEdit"></th><th md-column style="min-width:60px;width:60px" ng-if="(options.noEdit && !options.noDelete) || (!options.noEdit && options.noDelete)"></th></tr></thead><tbody md-body><tr md-row md-select="row" ng-repeat-start="row in (options.serverSide ? table.rows : (table.rows | filter:searchText | limitTo: table.limit: (table.page - 1) * table.limit))" ng-mouseover="row.mouserover=true" ng-mouseleave="row.mouserover=false" ng-class="{ \'md-selected\': row.mouserover || rowSelected == row }" ng-click="table.detail(row, $event)" style="cursor:pointer"><td md-cell ng-repeat="field in fields" ng-if="!field.columnHiden && !field.columnHidden" ng-style="field.styleCell" md-crud-template="getTemplateColumn(field, row)"></td><td md-cell ng-if="!options.noDelete || !options.noEdit"><md-button class="md-icon-button md-accent" ng-show="row.mouserover || rowSelected == row " ng-click="table.edit(row, $event)" ng-if="!options.noEdit"><md-icon></md-icon></md-button><md-button class="md-icon-button md-warn" ng-show="row.mouserover || rowSelected == row " ng-click="table.delete(row[options.id], $event)" ng-if="!options.noDelete"><md-icon></md-icon></md-button></td></tr><tr ng-repeat-end ng-if="rowSelected == row"><td colspan="{{countFieldsColums()}}" style="max-width: 0"><md-card layout-fill style="background-color: white"><md-crud-form ng-if="formEditable" options="options" ng-model="row" on-open="onOpen" on-edit="onEdit" on-detail="onDetail" on-cancel="onCancel" on-sussces="onSussces" on-submit="onSubmit" template-url="templateUrl" editable="formEditable" model-copy="true"></md-crud-form><md-crud-form ng-if="!formEditable" options="options" ng-model="row" on-open="onOpen" on-edit="onEdit" on-detail="onDetail" on-cancel="onCancel" on-sussces="onSussces" on-submit="onSubmit" template-url="templateUrl" editable="formEditable" model-copy="true"></md-crud-form></md-card></td></tr></tbody></table><md-table-pagination ng-if="!options.noPaginate" md-limit="table.limit" md-limit-options="table.limitOptions" md-page="table.page" md-total="{{options.serverSide ? table.total : (table.rows | filter:searchText).length}}" md-page-select md-label="{{table.labels()}}" style="background-color: white" md-on-paginate="table.onPaginate"></md-table-pagination></md-table-container>');
$templateCache.put('/views/crudForm.html','<div layout-padding><form name="formCrud" ng-submit="isFormValid(formCrud) && save()" novalidate><md-crud-form-base flex layout="row" layout-wrap options="options" ng-model="item" form-type="formType" editable="editable" form-crud="formCrud" is-loading="isLoading"></md-crud-form-base><div ng-repeat="message in errors" md-colors="{ color: \'default-warn\' }" flex="grow">{{translate(message)}}</div><div layout="row" layout-align="center center" flex="grow" ng-if="!(formType==\'detail\' && options.noDetailButtons) && !options.noButtons"><md-button class="md-raised" ng-click="cancel()" ng-disabled="isLoading">{{translate(options.formCancelText || text.formCancel)}}</md-button><div flex="5"></div><md-button class="md-raised md-primary" type="submit" ng-disabled="ef(options.readonly, item) || readonly || isLoading">{{translate(options.formSubmitText || text.formSubmit)}}</md-button></div></form></div>');
$templateCache.put('/views/crudFormBase.html','<div ng-repeat="field in fields" flex="{{field.flex || \'grow\'}}" flex-xs="100" ng-style="field.style" ng-if="(formType==\'create\' && !ef(field.createHiden || field.createHidden, item)) || (formType==\'edit\' && !ef(field.editHiden || field.editHidden, item)) || (formType==\'detail\' && !ef(field.detailHiden || field.detailHidden, item))"><div ng-switch="ef(field.type, item)" ng-if="!field.templateUrl && !field.template"><md-input-container class="md-block" flex ng-switch-default ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label>{{translate(field.label)}}</label><input ng-model="item[field.name]" name="{{field.name}}" ng-required="field.required" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-minlength="field.minlength" ng-maxlength="field.maxlength" ng-blur="field.onChange && field.onChange(item, formType)" ng-pattern="field.pattern" md-crud-input-validator="field.errorMessage" item="item"><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><md-input-container class="md-block" flex ng-switch-when="textarea" ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label>{{translate(field.label)}}</label><textarea ng-model="item[field.name]" name="{{field.name}}" ng-required="field.required" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-minlength="field.minlength" ng-maxlength="field.maxlength" rows="{{ field.rows || 3 }}" md-select-on-focus ng-blur="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item"></textarea><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><md-input-container class="md-block" flex ng-switch-when="email" ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label>{{translate(field.label)}}</label><input ng-model="item[field.name]" name="{{field.name}}" ng-required="field.required" type="email" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-minlength="field.minlength" ng-maxlength="field.maxlength" ng-pattern="field.pattern" ng-blur="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item"><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><md-input-container class="md-block" flexemail flex ng-switch-when="integer" ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label>{{translate(field.label)}}</label><input type="number" ng-model="item[field.name]" name="{{field.name}}" ng-required="field.required" md-crud-input-number ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-min="field.min" ng-max="field.max" step="{{field.step || 1}}" ng-blur="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item"><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><md-input-container class="md-block" flex ng-switch-when="decimal" ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label>{{translate(field.label)}}</label><input type="number" ng-model="item[field.name]" name="{{field.name}}" ng-required="field.required" md-crud-input-number ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-min="field.min" ng-max="field.max" step="{{field.step || \'any\'}}" ng-blur="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item"><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><div class="md-block" flex ng-switch-when="image"><lf-ng-md-file-input name="{{field.name}}" lf-files="files[field.name]" lf-mimetype="image/*" lf-placeholder="{{field.label}}" lf-browse-label="Abrir" lf-remove-label="Eliminar"></lf-ng-md-file-input><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div><br></div><div class="md-block" flex ng-switch-when="map"><ng-map zoom="{{field.zoom || 11}}" center="{{item[field.lat]}},{{item[field.lng]}}"><marker position="{{item[field.lat]}},{{item[field.lng]}}" title="drag me" draggable="true" on-dragend="onMarkerDrag()" data="{{field}}"></marker></ng-map></div><div class="md-block" flex ng-switch-when="boolean"><md-switch ng-model="item[field.name]" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" aria-label="field.label" ng-true-value="{{\'\\\'\'+ field.trueValue + \'\\\'\'}}" ng-if="field.trueValue" ng-change="field.onChange && field.onChange(item, formType)">{{translate(((item[field.name] == field.trueValue) ? field.trueLabel : field.falseLabel) || field.label)}}</md-switch><md-switch ng-model="item[field.name]" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" aria-label="field.label" ng-if="!field.trueValue" ng-change="field.onChange && field.onChange(item, formType)">{{translate((item[field.name] ? field.trueLabel : field.falseLabel) || field.label)}}</md-switch></div><md-input-container class="md-block" flex ng-switch-when="select" ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label>{{translate(field.label)}}</label><md-select ng-model="item[field.name]" ng-if="field.multiple" name="{{field.name}}" multiple="multiple" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-required="field.required" ng-change="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item" md-on-open="field.onOpen(item)"><md-option ng-value="option[field.value || \'value\']" ng-repeat="option in ef(field.data, item)"><md-text md-crud-template="templateSelect(field)"></md-text></md-option></md-select><md-select ng-model="item[field.name]" ng-if="!field.multiple" name="{{field.name}}" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-required="field.required" ng-change="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item" md-on-open="field.onOpen(item)"><md-option ng-if="!field.required"></md-option><md-option ng-value="option[field.value || \'value\']" ng-repeat="option in ef(field.data, item)" md-crud-template="templateSelect(field)"></md-option></md-select><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><md-input-container class="md-block" flex ng-switch-when="date" ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label>{{translate(field.label)}}</label><md-datepicker ng-model="item[field.name]" name="{{field.name}}" md-min-date="ef(field.minDate, item)" md-max-date="ef(field.maxDate, item)" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-required="field.required" md-crud-input-date aria-label="{{translate(field.label)}}" ng-change="field.onChange && field.onChange(item, formType)"></md-datepicker><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><md-input-container class="md-block" ng-switch-when="time" flex ng-class="{ \'hide-error-msg\': field.hideErrorMsg }"><label style="margin-left: 50px">{{translate(field.label)}}</label><div class="" layout="row" layout-align="start start"><md-button layout-nowrap ng-click="showTimePicker($event, item, field.name)" class="md-datepicker-button md-icon-button md-button md-ink-ripple" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading"><md-icon>access_time</md-icon></md-button><div flex><input class="md-datepicker-input md-input" type="time" name="{{field.name}}" ng-model="item[field.name]" md-crud-input-date aria-label="{{translate(field.label)}}" ng-required="field.required" flex ng-min="ef(field.min, item)" ng-max="ef(field.max, item)" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-blur="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item"><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></div></div></md-input-container><div class="md-block" ng-switch-when="datetime" flex layout="row" layout-align="start start"><md-input-container flex="none"><label style="overflow: visible;\r\n -webkit-transform: translate3d(0, 6px, 0) scale(0.75);\r\n transform: translate3d(0, 6px, 0) scale(0.75);\r\n -webkit-transition: width cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s, -webkit-transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s;\r\n transition: width cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s, -webkit-transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s;\r\n transition: transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s, width cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s;\r\n transition: transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s, width cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s, -webkit-transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s">{{translate(field.label)}}</label><md-datepicker layout-nowrap ng-model="item[field.name]" name="{{field.name}}" md-min-date="ef(field.minDate, item)" md-max-date="ef(field.maxDate, item)" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-required="field.required" md-crud-input-date aria-label="{{translate(field.label)}}" ng-change="field.onChange && field.onChange(item, formType)"></md-datepicker><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></md-input-container><md-input-container><div class="" layout="row" layout-align="start start"><md-button layout-nowrap ng-click="showTimePicker($event, item, field.name)" class="md-datepicker-button md-icon-button md-button md-ink-ripple" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading"><md-icon>access_time</md-icon></md-button><div flex><input class="md-datepicker-input md-input" type="time" name="{{field.name}}" ng-model="item[field.name]" md-crud-input-date aria-label="{{translate(field.label)}}" ng-required="field.required" flex ng-min="field.min" ng-max="field.max" ng-disabled="ef(field.readonly, item) || ef(options.readonly, item) || readonly || isLoading" ng-blur="field.onChange && field.onChange(item, formType)" md-crud-input-validator="field.errorMessage" item="item"><div ng-messages="formCrud[field.name].$error" ng-messages-multiple><div ng-messages-include="/views/crudFormMessages.html"></div></div></div></div></md-input-container></div><div class="md-block" ng-switch-when="button" flex layout-align="{{field.align}}"><md-button ng-class="field.class" ng-click="field.onClick(item)"><md-icon ng-if="field.icon">{{field.icon}}</md-icon><md-tooltip md-autohide ng-if="field.tooltip">{{translate(field.tooltip)}}</md-tooltip>{{translate(field.label)}}</md-button></div><div class="md-block" flex ng-switch-when="label"><span>{{translate(field.label)}}</span></div></div><div ng-if="field.templateUrl" ng-include="field.templateUrl"></div><div ng-if="field.template" md-crud-template="ef(field.template, item)"></div></div>');
$templateCache.put('/views/crudFormDialog.html','<md-dialog aria-label="Editar" flex="{{options.windowFlex}}"><md-toolbar><div class="md-toolbar-tools"><h2>{{ formTitle }}</h2><span flex></span><md-button class="md-icon-button" ng-click="cancelDialog()"><md-icon aria-label="Cerrar">close</md-icon></md-button></div></md-toolbar><md-dialog-content><md-crud-form options="options" ng-model="item" on-open="onOpen" on-edit="onEdit" on-detail="onDetail" on-cancel="onCancelDialog" on-sussces="onSusscesDialog" template-url="templateUrl" editable="formEditable" model-copy="true"></md-crud-form></md-dialog-content></md-dialog>');
$templateCache.put('/views/crudFormMessages.html','<div ng-message="required">{{translate(field.messageRequired || text.messageRequired)}}</div><div ng-message="minlength">{{translate(field.messageMinlength || text.messageMinlength)}} ({{field.minlength}}).</div><div ng-message="maxlength">{{translate(field.messageMaxlength || text.messageMaxlength)}} ({{field.maxlength}}).</div><div ng-message="pattern">{{translate(field.messagePattern || text.messagePattern)}}</div><div ng-message="min">{{translate(field.messageMin || text.messageMin)}} ({{field.min}}).</div><div ng-message="max">{{translate(field.messageMax || text.messageMax)}} ({{field.max}}).</div><div ng-message="mimetype">{{translate(field.messageMimetype || text.messageMimetype)}}</div><div ng-message="valid">{{translate(field.messageValid || text.messageValid)}}</div><div ng-message="mindate">{{translate(field.messageMindate || text.messageMindate)}} {{field.minDate | date:\'shortDate\'}}.</div><div ng-message="maxdate">{{translate(field.messageMaxdate || text.messageMaxdate)}} {{field.maxDate | date:\'shortDate\'}}.</div><div ng-message="mdCrudInputValidator">{{translate(ef(field.errorMessage, item[field.name], item))}}</div>');}]);
(function () {
'use strict';
/**
* @description
*
*/
angular.module('mdCrudModule', ['mdCrudTemplates']);
})();
(function () {
'use strict';
angular
.module('mdCrudModule')
.directive('mdCrud', crudDirective);
crudDirective.$inject = ['mdCrudService', 'mdCrudToolsService', '$mdDialog', '$interpolate', '$sce'];
function crudDirective(crudService, tools, $mdDialog, $interpolate, $sce) {
var directive = {
link: link,
restrict: 'EA',
scope: {
options: "=",
onLoad: "=",
rows: "="
},
templateUrl: '/views/crud.html'
};
return directive;
function link($scope, element, attrs) {
var text = crudService.text;
$scope.text = text;
var translate = crudService.options.translate;
$scope.translate = translate;
var options = $scope.options;
options.id = options.id || 'id';
$scope.formType = tools.evalDefined([attrs.formType, options.formType, crudService.options.formType]);
var deleteConfirm = tools.evalDefined([attrs.deleteConfirm, options.deleteConfirm, crudService.options.deleteConfirm]);
var autoRefresh = tools.evalDefined([attrs.autoRefresh, options.autoRefresh, crudService.options.autoRefresh]);
var getParams = tools.evalDefined([attrs.getParams, options.getParams, {}]);
$scope.searchText = attrs.searchText || options.searchText || "";
$scope.searchDelay = attrs.searchDelay || options.searchDelay || (options.serverSide ? 500 : 0);
$scope.fields = options.fields;
$scope.rowSelected = null;
$scope.rowCreate = null;
var ef = $scope.ef = tools.evalFunction;
$scope.stringToHtml = function(str, data) {
return $sce.trustAsHtml($interpolate(str)(data));
}
if(!options.offline)
$scope.isLoading = true;
$scope.getTemplateColumn = function(field, row) {
var template = field.templateColumn || field.columnTemplate || crudService.templateColumns[ef(field.type, row) || 'default'] || crudService.templateColumns['default'];
return template.replace("row[field.name]", "row." + field.name);
}
$scope.getTemplateSelect = function(field) {
if(field.templateSelect)
return field.templateSelect.replace('option', 'getOptionSelect(field, row)');
return "{{translate(getOptionSelect(field, row)." + (field.text || 'text') + ")}}";
}
$scope.getOptionSelect = function(field, row) {
var data = tools.evalFunction(field.data, row);
for(var i in data) {
if(data[i][field.value || 'value'] == row[field.name])
return data[i];
}
return row;
}
$scope.onSearchTextChange = function(text) {
$scope.searchText = text;
if(options.serverSide && serverSide.searchParam) {
$scope.table.page = 1;
options.refresh();
}
}
var serverSide = angular.copy(crudService.options.serverSide || {});
if(options.serverSide && !(typeof options.serverSide === 'boolean')) {
angular.extend(serverSide, options.serverSide);
}
$scope.countFieldsColums = function() {
var count = 0;
for(var i in options.fields) {
var field = options.fields[i];
if(!field.columnHiden && !field.columnHidden) {
count++;
}
}
return count + 2;
}
//Cargar datos de tipos select
var loadDataSelect = function(field) {
if(!field.data) {
crudService.get({ entity: field.entity }).then(function (response) {
field.data = response.data;
});
}
}
for(var i in options.fields) {
var field = options.fields[i];
if(field.entity) {
loadDataSelect(field);
}
}
$scope.table = {
rows: $scope.rows || [],
refresh: function (params) {
$scope.isLoading = true;
angular.extend(getParams, params);
var optionsGet = angular.copy(options.http || {});
optionsGet.entity = options.entity;
optionsGet.params = angular.copy(optionsGet.params || {});
angular.extend(optionsGet.params, getParams);
if(options.serverSide) {
optionsGet.params[serverSide.pageParam] = $scope.table.page;
optionsGet.params[serverSide.offsetParam] = ($scope.table.page - 1) * $scope.table.limit;
optionsGet.params[serverSide.limitParam] = $scope.table.limit;
optionsGet.params[serverSide.searchParam] = ($scope.searchText != "") ? $scope.searchText : undefined;
}
$scope.table.promise = crudService.get(optionsGet).then(function (response) {
$scope.isLoading = false;
if(options.serverSide) {
$scope.table.rows = response.data[serverSide.dataResponse];
$scope.table.total = response.data[serverSide.totalResponse];
}
else
$scope.table.rows = response.data;
});
},
create: function (ev) {
if(ev)
ev.stopPropagation();
$scope.rowSelected = null;
$scope.rowCreate = {};
if ($scope.formType == "window") {
showForm({}, true, ev).then(function (item) {
//$scope.table.refresh();
});
}
},
edit: function (row, ev) {
ev.stopPropagation();
if(row[options.id]) {
if ($scope.formType == "inline") {
$scope.rowCreate = null;
$scope.selectRow(row, true);
}
if ($scope.formType == "window") {
showForm(row, true, ev).then(function (item) {
//$scope.table.refresh();
});
}
}
},
detail: function (row, ev) {
if(options.editOnSelect) {
$scope.table.edit(row, ev);
return;
}
ev.stopPropagation();
if ($scope.formType == "inline") {
$scope.rowCreate = null;
if ($scope.rowSelected == row)
$scope.rowSelected = null;
else if (!options.noDetail)
$scope.selectRow(row, false);
}
if ($scope.formType == "window") {
showForm(row, false, ev).then(function (item) {
//$scope.table.refresh();
});
}
},
delete: function (rowId, ev) {
$scope.rowSelected = null;
ev.stopPropagation();
var t = this;
var index = this.rows.findIndex(function (r) {
return r[options.id] == rowId;
});
var deleteFunct;
if(!options.offline) {
var optionsHttp = angular.copy(options.http || {});
optionsHttp.entity = options.entity;
optionsHttp.id = rowId;
deleteFunct = function () {
crudService.delete(optionsHttp).then(function (data) {
t.rows.splice(index, 1);
}, function (data) {
var error = text.deleteError;
if (data && data.error)
error = data.error;
tools.showAlert(translate(text.deleteErrorTitle), translate(error), translate(text.btnAlertOk));
});
};
}
else {
deleteFunct = function () {
t.rows.splice(index, 1);
}
}
if(deleteConfirm) {
tools.showConfirm(translate(text.deleteConfirmTitle), translate(text.deleteConfirmMessage), translate(text.deleteConfirmOk),
translate(text.btnConfirmCancel), translate(text.btnConfirmCancel)).then(function () {
deleteFunct();
});
}
else {
deleteFunct();
}
},
promise: null,
order: '',
limit: tools.evalDefined([attrs.tableLimit, options.tableLimit, crudService.options.tableLimit]),
limitOptions: tools.evalDefined([attrs.limitOptions, options.limitOptions, crudService.options.limitOptions]),
page: 1,
rowSelection: false,
selected: [],
labels: function () {
return {
page: translate(text.tablePaginationPage),
rowsPerPage: translate(text.tablePaginationRowsPerPage),
of: translate(text.tablePaginationOf)
}
},
onPaginate: function() {
if(options.serverSide)
$scope.table.refresh();
}
}
options.refresh = function (params) {
$scope.table.refresh(params);
}
options.create = function () {
$scope.table.create();
}
options.cancel = function () {
$scope.rowSelected = null;
$scope.rowCreate = null;
$mdDialog.cancel();
}
if (autoRefresh) {
options.refresh();
}
var showForm = function (item, editable, ev) {
$scope.formEditable = editable;
return $mdDialog.show({
controller: ['$scope', '$mdDialog', 'mdCrudService', 'item', 'options', formController],
templateUrl: '/views/crudFormDialog.html',
clickOutsideToClose: true,
fullscreen: true,
scope: $scope,
preserveScope: true,
controllerAs: "vm",
locals: {
item: item,
options: options
},
targetEvent: ev,
parent: element
});
};
$scope.templateUrl = (options.form || {}).templateUrl;
$scope.onOpen = function (item, formType) {
if ((options.form || {}).onOpen)
options.form.onOpen(item, formType);
};
$scope.onEdit = function (item) {
if ((options.form || {}).onEdit)
options.form.onEdit(item);
};
$scope.onDetail = function (item) {
if ((options.form || {}).onDetail)
options.form.onDetail(item);
};
$scope.onCancel = function (error) {
if ((options.form || {}).onCancel)
options.form.onCancel(error);
$scope.rowSelected = null;
$scope.rowCreate = null;
if(error)
tools.showAlert(translate(text.generalErrorTitle), translate(error), translate(text.btnAlertOk));
};
$scope.onSussces = function (item, type) {
if ((options.form || {}).onSussces)
options.form.onSussces(item, type);
if (type == "create" && !options.noCreateAdd)
$scope.table.rows.unshift(item);
$scope.rowSelected = null;
$scope.rowCreate = null;
};
$scope.onSubmit = function (item, type) {
if ((options.form || {}).onSubmit)
options.form.onSubmit(item, type);
};
$scope.selectRow = function (item, editable) {
$scope.rowSelected = item;
$scope.formEditable = editable;
};
var formController = function ($scope, $mdDialog, crudService, item, options) {
$scope.formTitle = translate(item[options.id] ? (($scope.formEditable) ? text.editTitle : text.detailTitle) : text.createTitle);
//$scope.options = options;
$scope.item = item;
$scope.onCancelDialog = function (error) {
$scope.onCancel(error);
$mdDialog.cancel();
};
$scope.onSusscesDialog = function (item, type) {
$scope.onSussces(item, type);
$mdDialog.hide(item);
};
$scope.cancelDialog = function () {
$scope.onCancelDialog();
}
}
if($scope.onLoad)
$scope.onLoad();
}
}
})();
(function () {
'use strict';
angular
.module('mdCrudModule')
.directive('mdCrudForm', crudFormDirective);
crudFormDirective.$inject = ['mdCrudService', 'mdCrudToolsService', '$injector', '$interpolate', '$sce', '$compile', '$document'];
function crudFormDirective(crudService, toolsService, $injector, $interpolate, $sce, $compile, $document) {
//Optional services
var mdpTimePicker;
try {
mdpTimePicker = $injector.get('$mdpTimePicker');
} catch(e) {
}
var directive = {
link: link,
restrict: 'EA',
scope: {
options: "=",
ngModel: "=",
onOpen: "=",
onEdit: "=",
onDetail: "=",
onCancel: "=",
onSussces: "=",
onSubmit: "=",
templateUrl: "<?",
editable: "<?",
modelCopy: "<?"
},
template: '<div ng-include="getContentUrl()"></div>'
};
return directive;
function link($scope, element, attrs) {
var text = crudService.text;
$scope.text = text;
var translate = crudService.options.translate;
$scope.translate = translate;
$scope.stringToHtml = function(str, data) {
return $sce.trustAsHtml($interpolate(str)(data));
}
$scope.templateSelect = function(field) {
var html = field.templateSelect || "<translate>{{option." + (field.text || 'text') + "}}</translate>"
return html;
}
$scope.getModel = function(item, field) {
if(field.model)
return toolsService.evalFunction(field.model, item);
return item[field.name];
}
var options = $scope.options;
$scope.fields = options.fields;
$scope.readonly = $scope.editable == false;
$scope.ef = toolsService.evalFunction;
$scope.isLoading = false;
$scope.item = ($scope.modelCopy)? angular.copy($scope.ngModel || {}) : $scope.ngModel;
var idValue = $scope.item[options.id];
$scope.formTitle = idValue ? (($scope.editable) ? text.editTitle : text.detailTitle) : text.createTitle;
$scope.formType = idValue ? (($scope.editable) ? "edit" : "detail") : "create";
$scope.getContentUrl = function(elem,attrs) {
return $scope.templateUrl || '/views/crudForm.html'
}
$scope.showTimePicker = function(ev, item, fieldName) {
if(mdpTimePicker) {
mdpTimePicker(item[fieldName], {
targetEvent: ev
}).then(function(selectedDate) {
item[fieldName] = selectedDate;
});
}
}
if ($scope.onOpen)
$scope.onOpen($scope.item, $scope.formType);
if (idValue && !options.offline) {
$scope.isLoading = true;
var optionsHttp = angular.copy(options.http || {});
optionsHttp.entity = options.entity;
optionsHttp.id = idValue;
crudService.getById(optionsHttp).then(function (response) {
//$scope.item = response.data;
angular.extend($scope.item, response.data);
if ($scope.formType == 'edit' && $scope.onEdit)
$scope.onEdit($scope.item);
if ($scope.formType == 'detail' && $scope.onDetail)
$scope.onDetail($scope.item);
$scope.isLoading = false;
}, function(data) {
if ($scope.onError)
$scope.onError(data);
$scope.cancel(data);
});
}
$scope.save = function () {
if ($scope.onSubmit)
$scope.onSubmit($scope.item, $scope.formType);
if(!options.offline) {
var promise;
var optionsHttp = angular.copy(options.http || {});
optionsHttp.entity = options.entity;
optionsHttp.data = $scope.item;
if (idValue) {
optionsHttp.id = $scope.ngModel[options.id];
promise = crudService.patch(optionsHttp);
}
else {
promise = crudService.post(optionsHttp);
}
$scope.isLoading = true;
promise.then(function (response) {
angular.extend($scope.ngModel, response.data);
if ($scope.onSussces)
$scope.onSussces(response.data, $scope.formType);
$scope.isLoading = false;
}, function (data) {
if (data.details) {
$scope.errors = data.details;
}
else {
$scope.errors = [data.error];
}
if ($scope.onError)
$scope.onError(data);
$scope.isLoading = false;
});
}
else {
angular.extend($scope.ngModel, $scope.item);
if ($scope.onSussces)
$scope.onSussces($scope.item, $scope.formType);
}
}
$scope.cancel = function (data) {
if ($scope.onCancel)
$scope.onCancel(data);
}
$scope.onMarkerDrag = function (event) {
$scope.item[this.data.lat] = event.latLng.lat();
$scope.item[this.data.lng] = event.latLng.lng();
}
$scope.isFormValid = function(formCrud) {
if(!formCrud.$valid) {
//angular.element('input.ng-invalid').first().focus();
//angular.element($document[0].querySelector('.ng-invalid')).focus();
$document[0].querySelector('form .ng-invalid').focus();
return false;
}
return true;
}
}
}
})();
(function () {
'use strict';
angular
.module('mdCrudModule')
.directive('mdCrudFormBase', crudFormBaseDirective);
crudFormBaseDirective.$inject = ['mdCrudService', 'mdCrudToolsService', '$injector', '$interpolate', '$sce', '$compile', '$document'];
function crudFormBaseDirective(crudService, toolsService, $injector, $interpolate, $sce, $compile, $document) {
//Optional services
var mdpTimePicker;
try {
mdpTimePicker = $injector.get('$mdpTimePicker');
} catch(e) {
}
var directive = {
link: link,
restrict: 'EA',
scope: {
options: "=",
ngModel: "=",
formType: "=",
formCrud: "=",
editable: "<?",
isLoading: "="
},
templateUrl: '/views/crudFormBase.html'
};
return directive;
function link($scope, element, attrs) {
var text = crudService.text;
$scope.text = text;
$scope.formType = $scope.formType || 'detail';
var translate = crudService.options.translate;
$scope.translate = translate;
$scope.stringToHtml = function(str, data) {
return $sce.trustAsHtml($interpolate(str)(data));
}
$scope.templateSelect = function(field) {
var html = field.templateSelect || "<translate>{{option." + (field.text || 'text') + "}}</translate>"
return html;
}
var options = $scope.options;
$scope.fields = options.fields;
$scope.readonly = $scope.editable == false;
//Cargar datos de tipos select
var loadDataSelect = function(field) {
if(!field.data) {
crudService.get({ entity: field.entity }).then(function (response) {
field.data = response.data;
});
}
}
for(var i in options.fields) {
var field = options.fields[i];
if(field.entity) {
loadDataSelect(field);
}
}
$scope.ef = toolsService.evalFunction;
var idValue = $scope.ngModel[options.id];
$scope.item = $scope.ngModel;
$scope.showTimePicker = function(ev, item, fieldName) {
if(mdpTimePicker) {
mdpTimePicker(item[fieldName], {
targetEvent: ev
}).then(function(selectedDate) {
item[fieldName] = selectedDate;
});
}
}
$scope.onMarkerDrag = function (event) {
$scope.item[this.data.lat] = event.latLng.lat();
$scope.item[this.data.lng] = event.latLng.lng();
}
}
}
})();
(function () {
'use strict';
angular.module('mdCrudModule')
.directive('mdCrudInputNumber', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(value) {
return (typeof value != 'number') ? parseFloat(value) : value;
});
ngModel.$formatters.push(function(value) {
return (typeof value != 'number') ? parseFloat(value) : value;
});
}
};
})
.directive('mdCrudInputBoolean', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(value) {
return (typeof value != 'boolean') ? value == 'true' : value;
});
ngModel.$formatters.push(function(value) {
return (typeof value != 'boolean') ? value == 'true' : value;
});
}
};
})
.directive('mdCrudInputDate', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(value) {
return (value instanceof Date) ? value : new Date(value);
});
ngModel.$formatters.push(function(value) {
return (value instanceof Date) ? value : new Date(value);
});
}
};
})
.directive("mdCrudInputValidator", function () {
return {
require: "ngModel",
scope: {
validator: "=mdCrudInputValidator",
item: "=item"
},
link: function (scope, element, attributes, ngModel) {
ngModel.$validators.mdCrudInputValidator = function (modelValue) {
if(angular.isFunction(scope.validator))
return !angular.isDefined(scope.validator(modelValue, scope.item))
return !angular.isDefined(scope.validator);
};
}
};
});
})();
(function () {
'use strict';
angular
.module('mdCrudModule')
.directive('mdCrudTemplate', crudTemplateDirective);
crudTemplateDirective.$inject = ['$compile'];
function crudTemplateDirective($compile) {
// directive factory creates a link function
return function(scope, element, attrs) {
scope.$watch(
function(scope) {
// watch the 'compile' expression for changes
return scope.$eval(attrs.mdCrudTemplate);
},
function(value) {
// when the 'compile' expression changes
// assign it into the current DOM
element.html(value);
// compile the new DOM and link it to the current
// scope.
// NOTE: we only compile .childNodes so that
// we don't get into infinite loop compiling ourselves
$compile(element.contents())(scope);
}
);
};
}
})();
(function () {
'use strict';
angular.module('mdCrudModule').service('mdCrudService', ['$q', '$interpolate', '$http', 'mdCrudToolsService', fnService]);
function fnService($q, $interpolate, $http, tools) {
var defaultOptions = {
rootApi: '/api',
methodGet: 'GET',
methodPost: 'POST',
methodPatch: 'PATCH',
methodDelete: 'DELETE',
urlGet: '{{rootApi}}/{{entity}}',
urlGetById: '{{rootApi}}/{{entity}}/{{id}}',
urlPost: '{{rootApi}}/{{entity}}',
urlPatch: '{{rootApi}}/{{entity}}/{{id}}',
urlDelete: '{{rootApi}}/{{entity}}/{{id}}',
functionHttp: function(options, method) {
if(options.functionHttp)
return options.functionHttp(options);
return $q(function (resolve, reject) {
$http({
url: $interpolate(options.url)(options),
method: options.method,
params: options.params,
data: options.data
}).then(function (response) {
(options.functionData || defaultOptions.functionData)(response, resolve, reject, method);
}, function (response) {
reject(response.data);
});
});
},
functionData: function(response, resolve, reject, method) {
resolve(response);
},
formType: 'inline',
deleteConfirm: true,
tableLimit: 10,
limitOptions: [10, 20, 30],
translate: function(text) {
return text;
},
autoRefresh: true,
serverSide: {
pageParam: 'page',
offsetParam: 'offset',
limitParam: 'limit',
searchParam: 'search',
dataResponse: 'data',
totalResponse: 'total'
}
};
var defaultText = {
editTitle: 'Edit',
detailTitle: 'Detail',
createTitle: 'Create',
deleteError: 'Error while trying to delete row',
deleteErrorTitle: 'Error deleting',
deleteConfirmTitle: 'Delete',
deleteConfirmMessage: 'Are you sure you want to delete the row?',
tablePaginationPage: 'Page',
tablePaginationRowsPerPage: 'Rows per page:',
tablePaginationOf: 'of',
createOption: 'Create',
btnConfirmOk: 'Yes',
btnConfirmCancel: 'No',
btnAlertOk: 'Ok',
generalErrorTitle: 'Error',
messageRequired: 'Required',
messageMinlength: 'Min length',
messageMaxlength: 'Max length',
messagePattern: 'Invalid input format.',