a small relational database with user-editable schema for manual data entry
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
yopa/yopa-web/resources/src/components/EditRelationForm.vue

138 lines
3.8 KiB

<script>
import {castId, isEmpty, keyBy, objCopy} from "../utils";
import forEach from "lodash-es/forEach";
import isEqual from "lodash-es/isEqual";
export default {
props: ['model_id', 'schema', 'objects', 'initialInstances'],
name: "EditRelationForm",
data() {
const model = this.schema.rel_models.find((m) => m.id === this.model_id);
if(!model) throw Error("Relation model not exist");
let properties = this.schema.prop_models.filter((m) => m.object === model.id);
properties.sort((a, b) => a.name.localeCompare(b.name));
if (isEmpty(properties)) {
properties = [];
} else {
properties = keyBy(properties, 'id');
}
let related_model = this.schema.obj_models.find((m) => m.id === model.related);
if(!related_model) throw Error("Related model not exist");
let choices = {};
this.objects.forEach((obj) => {
if (obj.model === model.related) {
choices[obj.id] = obj.name;
}
});
return {
model,
related_model,
properties,
object_names: choices,
instances: objCopy(this.initialInstances),
}
},
methods: {
collectData() {
console.log('relation->collect', this.instances);
let relations = [];
forEach(objCopy(this.instances), (instance) => {
console.log('a instance', instance);
if (isEmpty(instance.related)) {
if (!this.model.optional) {
throw new Error(`Relation "${this.model.name}" is required`)
}
console.log("empty related", instance.related);
return; // continue
}
let values = [];
forEach(instance.values, (vv, prop_model_id) => {
for (let v of vv) {
if (isEqual(v.value, {"String": ""}) && this.properties[prop_model_id].optional) {
continue;
}
v.model = castId(prop_model_id);
values.push(v);
}
})
instance.related = castId(instance.related);
instance.model = this.model.id;
instance.values = values;
relations.push(instance);
})
console.log('collected', relations);
return relations;
},
addInstance() {
console.log('Add instance');
let values = {};
forEach(this.properties, (p) => {
if (p.optional) {
values[p.id] = [];
} else {
values[p.id] = [{id: null, value: objCopy(p.default)}];
}
});
this.instances.push({
related: '',
values
})
},
removeInstance(ri) {
this.instances.splice(ri, 1)
}
}
}
</script>
<style scoped>
.new-relation {
border: 1px dashed gray;
margin: 10px 0;
padding: 10px;
}
</style>
<template>
<div class="form-horizontal panel mt-1 mb-1 p-2" v-for="(instance, ri) in instances" :key="ri">
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ model.name }} -&gt; {{ related_model.name }}</label>
</div>
<div class="col-7">
<select class="form-select input-inline" v-model="instance.related">
<option v-for="(name, id) in object_names" :value="id">{{name}}</option>
</select>
</div>
<div class="col-2 text-right">
<a class="btn btn-delete" v-if="model.multiple || model.optional && instances.length > 0"
@click="removeInstance(ri)">
<i class="icon-cross icon"></i>
Delete
</a>
</div>
</div>
<edit-property v-for="(property, id) in properties"
:model="property"
:values="instance.values[id]" :key="id"></edit-property>
</div>
<div class="mt-2 mb-2">
<a class="btn" v-if="model.multiple || model.optional && instances.length==0"
@click="addInstance">
<i class="icon icon-plus"></i>
Add {{ model.name }} -&gt; {{ related_model.name }}
</a>
</div>
</template>