0

I am learning how to use vue with laravel. I have basic loops working well to pull direct model relationships, but I can't figure out how to access model methods in a loop. Many of my Larvel models have basic information formulated with a method pulling data from related models. I've tried to research it and think the answer might be some combination of eager loading, preformating the answer as a json response or maybe something with axios, but the snipits I've found aren't clear on what goes where, or what needs to be in place for them to work correctly. I've tried both eager loading and using a json response and neither has worked. I can access methods in simple vue components that are just text, but not in a loop where the variable isn't part of the page.

Example: I want to use Vue to display a list of ingredients on a recipe's page. The ingredient "title" is a method pulling the information from a related model.

RecipeController.php

  public function show(Recipe $recipe)
  {
    $ingredients = $recipe->ingredients;

    $view = $this->view('recipes.show');
    //(variable in the view, variable defined in current function)
    $view->with('recipe', $recipe);
    $view->with('ingredients', $ingredients);

    return $view;
  }

Recipe.php

  public function ingredients()
  {
    return $this->hasMany('App\Models\Ingredient', 'recipe_id', 'recipe_id');
  }

Ingredient.php

  public function title()
  {
    $title = $this->item->title();
    return $title;
  }

  public function vueTitle()
  {
    $title = Ingredient::title()->get();

    return response()->json($title );
  }

Recipes/show.php

<div>
  <ul>
      <li
        is="test-li"
        v-for="ingredient in {{ $ingredients }}"
        v-bind:key="ingredient.ingredient_id"
        v-bind:title= "ingredient.vueTitle"
        v-bind:id="ingredient.ingredient_id"
      ></li>
  </ul>
</div>

I'd prefer to reuse the same methods, but created a new one to try converting to json first but that didn't work (or I'm doing it wrong). I tried eager loading, but it either did nothing, or generated an error (Call to a member function on null) if I tried to eager load the specific method. I've tried various combinations of binding and not binding the title component. I've also tried title= "{{ingredient->title()}}" but that syntax errors.

How can I get the result of the Laravel method in a Vue loop?

jumki
  • 35
  • 6
  • I don't think this is possible. Printing objects from PHP does not magically transfer them into vue. Vue is made so you render the template in-browser. Why render it server-side to render it in-browser? You would typically create an API which responds with an array of objects. That can be looped through by vue. PHP objects cannot exist in JavaScript simply by printing them. – Peter Krebs Jun 15 '21 at 15:56
  • If an api is what it takes than that is what I will have to do (I can't just use blade/php because I need vue to make dynamic forms) I have never done api's before and was hoping to avoid them until I got the basics figured out, and I want to avoid adding extra dependencies/complexity that I don't understand. Do you have a recommendation for a guide that would show how to get the laravel method information into vue, including setting up the api? – jumki Jun 15 '21 at 16:46
  • You might just as well search the internet for *laravel build api tutorial*. It is not hard with Laravel, but it takes a bit of time to set up. Your intermediate solution might work for now but having an API opens up all sorts of possibilities for implementations in the frontend. – Peter Krebs Jun 16 '21 at 08:18
  • Setting up an accessor worked well for the time being. I'm sure I'll have to dig into api's later, but would rather wait until I have specific use cases. – jumki Jun 16 '21 at 14:36

2 Answers2

0

After more searching, I found this post which described how to add an accessor to a model. Doing so allowed me to access my custom method as if it were a standard direct relationship. It was a straightforward modification and will reduce complexity in a number of places. I made the following modifications:

Ingredient.php Added the get..Attribute() function and appended the array

  ...
  protected $table = 'ingredients';
  ...
  protected $appends = array('title');

  // Access methods as direct relationships
  public function getTitleAttribute()
  {
      return $this->title();
  }

Recipes/show.php Bound the title prop to the ingredient title as if it were a direct relationship.


    <div>
      <ul>
          <li
            is="test-li"
            v-for="ingredient in {{ $ingredients }}"
            v-bind:key="ingredient.ingredient_id"
            v-bind:title= "ingredient.title"
            v-bind:id="ingredient.ingredient_id"
          ></li>
      </ul>
    </div>

jumki
  • 35
  • 6
0

Another example, hope one may find it helpful:

Model.php

     /**
     * Accessor for Age.
     */
    protected $appends = ['age'];

    public function getAgeAttribute()
    {
        return Carbon::parse($this->attributes['dob'])->age;
    }

VueFile.vue

    <td>
      <span v-bind:age="user.age"> {{user.age}} </span>
    </td>
mante
  • 87
  • 1
  • 9