Viewed   179 times

I'm working with Laravel and Vue to make a single page web application. I've used Vue before to get the data from a database using a controller with no problem, but for some reason I'm now only getting a seemingly infinitely nested JS object that has getter and setter methods stored in each parent object instead of the data I queried. I've seen other people with similar issues, but the solutions that worked for them didn't work for me. For example, some people used JSON.parse(JSON.stringify(response.data)); to get just the raw data, but this doesn't work when I attempt to store it in this.actions. Here is my index method in my ActionLogController

public function index($url)
{

    $companyName = explode("/", $url);

    if(Auth::check())
    {
        $company = Company::where('name', '=', strtolower($companyName[count($companyName) - 1]))->first();

        // If sortby not empty
        $sortby = "created_at";

        //assume desc (most recent)
        $sortdirection = 'desc';

        if(request()->has('sortdirection') && request()->sortdirection == 'asc')
        {
            $sortdirection = 'asc';
        }

        // if sortby is set
        if(request()->has('sortby')) 
        {
            $sortby = request()->sortby;

            switch($sortby) 
            {
                case "date":
                    $sortby = "string_date";
                break;
                case "company":
                    $sortby = "company_name";
                break;
                case "name":
                    // do nothing
                break;
                case "communication-type":
                    $sortby = "communication_type";
                break;
                case "contact":
                    // do nothing
                break;
                case "subject":
                    $sortby = "status";
                break;
                case "assigned-to":
                    $sortby = "assigned_to";
                break;
                case "action":
                    $sortby = "action_item";
                break;
                case "assigned-to":
                    $sortby = "assigned_to";
                break;
                default:
                    $sortby = 'created_at';
                break;
            }
        }
    }

    if($sortdirection == 'asc') {
        return Auth::user()->actionLogs
            ->where('activity_key', '=', '1,' . $company->id)
            ->sortBy($sortby);
    }

    return Auth::user()->actionLogs
        ->where('activity_key', '=', '1,' . $company->id)
        ->sortByDesc($sortby);

}

This is my Vue component to get the data from the controller. I know the template code works, because it worked fine when I sent it dummy data before pulling the data from the controller.

<style scoped>
.action-link {
    cursor: pointer;
}

.m-b-none {
    margin-bottom: 0;
}
</style>

<template>
<div class="table-responsive">
    <table class="table table-striped table-sm">
        <thead>
            <tr>
                <th><a id="sortby-date" class="action-nav" href="?sortby=date&sortdirection=desc">Date</a></th>
                <th><a id="sortby-company" class="action-nav" href="?sortby=company&sortdirection=desc">Company</a></th>
                <th><a id="sortby-name" class="action-nav" href="?sortby=name&sortdirection=desc">Name</a></th>
                <th><a id="sortby-communication-type" class="action-nav" href="?sortby=communication-type&sortdirection=desc">Communication Type</a></th>
                <th><a id="sortby-contact" class="action-nav" href="?sortby=contact&sortdirection=desc">Contact</a></th>
                <th><a id="sortby-subject" class="action-nav" href="?sortby=subject&sortdirection=desc">Subject</a></th>
                <th><a id="sortby-action" class="action-nav" href="?sortby=action&sortdirection=desc">Comment/Action Item</a></th>
                <th>Archive</th>
                <!-- check if admin?? -->
                    <th><a id="sortby-assigned-to" class="action-nav" href="?sortby=date&sortdirection=desc">Assigned To</a></th>
                <!-- /check if admin?? -->
            </tr>
        </thead>
        <tbody v-if="actions.length > 0">
            <tr v-for="action in actions">
                <td>
                    {{ action.string_date }}
                </td>
                <td>
                    {{ action.company_name }}
                </td>
                <td>
                    {{ action.name }}
                </td>
                <td>
                    {{ action.communication_type }}
                </td>
                <td>
                    {{ action.contact }}
                </td>
                <td>
                    {{ action.status }}
                </td>
                <td>
                    {{ action.action_item }}
                </td>
                <td>
                    <input type="checkbox" :id="'archive-' + action.id" class="archive" :name="'archive-' + action.id">
                </td>
                <td :id="'record-' + action.id" class="assigned-to">
                    {{ action.assigned_to }}
                </td>
            </tr>
        </tbody>
    </table>
    <p id="add-action" style="text-align: center;">
      <button id="action-log-add" class="btn btn-sm btn-primary edit">Add Item</button>
      <button id="action-log-edit" class="btn btn-sm btn-danger edit">Edit Items</button>
    </p>
</div>
</template>

<script>
export default {
    data() {
        return {
            actions: []
        }
    },
    methods: {
        getActionLogs(location) {

            var company = location.split("/");
            company = company[company.length - 1];

            axios.get('/action-log/' + company)
                 .then(response => {

                    this.actions = response.data;                        
                    console.log(this.actions);

                 })
                 .catch(error => {
                    console.log('error! ' + error);
                 });
        }
    },
    mounted() {
        this.getActionLogs(window.location.href);
    }
}
</script>

This is the output I get in the browser console

    {…}
?
    1: Getter & Setter
?
    2: Getter & Setter
?
    3: Getter & Setter
?
    4: Getter & Setter
?
    5: Getter & Setter
?
    6: Getter & Setter
?
    7: Getter & Setter
?
    8: Getter & Setter
?
    9: Getter & Setter
?
    10: Getter & Setter
?
    __ob__: Object { value: {…}, dep: {…}, vmCount: 0 }
?
    <prototype>: Object { … }

I was expecting to see the normal array of data that gets returned, but this is what shows up instead and then won't update the component with the data. I'm new to Vue, so maybe there's something really easy I missing, but I can't seem to figure this out.

 Answers

1

Writing up my comments above as a sort of canonical answer to this as it keeps coming up...

What you're looking at is how Vue proxies your data to make it reactive. This is because you're using console.log() on a Vue instance data property.

When you assign values to a data property, it is transformed to an observable so Vue can treat it reactively. I suggest you forget about trying to console.log() anything assigned to this and use the Vue Devtools browser extension to inspect your components and their data if you're having trouble rendering the response.

Please note, there is nothing wrong here.

Thursday, December 15, 2022
 
aterik
 
2

I consider this bad practise because it violates CommandQuerySeparation. Setting a value is changing state (Command). Getting a value is asking for state (Query). A method should not do both, but one thing only.

Also, it's not really obvious what a method does when it's just called username, e.g. does not have a verb, like get or set. This gets even worse in your example, because the return value is either the object itself or the property value, so its not consistent.

Moreover, getters (and setters) should be used sparingly as they will quickly convolute your API. The more getters and setters you have, the more knowledge about an object is required by collaborators of that object. If you find your objects asking other objects about their internals, chances are you misplaced the responsibilities.

Tuesday, December 6, 2022
 
1

As Vue it's client side and laravel it's server side you can't accomplish that in that way.

But you can do something like this over the rendered route:

Create a vue method

goto_route: function (param1) {
     route = '{{ route("yournamedroute", ["yourparameter" => "?anytagtoreplace?"]) }}'
     location.href = route.replace('?anytagtoreplace?', param1)
}

Now in your action element

<div v-for="o in object">
     <a v-on:click="goto_route(o.id_key)">press</a>
</div> 

Basically you're replacing the... uhmm... let's name it "placehoder" in the rendered route with the required value.

hope it helps.

Wednesday, September 21, 2022
 
4

Within axios, you may need to access data from the response that is returned (see console.log examples here), try the following within your comments component:

methods: {
    fetchComments() {
        axios.get(`/results/${this.post.id}/comments`).then((response) => {
            this.comments = response.data.data
        })
    }
}

Note response.data.data is used.

I assume returning the ->paginate() will put the results within a data key in the returned array. If not, then just use response.data.

Also, in the controller getting the comments change to the following:

public function index(Post $post)
{
    return $post->comments()->with('user')->paginate(5);
}

This will eager load the users with the queried comments.

Sunday, December 4, 2022
 
todor
 
5

When you do

@dog = Dog.new

You do two spearate things

1) Create an instance variable @dog for whatever object your code is currently inside

2) Instantiate a new instance of Dog (with all its methods and attributes) and assign a reference to it to @dog

@dog is a variable, that just happens to point at the Dog instance ("instance of class" generally same meaning as "object") you created at that point. You can set other variables to point to the same instance, and in Ruby this is generally how you pass data around. Objects contain instance variables, and those instance variables point to yet more objects.

Using the assignment operator (i.e "=") you can point a variable at any other object.

To answer your questions in turn:

When I am in the owner class and I call @dog.popularity how does it know the value of popularity for that instance?

You have to be careful in Ruby (and OO languages in general) to differentiate between class and object in your descriptions and questions. Ruby I'm assuming you are referring to a line of code in the Owner class, and that you intend it to work with an owner object. I'd also assume that @dog is an attribute you have added to Owner.

In which case, Ruby knows because @dog points to the Dog object that you added to owner. Each Dog object has its own copy of all of Dog's instance variables. You do need to take care in Ruby though, because variables point to objects, that you aren't simply passing in the same Dog object to all the owners (i.e. they all effectively share a single dog). So you need to understand when you are creating new instances (via new) and when you are simply handling existing references.

At runtime are all methods processed and then that instance just always is tied to the value at the time?

No. At runtime, basic Ruby will only perform the assignments that you have coded. Instance variables may not even exist until the code that assigns them has been run. If you use attr_reader etc methods, then the variables will at least exist (but will be nil unless you assign something during initialize)

Friday, November 25, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :