Skip to content

Commit

Permalink
refactor of value handling, improvements to work with flexible-conten…
Browse files Browse the repository at this point in the history
…t and show details as actual list
  • Loading branch information
bashgeek committed Jul 24, 2023
1 parent da231f2 commit 4e15ba4
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 141 deletions.
2 changes: 1 addition & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

18 changes: 12 additions & 6 deletions resources/js/components/DetailField.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
<template>
<PanelItem :index="index" :field="field" />
<PanelItem :field="field" >
<template #value>
<ul>
<li class="mb-1" style="list-style: square; margin-left: 1rem;" v-for="value of fieldValue">
{{ value }}
</li>
</ul>
</template>
</PanelItem>
</template>

<script>
import HasFieldValue from "../mixins/HasFieldValue";
export default {
mixins: [HasFieldValue],
props: ['resource', 'resourceName', 'resourceId', 'field'],
created() {
if (Array.isArray(this.field.value)) {
this.field.value = this.field.value.join(", ");
}
},
}
</script>
272 changes: 143 additions & 129 deletions resources/js/components/FormField.vue
Original file line number Diff line number Diff line change
@@ -1,162 +1,176 @@
<template>
<DefaultField :field="currentField" :full-width-content="currentField.fullWidth" :show-help-text="showHelpText">
<template #field>
<div class="nova-items-field-input-wrapper flex mb-2" v-if="currentField.listFirst === false && ! maxReached">
<DefaultField :field="currentField" :full-width-content="currentField.fullWidth" :show-help-text="showHelpText">
<template #field>
<div class="nova-items-field-input-wrapper flex mb-2" v-if="currentField.listFirst === false && ! maxReached">
<input
v-model="newItem"
:type="currentField.inputType"
:placeholder="currentField.placeholder"
autocomplete="new-password"
@keydown.enter.prevent="addItem"
class="flex-1 form-control form-input form-input-bordered"
/>
<button
type="button"
@click="addItem"
v-html="currentField.createButtonValue"
v-if="currentField.hideCreateButton === false"
class="ml-3 cursor-pointer shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900 cursor-pointer rounded text-sm font-bold focus:outline-none focus:ring inline-flex items-center justify-center h-9 px-3 shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900"
/>
</div>
<ul ref="novaitemslist" :style="maxHeight" v-if="items.length" class="nova-items-field-input-items list-reset">
<draggable :disabled="currentField.draggable === false" v-model="items"
:item-key="currentField.attribute + '.' + index" handle=".sortable-handle">
<template #item="{ element, index }">
<li class="py-1">
<div class="nova-items-field-input-wrapper-item flex py-1 gap-2">
<button type="button" v-if="currentField.draggable === true" class="cursor-move sortable-handle px-4">
<Icon type="menu"/>
</button>
<input
v-model="newItem"
:value="element"
:type="currentField.inputType"
:placeholder="currentField.placeholder"
v-on:keyup="updateItem(index, $event)"
:name="currentField.name + '['+ index +']'"
autocomplete="new-password"
@keydown.enter.prevent="addItem"
:class="{'border-danger': hasErrors(index)}"
class="flex-1 form-control form-input form-input-bordered"
/>
>
<button
v-if="currentField.deleteButtonValue"
type="button"
@click="addItem"
v-html="currentField.createButtonValue"
v-if="currentField.hideCreateButton === false"
class="ml-3 cursor-pointer shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900 cursor-pointer rounded text-sm font-bold focus:outline-none focus:ring inline-flex items-center justify-center h-9 px-3 shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900"
/>
</div>
<ul ref="novaitemslist" :style="maxHeight" v-if="items.length" class="nova-items-field-input-items list-reset">
<draggable :disabled="currentField.draggable === false" v-model="items" :item-key="currentField.attribute + '.' + index" handle=".sortable-handle">
<template #item="{ element, index }">
<li class="py-1">
<div class="nova-items-field-input-wrapper-item flex py-1 gap-2">
<button type="button" v-if="currentField.draggable === true" class="cursor-move sortable-handle px-4"><Icon type="menu" /></button>
<input
:value="element"
:type="currentField.inputType"
v-on:keyup="updateItem(index, $event)"
:name="currentField.name + '['+ index +']'"
autocomplete="new-password"
:class="{'border-danger': hasErrors(currentField.attribute + '.' + index)}"
class="flex-1 form-control form-input form-input-bordered"
>
<button
v-if="currentField.deleteButtonValue"
type="button"
@click="removeItem(index)"
class="px-4 text-xl font-bold focus:outline-none focus:ring"
v-html="currentField.deleteButtonValue"
/>
<button v-else type="button" @click="removeItem(index)" class="px-1 ml-1 toolbar-button">
<Icon type="x"/>
</button>
</div>
<HelpText class="mt-2 help-text-error" v-if="hasErrors(currentField.attribute + '.' + index)">
{{ arrayErrors[currentField.attribute + '.' + index][0] }}
</HelpText>
</li>
</template>
</draggable>
</ul>
<div class="nova-items-field-input-wrapper flex mt-2" v-if="currentField.listFirst && ! maxReached">
<input
v-model="newItem"
:type="currentField.inputType"
:placeholder="currentField.placeholder"
class="flex-1 form-control form-input form-input-bordered"
@keypress.enter.prevent="addItem"
/>
<button
type="button"
@click="addItem"
v-html="currentField.createButtonValue"
v-if="currentField.hideCreateButton === false"
class="ml-3 cursor-pointer shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900 cursor-pointer rounded text-sm font-bold focus:outline-none focus:ring inline-flex items-center justify-center h-9 px-3 shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900"
@click="removeItem(index)"
class="px-4 text-xl font-bold focus:outline-none focus:ring"
v-html="currentField.deleteButtonValue"
/>
</div>
</template>
</DefaultField>
<button v-else type="button" @click="removeItem(index)" class="px-1 ml-1 toolbar-button">
<Icon type="x"/>
</button>
</div>
<HelpText class="mt-2 help-text-error" v-if="hasErrors(index)">
{{ arrayErrors[index][0] }}
</HelpText>
</li>
</template>
</draggable>
</ul>
<div class="nova-items-field-input-wrapper flex mt-2" v-if="currentField.listFirst && ! maxReached">
<input
v-model="newItem"
:type="currentField.inputType"
:placeholder="currentField.placeholder"
class="flex-1 form-control form-input form-input-bordered"
@keypress.enter.prevent="addItem"
/>
<button
type="button"
@click="addItem"
v-html="currentField.createButtonValue"
v-if="currentField.hideCreateButton === false"
class="ml-3 cursor-pointer shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900 cursor-pointer rounded text-sm font-bold focus:outline-none focus:ring inline-flex items-center justify-center h-9 px-3 shadow relative bg-primary-500 hover:bg-primary-400 active:bg-primary-600 text-white dark:text-gray-900"
/>
</div>
<HelpText class="mt-2 help-text-error" v-if="hasErrors()">
{{ arrayErrors[''][0] }}
</HelpText>
</template>
</DefaultField>
</template>

<style scoped>
</style>

<script>
import draggable from 'vuedraggable'
import { DependentFormField, HandlesValidationErrors } from 'laravel-nova'
import {DependentFormField, HandlesValidationErrors} from 'laravel-nova'
import HasFieldValue from "../mixins/HasFieldValue";
export default {
mixins: [DependentFormField, HandlesValidationErrors],
mixins: [DependentFormField, HandlesValidationErrors, HasFieldValue],
props: ['resourceName', 'resourceId', 'field'],
props: ['resourceName', 'resourceId', 'field'],
components: {draggable},
components: { draggable },
data()
{
return {
value: '',
items: [],
newItem: '',
arrayErrors: []
};
},
data() {
return {
value: '',
items: [],
newItem: '',
arrayErrors: []
};
methods: {
setInitialValue()
{
this.value = JSON.stringify(this.fieldValue);
this.items = this.fieldValue;
},
methods: {
setInitialValue() {
this.value = this.field.value || [];
this.items = this.field.value || [];
},
fill(formData)
{
formData.append(this.field.attribute, this.value || [])
},
fill(formData) {
formData.append(this.field.attribute, this.value || [])
},
addItem()
{
const item = this.newItem.trim();
if (item && !this.maxReached) {
this.items.push(item)
this.newItem = ''
addItem() {
const item = this.newItem.trim();
if (item && ! this.maxReached) {
this.items.push(item)
this.newItem = ''
this.$nextTick(() => {
if (this.field.maxHeight) {
this.$refs.novaitemslist.scrollTop = this.$refs.novaitemslist.scrollHeight;
}
})
}
},
this.$nextTick(() => {
if(this.field.maxHeight){
this.$refs.novaitemslist.scrollTop = this.$refs.novaitemslist.scrollHeight;
}
})
}
},
updateItem(index, event)
{
this.items[index] = event.target.value
},
updateItem(index, event) {
this.items[index] = event.target.value
},
removeItem(index)
{
this.items.splice(index, 1)
},
removeItem (index) {
this.items.splice(index, 1)
},
hasErrors(key)
{
return this.arrayErrors.hasOwnProperty(key ?? '');
}
},
computed: {
maxHeight()
{
if (this.field.maxHeight === false) {
return '';
}
hasErrors(key) {
return this.arrayErrors.hasOwnProperty(key);
}
return `max-height: ${this.field.maxHeight}px; overflow: auto;`;
},
computed: {
maxHeight() {
if (this.field.maxHeight === false) {
return '';
}
return `max-height: ${this.field.maxHeight}px; overflow: auto;`;
},
maxReached() {
return this.field.max !== false && this.items.length + 1 > this.field.max;
}
maxReached()
{
return this.field.max !== false && this.items.length + 1 > this.field.max;
}
},
watch: {
'items': {
handler: function (items) {
this.value = JSON.stringify(items);
},
deep: true
},
watch: {
'items': {
handler: function (items) {
this.value = JSON.stringify(items);
},
deep: true
},
'errors': {
handler: function (errors) {
if(errors.errors.hasOwnProperty(this.field.attribute)) {
this.arrayErrors = JSON.parse(errors.errors[this.field.attribute][0])
}
},
deep: true
}
'errors': {
handler: function (errors) {
this.arrayErrors = errors.errors.hasOwnProperty(this.field.validationKey) ? JSON.parse(errors.errors[this.field.validationKey][0]) : {};
},
deep: true
}
}
}
</script>
7 changes: 5 additions & 2 deletions resources/js/components/IndexField.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<template>
<div>
<span v-if="field.value">{{ field.value.length }}</span>
<span v-else>0</span>
<span v-if="fieldValue">{{ fieldValue.length }}</span>
<span v-else>0</span>
</div>
</template>

<script>
import HasFieldValue from "../mixins/HasFieldValue";
export default {
mixins: [HasFieldValue],
props: ['resourceName', 'field'],
}
</script>
18 changes: 18 additions & 0 deletions resources/js/mixins/HasFieldValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default {
computed: {
fieldValue() {
let fieldValue = this.field.value;
while (typeof fieldValue === 'string') {
try {
fieldValue = JSON.parse(fieldValue);
} catch {
fieldValue = null;
}
}
if (! fieldValue) {
fieldValue = [];
}
return fieldValue;
}
}
};
Loading

0 comments on commit 4e15ba4

Please sign in to comment.