Laravel and vuejs -> how to pass Controller data into my Vue view? - laravel

I am discovering php, laravel, vuejs at the same time and I guess there are some things I didn't get well yet ;)
I made a new component "tableau" which is a basic table and would like to use it at many places in my app, where I would just specify its title, columns and data.
FootballerController is the place where I get all my data.
Here is what is working now:
app.js
const tableau = new Vue({
components:{tableau:Tableau
},
data: function() {
return {
title: "the best footballers",
searchQuery: '',
gridColumns: ['footballer', 'cote', 'nationalite'],
gridData: [
{ footballer: 'Remond', cote: 951, nationalite:'USA' },
{ footballer: 'Marcel', cote: 935, nationalite:'ESP' },
{ footballer: 'Stian', cote: 923, nationalite:'NOR' },
{ footballer: 'Martin', cote: 923, nationalite:'USA' },
{ footballer: 'Pierre', cote: 918, nationalite:'ESP' },
]
}
}
}).$mount('#tableau');
footballer.blade.php
<tableau
v-bind:titre="title"
:rows="gridData"
:columns="gridColumns "
:filter-key="searchQuery" >
</tableau>
TableauComponent
<template>
<div >
<h1 >{{titre}}</h1>
<table >
<thead>
<tr>
<th v-for="key in columns"
{{ key | capitalize }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in rows">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name:'tableau',
props: {
rows: Array,
columns: Array,
titre: String
}
}
</script>
This works.
Then, here is what I would like: being able to put my values from the controller into footballer.blade.php, which is using TableauComponent.vue
FootballerController
public function footballer($id){
//process to get all this data in DB ($footballer, $gridData, $gridColumns, $title)
$footballer= (Footballer::select(SOME REQUEST)->where('id', '=', $id)->get())[0];
return view('footballers/footballer', ['footballer' => $footballer,
'gridData' => $gridData,
'gridColumns' => $gridColumns,
'title' => $title] );
}
And in footballer.blade.php
<tableau
v-bind:titre="{{ $title }}"
:rows="{{ $gridData }}"
:columns="{{ $gridColumns }}" >
</tableau>
Then in app.js I wouldn't need data anymore
const tableau = new Vue({
components:{tableau:Tableau
}
}).$mount('#tableau');
But this doesn't work and tells me "Property or method is not defined on the instance but referenced during render"
I don't manage at all and am worndering is I have the good way of doing: Should I not get my data in FootballerController? If not, where can I get it then?
Thanks a lot in advance.

When you use {{ value }} in both Blade & javascript framework at the same time. You need to use #{{ value }} to avoid collision between Blade & Vue.
try
<tableau
v-bind:titre="#{{ $title }}"
:rows="#{{ $gridData }}"
:columns="#{{ $gridColumns }}" >
</tableau>
Besides that, when you use :rows="value", the value must be javascript syntax, otherwise when rows="value", the value would be treated as string.
You might need to use json_encode to format your data from the Laravel, or use #json if you're using Laravel 5.5^.

Your are using ':' symbol before your attributes in your blade, which means 'v-bind' as the doc says : VueJS Shorthands.
So first, for assigning a String to a props, you don't need ':' before 'titre'.
Then, to solve your problem you could try to add a default value to your props, for example :
props: {
rows: {
default: []
},
columns: {
default: []
},
titre: {
default: ''
}
}
I didn't try but I think it should works.

Thanks a lot, indeed the php array to javascript array was the issue.
In the php controller, I parse my data into json
'gridData' =>json_encode($gridData),
In the php view footballer.blade.php
<tableau
titre="{{ $title }}"
rows="{{ $gridData }}">
</tableau>
And in my Vue view, I was getting an array, and changed the code for this:
rows: {
type: String,
default: ""
}
var rowsArray = JSON.parse(this.rows)
Now it seems like the data I get after my request isn't properly parsed, but that's another point :)

Related

Why I can't see my props from backend in my nuxt page?

I'm making an index page nad I have to recover from my db customers data and insert it in a table element in my index page.
I've set my props, mounted function with axios that get the data from the backend route and in a data function I return customers array,
my index.vue page:
<template>
<div>
<table v-if="customers">
<tr>
<th>name</th>
<th>address</th>
</tr>
<tr>
<td>{{ customers.name }}</td>
<td>{{ customers.address }}</td>
</tr>
</table>
</div>
</template>
<script>
import Table from "../components/Table.vue";
export default {
components: { Table },
name: "IndexPage",
data() {
return {
customers: [],
};
},
props: {
customer: {
required: true,
type: Object,
},
},
async mounted() {
const response = await this.$axios.$get("/api/customers");
this.customers = response.data;
},
};
</script>
if I write {{ customers }} the function return the list of customers fields but when I search for a specific data (for example {{ customers.name }}) it don't return me nothing, even errors.
Obviously I've set baseurl in nuxt.config with address of my laravel app

How to make array checkbox to work in laravel blade with petite-vue?

I want to create checkboxes which trigger a vue function when a user checks them. These checkboxes are an array. The problem I have is when I check one of the checkboxes, it will check all of them instead of the one I want.
Here is the script in the blade file.
#foreach ($students as $item)
<tr>
<td>{{ $item->student->name }} {{ $item->student_id }}</td>
<td>
<input type="checkbox" value="1" v-model="store.status"
#change="onclick('{{ $schedule->id }}','{{ $item->student_id }}')" id="">
Present
</td>
</tr>
#endforeach
And here is petite-vue script
<script type="module">
import {
createApp, reactive
} from 'https://unpkg.com/petite-vue?module';
createApp({
store: {
status: [],
},
onclick(schedule_id, student_id)
{
const token = '{{ $token }}';
const config = {
headers: { Authorization: 'Bearer ' + token }
}
const data = {schedule_id: schedule_id, student_id: student_id, status: `${this.store.status}`}
axios.post(`http://localhost:10000/api/check-present`, data, config)
.then((result) => {
console.log(result.data);
$('#successModal').modal('show');
})
.catch((err) => {
console.log(err.response)
});
}
}).mount('#app');
I look forward to idea how to solve this problem. Thanks.

Laravel + Vuetify error: Error in render: this.items.slice is not a function" & Invalid prop: Expected Array, got Object

I'm using vuetify and laravel to display some data from an array using vuetify's data table. The data get's displayed on the table fine, but these two errors appear? I need some help as for what I can do to avoid these errors.
Errors:
Error in render: "TypeError: this.items.slice is not a function"
Invalid prop: type check failed for prop "items". Expected Array, got Object
I've tried searching for the Invalid prop error for a while now but still nothing helped. As for the error in render part, this is where I really haven't found anything.
.Vue Data table:
<v-data-table
:headers="headers"
:items="lists"
class="elevation-1"
>
<v-btn color="success">Success</v-btn>
<template v-slot:items="lists">
<td class="text-xs-left">{{ lists.item.Customer }}</td>
<td class="text-xs-right">{{ lists.item.Address }}</td>
<td class="justify-center layout px-0">
<v-icon small class="mr-2" color="teal">visibility</v-icon>
<v-icon small class="mr-2" color="orange darken-2">edit</v-icon>
<v-icon small color="red darken-2">delete</v-icon>
</td>
</template>
script:
<script>
let Add = require('./Add.vue');
export default {
components: { Add },
data () {
return {
lists:{},
errors:{},
headers: [
{
text: 'Customer',
align: 'left',
value: 'Customer'
},
{ text: 'Address', value: 'Address' },
{ text: 'Contact No', value: 'CustomerContactNo' },
],
}
},
mounted(){
axios.post('/getData')
.then((response)=> this.lists = response.data)
.catch((error) => this.errors = error.response.data)
}
}
</script>
How do I avoid these errors? Any help is appreciated, Thanks.
Both errors suggest you have a prop called items that is being passed an object instead of an array.
A candidate would be the prop called items here:
<v-data-table
:headers="headers"
:items="lists"
class="elevation-1"
>
Based on those errors we can guess that the value lists might incorrectly be an object. Digging further, if we take a look in your JS code we find this:
data () {
return {
lists: {},
So your initial value is an object, not an array. Once your remote data shows up it will be replaced with an array and everything will appear to work correctly.
Try changing lists: {}, to lists: [],.

Using Vue in Laravel project

working on a project in Laravel and I want to integrate Vue and Vue Resource into it. I have setup it up but it is not working as expected. Below is my code:
routes.php
Route::get('api/projects', function() {
return App\Project::all();
});
app.js
new Vue({
el: '#project',
data: {
projects: []
},
ready: function() {
this.getProjects();
},
methods: {
getProjects: function() {
this.$http.get('api/projects').then(function(projects) {
this.$set('projects', projects);
});
}
}
});
my view
<div class="content" v-for="project in projects">
<h3 class="title">
#{{ project.title }}
</h3>
#{{ project.description }}
</div>
With the code above, nothing is displayed on the page but if I
#{{ $data | json }}
I get projects data in json. This is kind of weird, please what am I doing wrong.
Thanks to #PROGRAMMATOR on laracast. His answer solved the issue.
this.$set('projects', projects.data);
I saw you are using code like this :
this.$http.get('api/projects').then(function(projects) {
this.$set('projects', projects);
});
But you have to bind this with $http request as right now this.$http working within method :
this.$http.get('api/projects').then(function(projects) {
this.$set('projects', projects);
}.bind(this));
You can use like this also :
this.projects = projects;
then :
{{ $data | json }}
if result coming along with .data array then
this.projects = projects.data;

Sorting and Filtering ajax data using Laravel and VueJs

Current code is sorting and filtering data using vue.js. It is working fine but data is dummy, it is hardcoded. I need to get data dynamically from table using vue js and laravel. How can I get dynamic data in gridData?
JS
Vue.component('demo-grid', {
template: '#grid-template',
props: {
data: Array,
columns: Array,
filterKey: String
},
data: function () {
var sortOrders = {}
this.columns.forEach(function (key) {
sortOrders[key] = 1
})
return {
sortKey: '',
sortOrders: sortOrders
}
},
methods: {
sortBy: function (key) {
this.sortKey = key
this.sortOrders[key] = this.sortOrders[key] * -1
}
}
})
// bootstrap the demo
var demo = new Vue({
el: '#app',
data: {
searchQuery: '',
gridColumns: ['name', 'power'],
gridData: [
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
}
})
laravel.blade.php
#extends('layouts.app')
#section('title', 'Customers List')
#section('styles')
#endsection
#section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">Customers List</div>
<div class="panel-body">
<script type="text/x-template" id="grid-template">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th v-for="key in columns" #click="sortBy(key)" :class="{active: sortKey == key}">#{{key | capitalize}}<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'"></span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in data | filterBy filterKey | orderBy sortKey sortOrders[sortKey]">
<td v-for="key in columns">
#{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</script>
<div id="app">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid :data="gridData" :columns="gridColumns" :filter-key="searchQuery"></demo-grid>
</div>
</div>
</div>
</div>
</div>
</div>
#endsection
#section('scripts')
<script src="/js/vue.js"></script>
<script src="/js/vue-resource.min.js"></script>
<script src="/js/customers.js"></script>
#endsection
You will need to do a few things.
First, in Laravel, create a new route in your routes.php file, for ex.:
Route::get('/api/fighters', 'SomeController#index');
Then in your controller (somecontroller.php), you will have a method index which will query your database table and return it as JSON data.
public function index() {
//query your database any way you like. ex:
$fighters = Fighter::all();
//assuming here that $fighters will be a collection or an array of fighters with their names and power
//when you just return this, Laravel will automatically send it out as JSON.
return $fighters;
}
Now, in Vue, your can call this route and grab the data. Using AJAX. You can use any AJAX library that you like, even jQuery. I currently use Superagent.js. Vue will work just fine with any.
So, in your Vue code, create a new method to get your data.:
methods: {
getDataFromLaravel: function() {
//assign `this` to a new variable. we will use it to access vue's data properties and methods inside our ajax callback
var self = this;
//build your ajax call here. for example with superagent.js
request.get('/api/fighters')
.end(function(err,response) {
if (response.ok) {
self.gridData = response.body;
}
else {
alert('Oh no! We have a problem!');
}
}
}
}
Then you can just call this new method using a button or anyway you like. For example, using a button click event:
<button type="button" #click="getDataFromLaravel">Get Data</button>
Or you can even just have the data loaded automatically using Vue's ready function:
// bootstrap the demo
var demo = new Vue({
el: '#app',
data: {
.... }
ready: function () {
this.getDataFromLaravel();
},
methods: {
.... }
});
Done! You now have your database data assigned to Vue's data property gridData.

Resources