Unexpected form behavior, array value loss on submit

What seems to be the problem:
The problem seems to be when I upload an image and submit the form, I have an item in the array for id it becomes null without an image I’m getting the value.

Steps to Reproduce:

Are you using the latest version of Livewire:

Do you have any screenshots or code examples:
A video link: https://1drv.ms/v/s!AlFUT1sTV7iFiKFymPah1CHqh7DPSg?e=95AhUO

Hey, @hafiz.r
Can you paste some code of your application to figure out what you are missing?

<?php

namespace App\Http\Livewire\Pages\Editor\News;

use Livewire\Component;
use App\Models\News;
use App\Models\NewsAttachment;
use Livewire\WithFileUploads;
use App\Models\Tag;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Arr;

class NewsEdit extends Component
{
    use WithFileUploads;
    public $news;

    public $cover_photo, $cover_title, $cover_caption;
    public $title, $description, $content, $category, $written_by, $news_source, $photo_source, $schedule, $highlight;

    public $accordions = [];
    public $photo_gallery = [];
    public $wide_gallery = [];

    public $type = '';

    public $tags = [];
    public $selectedTags = [];
    public $news_id;

    protected $rules = [
        'cover_photo' => 'required',
        'cover_title' => 'required|min:10|max:255',
        'cover_caption' => 'required|min:10|max:255',
        'title' => 'required|string|max:255',
        'description' => 'nullable',
        'content' => 'nullable',
        'category' => 'required',
        'written_by' => 'nullable',
        'news_source' => 'nullable',
        'photo_source' => 'nullable',
        'schedule' => 'nullable',
        'highlight' => 'boolean',
        'accordions.*.accordion_id' => 'nullable',
        'accordions.*.accordion_title' => 'nullable',
        'accordions.*.accordion_caption' => 'nullable',
        'photo_gallery.*.photo_id' => 'nullable',
        'photo_gallery.*.photo_image' => 'nullable',
        'photo_gallery.*.photo_title' => 'nullable',
        'photo_gallery.*.photo_caption' => 'nullable',
        'wide_gallery.*.wide_id' => 'nullable',
        'wide_gallery.*.wide_image' => 'nullable',
        'wide_gallery.*.wide_title' => 'nullable',
        'wide_gallery.*.wide_caption' => 'nullable',
        'type' => 'required',
        'selectedTags.*.id' => 'exists:tags,id'
    ];

    function mount($news)
    {

        $this->tags = Tag::all()->where('type', '=', 'news');
        $this->news = News::where('id', '=', $news)->with(['attachments', 'tags'])->first();
        $this->news_id = $this->news->id;

        $cover = $this->news->attachments->filter(function ($value, $key) {
            return data_get($value, 'cover') > 0;
        });

        foreach ($cover as $data) {
            $this->cover_photo = $data['path'];
            $this->cover_title = $data['filename'];
            $this->cover_caption = $data['caption'];
        }

        $this->title = $this->news['title'];
        $this->description = $this->news['description'];
        $this->content = $this->news['content'];
        $this->category = $this->news['category'];
        $this->written_by = $this->news['written_by'];
        $this->news_source = $this->news['article_source_from'];
        $this->photo_source = $this->news['photo_source_and_credit_to'];
        $this->schedule = $this->news['featured_publish_date'];
        $this->highlight = $this->news['highlight'];

        $attachments = collect($this->news->attachments->all());
        $existingTags = collect($this->news->tags->all());

        $accordions = $attachments->whereIn('type', 'news_accordions')->values();
        $photo_gallery = $attachments->whereIn('type', 'news_photos')->values();
        $wide_gallery = $attachments->whereIn('type', 'news_wides')->values();

        foreach ($existingTags as $tag) {
            $this->selectedTags[] = ['id' => $tag->id, 'name' => $tag->name];
        }

        foreach ($accordions as $accordion) {
            $this->accordions[] = ['accordion_id' => $accordion->id, 'accordion_title' => $accordion->filename, 'accordion_caption' => $accordion->caption];
        }

        foreach ($photo_gallery as $photo) {
            $this->photo_gallery[] = ['photo_id' => $photo->id, 'photo_image' => $photo->path, 'photo_title' => $photo->filename, 'photo_caption' => $photo->caption];
        }



        foreach ($wide_gallery as $wide) {
            $this->wide_gallery[] = ['wide_id' => $wide->id, 'wide_image' => $wide->path, 'wide_title' => $wide->filename, 'wide_caption' => $wide->caption];
        }
    }

    public function updated($propertyName)
    {
        $this->validateOnly($propertyName);
    }


    public function addTag($id, $name)
    {
        $tagsID = collect($this->selectedTags)->pluck('id')->values()->toArray();
        if (in_array($id, $tagsID)) {
            session()->flash('message', 'Tag already selected');
        } else {
            $this->selectedTags[] = ['id' => strval($id), 'name' => strval($name)];
        }
    }

    public function removeTag($id)
    {
        unset($this->selectedTags[$id]);
        $this->selectedTags = array_values($this->selectedTags);
    }


    public function addAccordionSection()
    {
        $this->accordions[] = ['accordion_title' => '', 'accordion_caption' => ''];
    }

    public function removeAccordionSection($index)
    {
        unset($this->accordions[$index]);
        $this->accordions = array_values($this->accordions);
    }


    public function addPhotoSection()
    {
        $this->photo_gallery[] = ['photo_image' => '', 'photo_title' => '', 'photo_caption' => ''];
    }

    public function removePhotoSection($index)
    {
        unset($this->photo_gallery[$index]);
        $this->photo_gallery = array_values($this->photo_gallery);
    }


    public function addWideSection()
    {
        $this->wide_gallery[] = ['wide_image' => '', 'wide_title' => '', 'wide_caption' => ''];
    }

    public function removeWideSection($index)
    {
        unset($this->wide_gallery[$index]);
        $this->wide_gallery = array_values($this->wide_gallery);
    }







    public function update()
    {
        $this->highlight = filter_var($this->highlight, FILTER_VALIDATE_BOOLEAN);
        $validatedData = $this->validate();
        // dd($this->photo_gallery);

        $news = News::with('tags', 'attachments')->find($this->news_id);

        // cover update section
        $cover = $this->news->attachments->filter(function ($value, $key) {
            return data_get($value, 'cover') > 0;
        })->values()->toArray();

        // get old cover path
        $old_cover_photo = $cover[0]['path'];
        $coverData = NewsAttachment::find($cover[0]['id']);

        // checks if the existing cover_photo is same as the submitted cover_photo
        if ($validatedData['cover_photo'] == $old_cover_photo) {
            $coverData['filename'] = $this->cover_title;
            $coverData['caption'] = $this->cover_caption;
            $coverData->save();
        } else {
            // if not same store the new one and create imagePath
            $imagePath = $this->cover_photo->store('uploads/news/photos', 'public');
            $extension = $this->cover_photo->extension();
            Storage::disk('public')->delete($old_cover_photo); // delete old cover in directory
            $this->cover_photo = $imagePath;
            $coverData['path'] = $this->cover_photo; // set new cover image path
            $coverData['filename'] = $this->cover_title;
            $coverData['extension'] = $extension;
            $coverData['caption'] = $this->cover_caption;
            $coverData->save();
        }
        // cover update end




        // accordion update start
        $existingAccordions = $this->news->attachments->whereIn('type', 'news_accordions')->values()->toArray();
        if (isset($validatedData['accordions'])) {
            foreach ($this->accordions as $accordionIndex => $accordion) {
                if (isset($accordion['accordion_id'])) {
                    $attachment = NewsAttachment::find($accordion['accordion_id']);
                    $attachment->filename = $accordion['accordion_title'];
                    $attachment->caption = $accordion['accordion_caption'];
                    $attachment->save();
                } else {
                    $news->attachments()->create(['type' => 'news_accordions', 'filename' => $accordion['accordion_title'], 'caption' => $accordion['accordion_caption']]);
                }
            }
            $existingAccordions = $this->news->attachments->whereIn('type', 'news_accordions');
            $existingAccordionsID = $existingAccordions->pluck('id')->values()->toArray();
            $currID = collect($this->accordions)->pluck('accordion_id')->values()->toArray();
            $res = array_diff($existingAccordionsID, $currID);
            foreach ($res as $del) {
                $news = NewsAttachment::find($del);
                $news->delete();
            }
        } else {
            foreach ($existingAccordions as $existingAccordion) {
                $attachment = NewsAttachment::find($existingAccordion['id']);
                $attachment->delete();
            }
        }
        // accordion update end


        // photo gallery update start

        $existingPhotoGallery = $this->news->attachments->whereIn('type', 'news_photos')->values()->toArray();

        // // dump($existingPhotoGallery);
        // // dump($this->photo_gallery);

        if (isset($validatedData['photo_gallery'])) {
            // dd($this->photo_gallery);
            foreach ($this->photo_gallery as $photo) {
                // dd($photo);
                if (isset($photo['photo_id'])) {
                    $attachment = NewsAttachment::find($photo['photo_id']);
                    if ($attachment->path == $photo['photo_image']) {
                        $attachment->filename = $photo['photo_title'];
                        $attachment->caption = $photo['photo_caption'];
                        $attachment->save();
                    } else {
                        $imagePath = $photo['photo_image']->store('uploads/news/photos', 'public');
                        $extension = $photo['photo_image']->extension();
                        Storage::disk('public')->delete($attachment->path); // delete old cover in directory
                        $photo['photo_image'] = $imagePath;
                        $attachment['path'] = $photo['photo_image']; // set new cover image path
                        $attachment['filename'] = $photo['photo_title'];
                        $attachment['extension'] = $extension;
                        $attachment['caption'] = $this->cover_caption;
                        $attachment->save();
                    }
                } else {
                    $news->attachments()->create(['type' => 'news_photos', 'filename' => $photo['photo_title'], 'caption' => $photo['photo_caption']]);
                }
            }
            $existingPhotoGallery = $this->news->attachments->whereIn('type', 'news_photos');
            $existingPhotoGalleryID = $existingPhotoGallery->pluck('id')->values()->toArray();
            $currPhotoGalleryID = collect($this->photo_gallery)->pluck('photo_id')->values()->toArray();
            $phDeletable = array_diff($existingPhotoGalleryID, $currPhotoGalleryID);

            foreach ($phDeletable as $del) {
                $news = NewsAttachment::find($del);
                $news->delete();
            }
        } else {
            foreach ($existingPhotoGallery as $photo) {
                $attachment = NewsAttachment::find($photo['id']);
                $attachment->delete();
            }
        }
        // photo gallery update end



        // wide gallery update start
        $existingWideGallery = $this->news->attachments->whereIn('type', 'news_wides')->values()->toArray();
        // dd($validatedData['wide_gallery']);
        if (isset($validatedData['wide_gallery'])) {
            foreach ($this->wide_gallery as $wide) {
                if (isset($wide['wide_id'])) {
                    $attachment = NewsAttachment::find($wide['wide_id']);
                    $attachment->filename = $wide['wide_title'];
                    $attachment->caption = $wide['wide_caption'];
                    $attachment->save();
                } else {
                    if ($wide['wide_image'] != '') {
                        $imagePath = $wide['wide_image']->store('uploads/news/wides', 'public');
                        $extension = $wide['wide_image']->extension();
                        $wide['wide_image'] = $imagePath;
                        $news->attachments()->create(['type' => 'news_wides', 'path' => $wide['wide_image'], 'extension' => $extension, 'filename' => $wide['wide_title'], 'caption' => $wide['wide_caption']]);
                    } else {
                        $news = News::with('tags', 'attachments')->find($this->news_id);
                        $news->attachments()->create(['type' => 'news_wides', 'filename' => $wide['wide_title'], 'caption' => $wide['wide_caption']]);
                    }
                }
            }
            $existingWideGallery = $this->news->attachments->whereIn('type', 'news_wides');
            $existingWideGalleryID = $existingWideGallery->pluck('id')->values()->toArray();
            $currWideGalleryID = collect($this->wide_gallery)->pluck('wide_id')->values()->toArray();
            $widesDeletable = array_diff($existingWideGalleryID, $currWideGalleryID);

            foreach ($widesDeletable as $del) {
                $news = NewsAttachment::find($del);
                $news->delete();
            }
        } else {
            foreach ($existingWideGallery as $wide) {
                $attachment = NewsAttachment::find($wide['id']);
                $attachment->delete();
            }
        }
        // wide gallery update end





        // common details and tag update
        $news->title = $validatedData['title'];
        $news->content = $validatedData['content'];
        $news->description = $validatedData['description'];
        $news->category = $validatedData['category'];
        $news->written_by = $validatedData['written_by'];
        $news->article_source_from = $validatedData['news_source'];
        $news->photo_source_and_credit_to = $validatedData['photo_source'];
        $news->featured_publish_date = $validatedData['schedule'];
        $news->STATUS = $validatedData['type'];
        $news->highlight = $validatedData['highlight'];

        // remove previous tags
        foreach ($news->tags->all() as $tag) {
            $news->tags()->detach($tag['id']);
        }

        // add new selected tags
        foreach ($validatedData['selectedTags'] as $tag) {
            $news->tags()->attach($tag['id']);
        }

        $news->save();
        session()->flash('message', 'News successfully updated.');
        return redirect()->route('news.edit', $this->news_id);

        // dd($news);

        // $selectedTagID = array_map(function ($var) {
        //     return ($var['id']);
        // }, $this->selectedTags);


        // $existingTagID = array_map(function ($var) {
        //     return ($var['id']);
        // }, $news->tags->all());

        // $newTags = array_diff( $existingTagID, $selectedTagID);



    }


    public function render()
    {
        return view('livewire.pages.editor.news.news-edit')
            ->extends('layouts.auth')
            ->section('page');
    }
}

blade

<div class="row">
            <div class="col-2">
                Photo Gallery
            </div>


            <div class="col">

                @foreach($photo_gallery as $index => $value)
                <div class="row pb-3">
                    <div class="col imageSection p-0">
                        @if($photo_gallery[$index]['photo_image'])
                        <img class="image" src="{{asset('storage/'.$photo_gallery[$index]['photo_image'])}}"
                            height="200" width="200" alt="">
                        <button class="btn btn-danger btn-sm remove"
                            wire:click.prevent="removePhotoSection({{$index}})">Delete</button>
                        @elseif($photo_gallery[$index]['photo_image'] == '')
                        <input id="photo_gallery[{{$index}}][photo_title]" name="photo_gallery[{{$index}}][photo_title]"
                            class="remove" wire:model="photo_gallery.{{$index}}.photo_image"
                            class="form-control @error('photo_image') is-invalid @enderror " type="file">
                        <label for="photo_gallery[{{$index}}][photo_title]"
                            class="btn btn-danger btn-sm remove">Change</label>
                        @else
                        <input name="photo_gallery[{{$index}}][photo_title]"
                            wire:model="photo_gallery.{{$index}}.photo_image"
                            class="form-control @error('photo_image') is-invalid @enderror " type="file">
                        @endif



                    </div>
                    <div class="col">
                        <div class="form-group row">
                            <label for="photo_title" class="col-sm-2 col-form-label">Title</label>
                            <div class="col-sm-10">
                                <input name="photo_gallery[{{$index}}][photo_title]" type="text" class="form-control"
                                    placeholder="Title" wire:model="photo_gallery.{{$index}}.photo_title">
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="photo_caption" class="col-sm-2 col-form-label">Caption</label>
                            <div class="col-sm-10">
                                <textarea name="photo_gallery[{{$index}}][photo_caption]" class="form-control" rows="2"
                                    wire:model="photo_gallery.{{$index}}.photo_caption"></textarea>
                            </div>
                        </div>

                    </div>
                </div>
                @endforeach
                <label class="add_button" wire:click.prevent="addPhotoSection"><img src="{{asset('icons/add-pic.png')}}"
                        alt="">
                    Add</label>
            </div>

        </div>

wallah you’ve to solve it man. :sweat_smile:
I am stuck with it for a while @skywalker

    public function addPhotoSection()
    {
        $this->photo_gallery[] = ['photo_image' => '', 'photo_title' => '', 'photo_caption' => ''];
    }

Why you are setting the $photo_gallery values to empty?

for a new section, dynamic form

Try to send the photo_id with the image and reset it again!

You Have passed a lot of code :smile: I’m lost man

Can you at least explain to me what you are trying to do exactly, from the code I notice you are updating an image not create a new one,

So If your News Model Contain the Image itself and you want to update the image use the news_id

If you have separate table contain images and related with News Model use the relationships while updating the images (e.x $this->news->images()->update($data)) or something like that.
Or if you have some more explanation I’m Happy to hear.

I am getting the id while i submit from without file. but when i submit it with file the id shows null.

there can be update, create and delete in submission. Do you have any better way to do it?


I saw the same problem with yours and the solution is change the typecasting of the id from integer to string (e.g. (string)$this->id or $this->id = '' + $model->id)