5

I have been running into this very weird issue with Laravel.

I had a problem where one of my component views was not able to read the variables defined in its class. It was kind of strange because I have several components running in my project and they all worked fine, except for this one.

So I created a fresh Laravel project to test some things out (Wanted to check if the problem was on my end, maybe I somehow messed up the project files).

I created a new component on a blank project using php artisan make:component Test

Then I simply added a test variable to the class component like so:

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Test extends Component
{

    public $test;

    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->test = "testing";
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.test');
    }
}

And tried to access it over in the view like so:

<div>
    <p> {{$test}} </p>
</div>

For some reason, this is not working and I can't figure out why. It just says that $test is undefined. Perhaps I should point out, I am a beginner in Laravel, so excuse me if I am making some obvious mistake. It just seemed weird that this is not working on a blank project.

Thank you in advance.

Error-Related Image

4
  • 1
    Change the return statement to return view('components.test', ['test' => $test]); Commented Mar 24, 2021 at 22:11
  • I tried this with $this->test because $test was undefined. It still doesn't work (Same problem). Also, according to the docs, aren't public variables supposed to be available to the view by default? Meaning, I don't have to explicitly pass them like in the example you provided? Commented Mar 24, 2021 at 22:15
  • Does the view works without the variable? Commented Mar 24, 2021 at 22:25
  • Yes it does. No issues if I don't attempt to read any variables. Commented Mar 24, 2021 at 22:38

4 Answers 4

10

In fact, all of the answers are misleading. The $test property is already public, and as such available to the template. Please don't go and manually add parameters to the view.

I just encountered a similar issue, and while I can say for sure that it has to do with the component class name, I could not trace it down, because it started working again magically.

What I can say about it is:

  • I had a class with the same base classname but a different namespace, deleted the non-component class, and then suddenly the component was rendered as an anonymous component, by-passing the component class completely. (You can easily verify that by putting a dd() in your component class constructor.)

  • My first thought was that the autoloader needed a refresh, but composer dump did not change anything.

  • renaming the component class and template to something else solved the issue.

  • when I wanted to track down the bug, I renamed the class and template back to the original name, but now it suddenly worked...

  • my guess is that the view cache was causing the issue. It worked from the moment when I was changing the x-blade (<x-component-name ... />) in the template that was including the component. So it is plausible that the issue magically went away because the cached view was replaced due to the template change.

So based on this, your best options to solve the issue are:

  1. Verify that your properties are public, they will not be available in your template if they are protected or private.
  2. Clear caches, esp. the view cache (php artisan view:clear).
  3. Dump the autoloader (composer dump).
  4. Verify that your class is actually used. Put a dd() in your constructor. If you still get errors from the template, Blade is by-passing your class and trying to use your template as an anonymous component.
  5. Rename the component to something else to see if the class name clashes.

Hope that helps anyone who experiences this confusing issue.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much for this. You pretty much nailed it. I forgot about this question but I planned to come back and write something similar myself. Nevertheless, you are right, for me it magically solved itself, so it was probably something with the view cache and the naming. This is the biggest problem I have with Laravel. These magic name links are helpful, until something stops working. Then it is impossible to debug, because there are no explicit declarations anywhere.
Same situation here. I had a "header" named component. Renamed to "WebsiteHeader" and voila! It worked as expected. So lesson learnt here is: DO NOT use common names. Maybe prefix them with something. Big thank you
THANK YOU! I had used an anonymous component that I then want to do some data manipulation on, so I created its corresponding class in View/Components/. Turns out your #4 was happening — the class file was never even being read. I'm using Roots Sage so a wp acorn view:clear fixed the issue for me
This seems to be caused by not capitalizing the first letter of the component's class name. This is confirmed by Internetbug256's answer above.
3

In my case It was because of cached view so php artisan view:clear did the job

so what is wrong?

The problem happens when you already have a view component and in some point you want to add a dedicated class to provide some data to your component and because laravel already cached your component the "dedicated class" wont be triggered

1 Comment

This can also happen yes. Particularly when you first create the view, and later decide to add some logic to the component. In that case, the old view is cached, and won't read the new changes until the cached viewed is replaced.
1

You need to send variable to the view. Some ways

  1. In an array

    $test = 'Hi';
    return view('components.test', ['test' => $this->test]);
    
  2. Using with

    $test = 'Hi';
    return view('components.test')->with('test', $test);
    
  3. The last one, i like it this one.

    $test = 'Hi';
    return view('components.test', compact('test'));
    

Let me know how it works, regards.

4 Comments

I tried the first way, it didn't work. I will try the other ones a bot later today and come back with results. I read a bit about components in the docs and I was left under the impression that public variables were passed down automatically. (Basically the render function does that in the background)
Okay, so I think I pinpointed the problem. I was right, the public variables are passed on automatically ONLY if they are rendered through the component's class render() method. So if at the routes I point to the component welcome, and inside welcome I try to render test like so: <x-test /> , then this works. However, if I try to render the test component from the route directly, it won't work.
@Teabx I don't think I understand what you are writing... so you tried to use the component template directly in a view() call from a controller action? Of course it only works if it is rendered through the component class. Why shouldn't it?
This is a bit old, and I am a bit more experienced with the framework now. The better explanation to the problem (and possible solutions) are provided in the answer marked as the solution.
-1

within the render() function, instead of return view('components.test');, do return view('components.test', ['test' => $this->test])

1 Comment

I would suggest before answering please look into all the comments as well

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.