Get data from component - laravel

I have component: ckeditor. I am trying to get data from it and save it to the database. Every time I save the data using the store function I get an empty record in the database:
public function store(Request $request)
{
$business = Business::create($request->all());
if($request->has('photos')) {
foreach ($request->photos as $photo) {
$filename = $photo->store('public/photos');
Photo::create([
'business_id' => $business->id,
'filename' => $filename
]);
}
}
return redirect()->action('BusinessController#clist');
}
Here is my code of component:
<template>
<vue-ckeditor type="classic" v-model="editorData" :editors="editors" id="description" name="description"></vue-ckeditor>
</template>
<script>
import VueCkeditor from 'vue-ckeditor5'
export default {
components: {
'vue-ckeditor': VueCkeditor.component
},
data(){
return {
editors: {
classic: ClassicEditor
},
editorData: '<p>Content of the editor.</p>',
}
},
}
</script>
The code in create.blade.php:
<vue-ck name="description" id="description"></vue-ck>
I will just add that the store function works fine for textarea input. Thanks for help guys.
Model:
class Business extends Model
{
protected $fillable = [
'title',
'description',
'order',
'visible',
'lang'
];
public function photos()
{
return $this->hasMany(Photo::class);
}
}
I have additional columns there, title, lang etc. But the important column is a description. I do not know why I do not want to download data from this component.

Related

I can't set Session Items in laravel inertia

I am using Laravel with inertia, but I am not able to set session items in laravel.
here is my laravel code:
use Illuminate\Support\Facades\Session;
public function index()
{
Session::put('message', 'showCatergories');
$categories = Category::all();
return Inertia::render('Admin/Categories', ['categories' => $categories]);
}
nothing appears in application -> storage-> sessoin storage
my route:
Route::middleware(['auth', 'web'])->group(function () {
Route::resource('/categories', CategoriesController::class);
});
How to tackle this issue?
Working with session items and flash messages in Inertia.js is done by appending it to the shared method in the HandleInertiaRequests middleware.
class HandleInertiaRequests extends Middleware
{
public function share(Request $request)
{
return array_merge(parent::share($request), [
'flash' => [
'message' => fn () => $request->session()->get('message')
],
]);
}
}
Here we get the message item on the session and append it as a flash prop on the request.
Then we can use it in our frontend of choice. Here is a React.js example:
import { usePage } from '#inertiajs/inertia-react'
export default function Layout({ children }) {
const { flash } = usePage().props
return (
<main>
<header></header>
<content>
{flash.message && (
<div class="alert">{flash.message}</div>
)}
{children}
</content>
<footer></footer>
</main>
)
}
You can read more about flash messages in the documentation.

Laravel Inertia prop not passing values

When calling an edit function the prop mealService is passing null values and will not populate form fields with values. It looks like the controller isn't loading the model to query the single record. The Create and Store functions work fine.
First time posting. And very new to coding. Please let me know if more info is needed for the question.
edit.vue
export default {
components: {
Head,
Link,
LoadingButton,
SelectInput,
TrashedMessage,
},
layout: Layout,
props: {
mealService: Object,
sites: Array,
},
remember: 'form',
data() {
return {
form: this.$inertia.form({
site_id: this.mealService.site_id,
meal_type: this.mealService.meal_type,
adults: this.mealService.adults,
tally: this.mealService.tally,
}),
}
},
MealServiceController
public function edit(MealService $meal_service)
{
return Inertia::render('MealServices/Edit', [
'mealService' => [
'id' => $meal_service->id,
'site_id' => $meal_service->site_id,
'meal_type' => $meal_service->meal_type,
'adults' => $meal_service->adults,
'tally' => $meal_service->tally,
],
'sites' => Auth::user()->sfa
->sites()
->orderBy('name')
->get()
->map
->only('id', 'name'),
]);
}
MealService Model
class MealService extends Model
{
use HasFactory;
use SoftDeletes;
public function resolveRouteBinding($value, $field = null)
{
return $this->where($field ?? 'id', $value)->withTrashed()->firstOrFail();
}
public function site()
{
return $this->belongsTo(Site::class);
}
public function scopeFilter($query, array $filters)
{
$query->when($filters['search'] ?? null, function ($query, $search) {
$query->WhereHas('site', function ($query) use ($search) {
$query->where('name', 'like', '%'.$search.'%');
});
})->when($filters['trashed'] ?? null, function ($query, $trashed) {
if ($trashed === 'with') {
$query->withTrashed();
} elseif ($trashed === 'only') {
$query->onlyTrashed();
}
});
}
}
Route
Route::get('mealServices/{mealService}/edit', [MealServicesController::class, 'edit'])
->name('mealServices.edit')
->middleware('auth');
In your edit function you are using meal_service while in your route you use mealService
Try naming the one in the edit function mealService too

.isDirty is true after submitting and reloading InertiaJS page

I have a simple form with a "Save" button that shows up if the user has updated any of the checkboxes.
The form sends a POST request to a store route in a controller that creates new records in the databases and redirects them to the index route.
When the page reloads, it doesn't seem to reset the Inertia form isDirty state from true to false even when I manually refresh the page.
public function index(Request $request)
{
$restaurantCategories = auth()->user()
->currentTeam->categories()
->with('category')->get();
$allCategories = Category::all();
$filters = $request->only('search');
return Inertia::render('Restaurant/Categories/Index',
[
'restaurantCategories' => $restaurantCategories,
'allCategories' => $allCategories, 'filters' => $filters
]);
}
public function store(Request $request)
{
foreach (auth()->user()->currentTeam->categories as $category) {
$category->delete();
}
foreach ($request->checkedCategories as $category) {
auth()->user()->currentTeam->categories()
->create(['category_id' => $category['id']]);
}
return redirect()->route('restaurant.categories.index');
}
Vue
export default{
props: {
filters: Object,
restaurantCategories: Object,
allCategories: Object,
},
data: {
updateForm: this.$inertia.form({
checkedCategories: this.restaurantCategories.map(
(resCat) => resCat.category
),
}),
}
}
methods:{
//THIS METHOD IS CALLED WHEN THE SAVE BUTTON IS CLICKED
sendUpdate() {
this.$inertia.post(
this.route("restaurant.categories.store"),
this.updateForm
);
},
},
}
I've tried setting a key to the save button and updating the key on sendUpdate method, and calling Inertia.reload()

Why this validation gives me always required?

probably I'm doing something wrong, I have been coding by instinct haha. Laravel validation seems super easy to implement but for some reason between my vuejs component to my php function I'm always getting "required".
I'm new with both Laravel and Vuejs, it seems to me that my php function is fine (for what I can see on the web) but probably I'm missing something on the comunication between laravel and vue. Can you tell me whats wrong?
public function createTag(Request $request)
{
try {
$data = request()->validate([
'title' => 'required'
]);
$tag = new Tag;
$tag->title = $request->title;
if($tag->save())
{
$tag->usercontracts()->attach($request->usercontractId);
}
return response()->success(__('success.showing', ['resource' => 'des Vertrags', 'resourceE' => 'tag']), $tag->id, 200);
} catch (Exception $e) {
return response()->error(__('error.showing', ['resource' => 'des Vertrags', 'resourceE' => 'tag']), 400, $e);
}
}
<template>
<div id="relative">
<button #click.prevent="show = 1" v-if="show == 0">+tag</button>
<input type="text" v-model="title" name="title" v-if="show == 1">
<button #click="createTag" v-if="show == 1">add</button>
</div>
</template>
<script>
import TagService from "#/services/TagService";
export default {
name: "add-tag-component",
props: ['usercontractId'],
data(){
return {
title:null,
show:0
};
},
methods:
{
async createTag()
{
const {body: {data}} = await TagService.createTag(this.title, this.usercontractId);
this.$emit('addedTag', this.title, data);
this.title = '';
this.show = 0;
}
}
};
</script>
And this is TagService
export default {
createTag(title, usercontractId, tagId) {
return Vue.http.post(`contract/createTag/${title}/${usercontractId}`, tagId);
}
}
I'm also getting this error. May be here is the answer?
Vue warn]: Error in v-on handler (Promise/async): "[object Object]"
found in
---> at resources/assets/js/components/contract/listing/AddTagComponent.vue
at resources/assets/js/components/contract/listing/ContractListingItemComponent.vue
at resources/assets/js/components/contract/listing/ContractListingComponent.vue
In your TagService
You need to pass the ${title} as payload not as uri.
export default {
createTag(title, usercontractId, tagId) {
return Vue.http.post(`contract/createTag/${title}/${usercontractId}`, tagId);
}
}
to
export default {
createTag(title, usercontractId, tagId) {
return Vue.http.post(`contract/createTag`, {
tagId: tagId,
title: title,
usercontractId: usercontractId
});
}
}
Laravel validates the payload you pass.

Laravel nova, custom resource tool not appears in edit mode

I have a custom resource-tool working fine in the view panel of a resource, but it dont appears when i go o the edit mode. Is there something i should add to the component or to the Nova configuration to enable the component in the edit mode?
Code in User.php
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('First name', 'firstName')
->sortable()
->rules('required', 'max:255'),
Text::make('Last name', 'lastName')
->sortable()
->rules('required', 'max:255'),
Text::make('Email')
->sortable()
->rules('required', 'email', 'max:254')
->creationRules('unique:users,email')
->updateRules('unique:users,email,{{resourceId}}'),
Password::make('Password')
->onlyOnForms()
->creationRules('required', 'string', 'min:6')
->updateRules('nullable', 'string', 'min:6'),
YesNovaUserPermissions::make(),
];
}
User view:
User edit:
Nova does not seem to allow you to obtain this functionality with a custom resource but you can with a custom field. You basically create a "dummy" field which does not really exist on the model and use a mutator on the model to overwrite the default model saving functionality.
Following the documentation above, you can build a Vue component which will appear within the resource edit form itself, similarly to how I have done with the tags picker pictured below.
Code for that:
<template>
<default-field :field="field" :errors="errors" :show-help-text="showHelpText">
<label for="tag" class="inline-block text-80 pt-2 leading-tight">Tag</label>
<template slot="field">
<div id="multitag-flex-holder">
<div id="multitag-search-holder" class="w-1/2">
<div class="search-holder">
<label>Search Categories</label>
<input type="text" v-model="searchString" #focus="isSearching = true" #blur="isSearching = false" style="border:2px solid #000"/>
<div class="found-tags" v-if="isSearching">
<div v-for="(tag, i) in foundTags" #mousedown="addToSelected(tag)" :key="i">{{tag.name}}</div>
</div>
</div>
</div>
<div class="select-tags-holder w-1/2">
<div class="selected-tags">
<div v-for="(tag, i) in selectedTags" :key="'A'+i" #click="removeTag(tag)">{{tag.name}} X</div>
</div>
</div>
</div>
</template>
</default-field>
</template>
<script>
import { FormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [FormField, HandlesValidationErrors],
props: ['resourceName', 'resourceId', 'field'],
data: function () {
return {
selectedTags:[],
isSearching:false,
searchString:''
}
},
mounted(){
console.log(this.field)
this.field.value.forEach((tag)=>{
this.addToSelected(tag)
})
formData.append('whereType', 'Tag');
},
computed: {
// a computed getter
foundTags() {
// `this` points to the vm instance
return this.field.tags.filter((tag) => {
if(tag.name.search(new RegExp(this.searchString, "i")) >= 0){
if(this.selectedTagNames.indexOf(tag.name) == -1){
return tag;
}
};
})
},
selectedTagNames(){
var selNames = this.selectedTags.map((tag) => {
return tag.name;
})
return selNames;
}
},
methods: {
/*
* Set the initial, internal value for the field.
*/
setInitialValue() {
this.value = this.field.value || ''
},
removeTag(tag){
var index = this.selectedTags.indexOf(tag);
if (index > -1) {
this.selectedTags.splice(index, 1);
}
},
addToSelected(tag){
this.selectedTags.push(tag)
},
/**
* Fill the given FormData object with the field's internal value.
*/
fill(formData) {
var tagIdArray = []
this.selectedTags.forEach((tag)=>{
tagIdArray.push(tag.id)
})
formData.append(this.field.attribute, tagIdArray)
},
},
}
</script>
Then, you can overwrite how the save functionality works in your model to accommodate for the "dummy" field. Note below instead of syncing the tags directly on the mutator, which will work most of the time depending on your data structure, I had to pass the tags to the "Saved" event on the model to accommodate for when creating a new record and the associated record id is not yet available, thus cannot be synced for a many to many relationship.
public function setTagsAttribute($value)
{
$tags = explode(",", $value);
$this->tempTags = $tags;
unset($this->tags);
}
protected static function booted()
{
static::saved(function ($article) {
$article->tags()->sync($article->tempTags);
});
}

Resources