简体   繁体   中英

Vue2 Laravel component in list

I am building a Laravel app and trying to use vue.js (without much success.). I'm not understanding the way components work with ajax data, Almost all examples I've found showing this functionality define the data for the component at the app level. not the component level.

I'm trying to dynamically define my data in the component itself, and always get the error that Property or method tasks is not defined on the instance but referenced during render . Here's the component, which is meant to just call out to an endpoint to pull basic "to do" tasks:

Vue.component('tasks', {
    data: function() {
        return {
            tasks: []
        }
    },
    mounted() {
        this.getTasks();
    },
    methods: {
        getTasks() {
            axios.get('/tasks').then(function (response) {
                this.tasks = response.data;
                console.dir(this.tasks);
            })
            .catch(function (error) {
                console.log(error);
            });
        }
    },
    template: `
            <div class="card">
                <div class="card-title">{{ task.name }}</div>
                <div class="card-body">
                    <div class="service-desc">{{ task.description }}</div>
                    <div class="task-notes"><input class="form-control" v-model="task.notes" placeholder="Notes"></div>
                    <div class="task-active"><input type="checkbox" checked data-toggle="toggle" data-size="sm" v-model="task.active" v-on:click="$emit('disable')"></div>
                </div>
            </div>
  `
});

the component is called from within the blade template using:

<tasks v-for="task in tasks" :key="task.id"></tasks>

tasks is declared in the data function, so I'm not sure why vue is telling me it's not defined?

When you define a data property on a component it's only available within that component and its template. Your v-for directive is in the parent scope (ie outside of the component where tasks is defined).

The simplest solution here is probably to move the container element inside the component, and iterate over the tasks there:

<div>
  <div class="card" v-for="task in tasks" :key="task.id">
    <div class="card-title">{{ task.name }}</div>
    <div class="card-body">
      <div class="service-desc">{{ task.description }}</div>
      <div class="task-notes"><input class="form-control" v-model="task.notes" placeholder="Notes"></div>
      <div class="task-active"><input type="checkbox" checked data-toggle="toggle" data-size="sm" v-model="task.active" v-on:click="$emit('disable')"></div>
    </div>
  </div>
</div>

Note : you can't use v-for a template's root element, which is why you'd move the container element into the template.

An alternative is break this into two components (eg TaskList and TaskItem ) where the parent component is responsible for fetching the tasks from the API. The child component can just receive a single task as a prop and render it to the UI.

TaskList

Vue.component('task-list', {
    data: function() {
        return {
            tasks: []
        }
    },
    mounted() {
        this.getTasks();
    },
    methods: {
        getTasks() {
            axios.get('/tasks').then(response => {
                this.tasks = response.data;
                console.dir(this.tasks);
            })
            .catch(error => {
                console.log(error);
            });
        }
    },
    template: `
            <div class="container">
                <task-item
                    v-for="task in tasks"
                    :key="task.id"
                    :task="task"
                />
            </div>
  `
});

TaskItem

Vue.component('tasks', {
    props: {
        task: {
            required: true
        }
    },
    template: `
            <div class="card">
                <div class="card-title">{{ task.name }}</div>
                <div class="card-body">
                    <div class="service-desc">{{ task.description }}</div>
                    <div class="task-notes"><input class="form-control" v-model="task.notes" placeholder="Notes"></div>
                    <div class="task-active"><input type="checkbox" checked data-toggle="toggle" data-size="sm" v-model="task.active" v-on:click="$emit('disable')"></div>
                </div>
            </div>
  `
});

The advantage of this is that it separates the responsibility of the components a little better. You could add logic to the TaskList component to handle displaying a loading spinner and/or error messages for the API call, while TaskItem only has to concern itself with displaying a single task.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM