|
|
@@ -0,0 +1,151 @@
|
|
|
+const _ = require('lodash')
|
|
|
+const app = require('../../app')
|
|
|
+/**
|
|
|
+ * @param {CrudPagesOptions} opts
|
|
|
+ */
|
|
|
+const details = (opts) => {
|
|
|
+
|
|
|
+ const autocompleteInput = column => {
|
|
|
+ if (!column.apiPrefix) throw new Error('apiPrefix is required for autocomplete fields')
|
|
|
+
|
|
|
+ return html`
|
|
|
+ <md-autocomplete flex
|
|
|
+ md-selected-item="ctrl.autocomplete.${raw(column.camelName)}.selectedItem"
|
|
|
+ md-search-text="ctrl.autocomplete.${raw(column.camelName)}.searchText"
|
|
|
+ md-items="item in ctrl.autocomplete.${raw(column.camelName)}.getItems(ctrl.autocomplete.${raw(column.camelName)}.searchText)"
|
|
|
+ md-item-text="item.name || item.key || item.id"
|
|
|
+ md-require-match="true"
|
|
|
+ md-selected-item-change="ctrl.autocomplete.${raw(column.camelName)}.onChange()"
|
|
|
+ md-min-length="0"s
|
|
|
+ placeholder="${column.titleName}"
|
|
|
+ >
|
|
|
+ <md-item-template>
|
|
|
+ <span md-highlight-text="ctrl.searchText.${raw(column.camelName)}" md-highlight-flags="^i">{{item.name || item.key || item.id}}</span>
|
|
|
+ </md-item-template>
|
|
|
+ </md-autocomplete>
|
|
|
+ `
|
|
|
+ }
|
|
|
+
|
|
|
+ const standardInput = column => html`
|
|
|
+ <md-input-container flex>
|
|
|
+ <label>${column.titleName}</label>
|
|
|
+ <input type="${column.type || 'text'}" ng-model="model.${raw(column.camelName)}" />
|
|
|
+ </md-input-container>
|
|
|
+ `
|
|
|
+
|
|
|
+ const defaultField = column =>
|
|
|
+ column.type === 'autocomplete'
|
|
|
+ ? autocompleteInput(column)
|
|
|
+ : standardInput(column)
|
|
|
+
|
|
|
+ const layout = () => {
|
|
|
+ if (opts.layout) {
|
|
|
+ const cols = _.fromPairs(opts.columns.map(col => [col.camelName, col]))
|
|
|
+
|
|
|
+ return opts.layout.map(section => html`
|
|
|
+ ${section.section ? html`<md-subheader>${section.section}</md-subheader>`:''}
|
|
|
+ ${raw(section.rows ? section.rows.map(
|
|
|
+ row => html`
|
|
|
+ <div layout-gt-sm="row" layout-padding>
|
|
|
+ ${raw(row
|
|
|
+ .map(field => cols[field])
|
|
|
+ .map(c => c.field || defaultField(c))
|
|
|
+ .join('\n')
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ `).join('\n')
|
|
|
+ : '')}
|
|
|
+ `).join('\n')
|
|
|
+ } else {
|
|
|
+ return html`
|
|
|
+ <div layout-gt-sm="row" layout-padding>
|
|
|
+ ${opts.columns.map(c => c.field || defaultField(c))}
|
|
|
+ </div>
|
|
|
+ `
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const template = html`
|
|
|
+ <app-user-area>
|
|
|
+ <h1>{{ctrl.isNew ? 'New ${opts.titleName}' : '${opts.titleName} Details'}}</h1>
|
|
|
+ <form name="form" ng-submit="ctrl.submit()">
|
|
|
+ ${raw(layout())}
|
|
|
+ <div>
|
|
|
+ <md-button type="submit" class="md-raised md-primary">Submit</md-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </form>
|
|
|
+ </app-user-area>
|
|
|
+ `
|
|
|
+ app.component(`app${opts.pascalName}DetailsPage`, {
|
|
|
+
|
|
|
+ template,
|
|
|
+ controllerAs: 'ctrl',
|
|
|
+ controller: function(api, $scope, $routeParams, $mdToast, $location, $q) {
|
|
|
+ this.template = template // For inspection purposes
|
|
|
+ this.isNew = $routeParams[opts.routeParam] === 'new'
|
|
|
+ const crud = api.crud(opts.apiPrefix)
|
|
|
+ let original
|
|
|
+ if (this.isNew) {
|
|
|
+ original = {}
|
|
|
+ $scope.model = Object.create(original)
|
|
|
+ this.loadingPromise = $q.resolve($scope.model)
|
|
|
+ } else {
|
|
|
+ this.loadingPromise = crud.read($routeParams[opts.routeParam]).then(model => {
|
|
|
+ original = model
|
|
|
+ $scope.model = Object.create(original)
|
|
|
+ return $scope.model
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ this.submit = async () => {
|
|
|
+ try {
|
|
|
+ if (this.isNew) {
|
|
|
+ await crud.create($scope.model)
|
|
|
+ } else {
|
|
|
+ const obj = {}
|
|
|
+ for (var key in $scope.model) {
|
|
|
+ if ($scope.model.hasOwnProperty(key)) {
|
|
|
+ obj[key] = $scope.model[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await crud.update(original.id, obj)
|
|
|
+ }
|
|
|
+ $mdToast.showSimple(`${opts.titleName} saved.`)
|
|
|
+ $location.url(opts.appPrefix)
|
|
|
+ } catch (err) {
|
|
|
+ console.error(err)
|
|
|
+ $mdToast.showSimple(`Could not save ${opts.titleName}: ${err.message || err}`)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Autocomplete fields */
|
|
|
+ this.searchText = {}
|
|
|
+ this.autocomplete = {}
|
|
|
+
|
|
|
+ opts.columns.filter(c => c.type === 'autocomplete').forEach(c => {
|
|
|
+ const crud = api.crud(c.apiPrefix)
|
|
|
+ const ac = this.autocomplete[c.camelName] = {
|
|
|
+ onChange() {
|
|
|
+ $scope.model[c.camelName] = ac.selectedItem
|
|
|
+ ? ac.selectedItem.id
|
|
|
+ : null
|
|
|
+ },
|
|
|
+ getItems(searchText) {
|
|
|
+ return crud.autocomplete(searchText)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.loadingPromise.then(model => {
|
|
|
+ if (model[c.camelName]) {
|
|
|
+ crud.read(model[c.camelName]).then(record => {
|
|
|
+ ac.selectedItem = record
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = details
|