Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Michael Fayez's avatar

what's missing in my code

Hello best devS , would like to make dropdown menu with Livewire, when creating design I have to choose Project it has to filter only posts related to this project this is the the Design Component:-

<?php

namespace App\Http\Livewire\Design;

use App\Models\Design;
use App\Models\Post;
use App\Models\Project;
use App\Models\Team;
use Livewire\Component;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use App\Listeners\Design\DesignCreatedEmail;
use App\Events\Design\DesignCreated;

class Create extends Component
{
    public Design $design;

    public $posts;
    public $projects;
    public $post;
    public $project;

    public array $mediaToRemove = [];

    public array $listsForFields = [];

    public array $mediaCollections = [];

    public function addMedia($media): void
    {
        $this->mediaCollections[$media['collection_name']][] = $media;
    }

    public function removeMedia($media): void
    {
        $collection = collect($this->mediaCollections[$media['collection_name']]);

        $this->mediaCollections[$media['collection_name']] = $collection->reject(fn ($item) => $item['uuid'] === $media['uuid'])->toArray();

        $this->mediaToRemove[] = $media['uuid'];
    }

    protected function syncMedia(): void
    {
        collect($this->mediaCollections)->flatten(1)
            ->each(fn ($item) => Media::where('uuid', $item['uuid'])
                ->update(['model_id' => $this->design->id]));

        Media::whereIn('uuid', $this->mediaToRemove)->delete();
    }

    public function mount(Design $design)
    {
        $this->design = $design;
        $this->initListsForFields();
    }

    public function updatedPost($value)
    {
        $this->posts = Post::where('Project_id', $value)->get();
        $this->post = $this->posts->first()->id ?? null;
    }

    public function render()
    {
        return view('livewire.design.create');
    }

    public function submit()
    {
        $this->validate();

        $this->design->save();
        $this->syncMedia();
        event(new DesignCreated($this->design));

        return redirect()->route('admin.designs.index');
    }

    protected function rules(): array
    {
        return [
            'design.project_id' => [
                'integer',
                'exists:projects,id',
                'nullable',
            ],
            'design.post_id' => [
                'integer',
                'exists:posts,id',
                'nullable',
            ],
            'mediaCollections.design_design' => [
                'array',
                'required',
            ],
            'mediaCollections.design_design.*.id' => [
                'integer',
                'exists:media,id',
            ],
            'design.statues' => [
                'nullable',
                'in:' . implode(',', array_keys($this->listsForFields['statues'])),
            ],
            'design.confirmation' => [
                'nullable',
                'in:' . implode(',', array_keys($this->listsForFields['confirmation'])),
            ],
            'design.note' => [
                'string',
                'nullable',
            ],
            'design.review' => [
                'nullable',
                'in:' . implode(',', array_keys($this->listsForFields['review'])),
            ],
            'design.team_id' => [
                'integer',
                'exists:teams,id',
                'required',
            ],
        ];
    }

    protected function initListsForFields(): void
    {
        $this->listsForFields['project']      = Project::pluck('name', 'id')->toArray();
        $this->listsForFields['post']         = Post::pluck('title', 'id')->toArray();
        $this->listsForFields['statues']      = $this->design::STATUES_RADIO;
        $this->listsForFields['confirmation'] = $this->design::CONFIRMATION_RADIO;
        $this->listsForFields['review']       = $this->design::REVIEW_RADIO;
        $this->listsForFields['team']         = Team::pluck('name', 'id')->toArray();
    }
}

this is the view side

<form wire:submit.prevent="submit" class="pt-3">

    <div class="form-group {{ $errors->has('design.project_id') ? 'invalid' : '' }}">
        <label class="form-label" for="project">{{ trans('cruds.design.fields.project') }}</label>
            <select wire:model="project" name="project"
                    class="mt-2 text-sm sm:text-base pl-2 pr-4 rounded-lg border border-gray-400 w-full py-2 focus:outline-none focus:border-blue-400"
                    required>
                <option value="">-- choose project --</option>
                 @foreach ($projects as $project)
                    <option value="{{ $project->id }}">{{ $project->name }}</option>
                @endforeach
            </select>
        <div class="validation-message">
            {{ $errors->first('design.project_id') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.design.fields.project_helper') }}
        </div>
    </div>
    <div class="form-group {{ $errors->has('design.post_id') ? 'invalid' : '' }}">
        <label class="form-label" for="post">{{ trans('cruds.design.fields.post') }}</label>
        
            <select wire:model="updatedPost" name="post"
                    class="mt-2 text-sm sm:text-base pl-2 pr-4 rounded-lg border border-gray-400 w-full py-2 focus:outline-none focus:border-blue-400" required>

                @foreach ($posts as $post)
                    <option value="{{ $post->id }}">{{ $post->name }}</option>
                @endforeach
            </select>
        <div class="validation-message">
            {{ $errors->first('design.post_id') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.design.fields.post_helper') }}
        </div>
    </div>

I get foreach() argument must be of type array|object, null given, so what's the mistake ????

0 likes
4 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It looks like the issue is with the way you're trying to populate the $projects and $posts variables and how you're using them in your Blade view. The error message you're getting suggests that $projects or $posts is null when you're trying to iterate over it with foreach.

Here's a revised version of your Livewire component and Blade view that should fix the issue:

Livewire Component:

<?php

namespace App\Http\Livewire\Design;

// ... other use statements ...

class Create extends Component
{
    // ... other properties ...

    public $selectedProjectId = null; // Add a property for the selected project ID

    // ... other methods ...

    public function mount(Design $design)
    {
        $this->design = $design;
        $this->projects = Project::all(); // Load all projects
        $this->posts = collect(); // Initialize posts as an empty collection
        $this->initListsForFields();
    }

    public function updatedSelectedProjectId($projectId)
    {
        $this->posts = Post::where('project_id', $projectId)->get(); // Update posts based on selected project
    }

    // ... other methods ...
}

Blade View:

<form wire:submit.prevent="submit" class="pt-3">

    <div class="form-group {{ $errors->has('design.project_id') ? 'invalid' : '' }}">
        <label class="form-label" for="project">{{ trans('cruds.design.fields.project') }}</label>
        <select wire:model="selectedProjectId" name="project"
                class="mt-2 text-sm sm:text-base pl-2 pr-4 rounded-lg border border-gray-400 w-full py-2 focus:outline-none focus:border-blue-400"
                required>
            <option value="">-- choose project --</option>
            @foreach ($projects as $project)
                <option value="{{ $project->id }}">{{ $project->name }}</option>
            @endforeach
        </select>
        <div class="validation-message">
            {{ $errors->first('design.project_id') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.design.fields.project_helper') }}
        </div>
    </div>
    <div class="form-group {{ $errors->has('design.post_id') ? 'invalid' : '' }}">
        <label class="form-label" for="post">{{ trans('cruds.design.fields.post') }}</label>
        <select wire:model="design.post_id" name="post"
                class="mt-2 text-sm sm:text-base pl-2 pr-4 rounded-lg border border-gray-400 w-full py-2 focus:outline-none focus:border-blue-400" required>
            @foreach ($posts as $post)
                <option value="{{ $post->id }}">{{ $post->title }}</option>
            @endforeach
        </select>
        <div class="validation-message">
            {{ $errors->first('design.post_id') }}
        </div>
        <div class="help-block">
            {{ trans('cruds.design.fields.post_helper') }}
        </div>
    </div>
</form>

Make sure to update the wire:model in the project <select> to selectedProjectId and in the post <select> to design.post_id. Also, ensure that the updatedSelectedProjectId method is named correctly to match the Livewire's automatic convention for updating properties (i.e., updated followed by the CamelCase name of the property).

This should resolve the foreach() error and allow you to select a project and dynamically load the related posts.

1 like
Tray2's avatar

You probably need to pass the $projects in your render method

 public function render()
    {
        return view('livewire.design.create')
			->with([
				'projects' => $project
			]);
    }

Please or to participate in this conversation.