Using Vue in Laravel project - laravel-5

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;

Related

how can I display vue data to Laravel blade?

I have a project with Laravel + vue.js.
I made a vue component and it takes some data from a controller.
I wanted to display the data in the view using v-for, but nothing is displaying.
vue template code
<template>
<div v-for="val in expiredIos" class="card col-xs-12 col-md-5 col-lg-2 m-1 p-0 d-inline-block">
<div class="mx-0 p-2 text-truncate" style="width:10rem;vertical-align:middle;">
{{ val.app_name }}
</div>
</div>
...
</template>
vue script part
export default {
data: function() {
return {
expiredIos: []
}
},
mounted() {
console.log("expired here");
this.getExpiredIosData();
},
methods: {
getExpiredIosData: function() {
axios.post('/expired')
.then(response => {
for (var i = 0; i < response.data.length; i++) {
this.expiredIos[i] = response.data[i];
console.log(this.expiredIos[i]);
}
});
}
},
}
The result of console.log
{app_name: "app1", app_id: "migunstyle", ios_dev_exp: "2019-01-16"}
{app_name: "app2", app_id: "jcalling", ios_dev_exp: "2019-02-19"}
{app_name: "app3", app_id: "modoobebe", ios_dev_exp: "2019-03-08"}
{app_name: "app4", app_id: "babyfactory", ios_dev_exp: "2019-03-19"}
{app_name: "app5", app_id: "merrygirl", ios_dev_exp: "2019-03-21"}
...
What did I wrong here?
Try setting the entire array to the data property directly.
getExpiredIosData: function() {
axios.post('/expired')
.then(response => {
this.expiredIos = response.data; // <-- Set property directly
});
}
Vue tracks all data properties, but tracking array changes is something it cannot do. You need to either use the build in array manipulation functions or replace the array entirely for vue to pick up the change.
https://v2.vuejs.org/v2/guide/list.html#Array-Change-Detection

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

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 :)

Laravel router-link works only the first time

I am trying to fetch results from database in News.vue, and display them in Topnews.vue. I have two links fetched. When I click link1, it shows up the Topnews.vue template with everything working as intended, however, if i click link2, nothing happens, except for that the URL changes, but the template does not show up the result. If i refresh the page and click link2 or click on the navbar, then link2, it shows up, and same, clicking then link1, changes the URL, but doesnt show up. I'm really stuck on that and I'd be really glad if you help me out on that issue. Hope you understand.
News.vue
<template id="news">
<div class="col-sm-5">
<div class="cars" v-for="row in filteredNews" >
<div class="name" >
<p class="desc_top_time">{{row.created_at}}</p>
<span class="last_p"> {{row.category}}</span>
<h3 style="margin-bottom:-4px; font-size: 16px;">
<router-link class="btn btn-primary" v-bind:to="{name: 'Topnews', params: {id: row.id} }">{{row.title}}</router-link></h3>
</div></div></div>
</template>
<script>
export default {
data: function() {
return {
news: [],
}
},
created: function() {
let uri = '/news';
Axios.get(uri).then((response) => {
this.news = response.data;
});
},
computed: {
filteredNews: function() {
if (this.news.length) {
return this.news;
}
}
}
}
</script>
Topnews.vue
<template id="topnews1">
<div class="col-sm-7">
<div class="cars">
<img :src="topnews.thumb" class="img-responsive" width=100%/>
<div class="name" ><h3>{{ topnews.title }}</h3>
<p>
<br>{{ topnews.info }}<br/>
</p>
</div></div></div>
</template>
<script>
export default {
data:function(){
return {topnews: {title: '', thumb: '', info: ''}}
},
created:function() {
let uri = '/news/'+this.$route.params.id;
Axios.get(uri).then((response) => {
this.topnews = response.data;
});
}
}
</script>
Like GoogleMac said Vue will reuse the same component whenever possible. Since the route for both IDs use the same component Vue will not recreate it, so the created() method is only being called on the first page. You'll need to use the routers beforeRouteUpdate to capture the route change and update the data.
in TopNews.vue:
export default {
data:function(){
return {topnews: {title: '', thumb: '', info: ''}}
},
beforeRouteEnter:function(to, from, next) {
let uri = '/news/'+ to.params.id;
Axios.get(uri).then((response) => {
next(vm => {
vm.setData(response.data)
})
});
},
beforeRouteUpdate: function(to, from, next) {
let uri = '/news/'+ to.params.id;
Axios.get(uri).then((response) => {
this.setData(response.data);
next();
});
},
methods: {
setData(data) {
this.topnews = data
}
}
}
If you click a link referring to the page you are on, nothing will change. Vue Router is smart enough to not make any changes.
My guess is that the IDs are messed up. If you are using Vue devtools you will be able to easily see what data is in each link. Are they as you expect.

How i can send ajax request after render vue component?

I have a component
html:
table
tr(is="trcom" v-for="xml in xmls" :xml="xml")
js:
components: {
trcom: {
props: ['xml'],
template: "<tr><td> {{ xml.query }} </td><td> downloading </td><td> downloading </td></tr>",
data: function(){
return {
position: "",
}
}
}
}
can i send ajax request and replace template if ajax is done?
final template:
<tr><td> {{ xml.query }} </td> <td> {{ position }} </td> ...etc... </tr>
Given our discussion in the comments below your question, I have a recommendation:
1) The elements that you're adding and want replaced after individual ajax calls should each be their own component.
2) Because you will be using individual child components, you should use the mounted lifecycle hook to perform your ajax calls.
3) Instead of "replacing" the components' templates, which I'm not sure is even possible, you can instead use conditional rendering to show an initial state vs. a post-ajax state.
Below is a toy example which also uses jQuery (the jQuery itself isn't necessary but is being used for simplicity):
Child Component
Vue.component('my-child-component', {
template: `
<div>
<div v-if="initialized">
I'm initialized! My prop value is: {{my_prop}}
</div>
<div v-else>
I'm not initialized yet!
</div>
</div>
`,
props: ['my_prop'],
data: function() {
return {
initialized: false
};
},
mounted: function() {
//needed because we can't use "this" to reference the vue instance in our ajax call!
var this_vue_instance = this;
//this jQuery ajax call will execute as soon as this component has finished rendering
$.post('/your/target/url', {any_data: 'you might need'}, function(data) {
this_vue.initialized = true;
});
}
});
Root Vue Instance
<script>
$(document).ready(function() {
var root_vue_instance = new Vue({
el: '#app',
data: {
items: [0, 1, 2, 3]
}
});
});
</script>
<div id="app">
<div v-for="item in items">
<my-child-component :my_prop="item"></my-child-component>
</div>
</div>
The above is really bare-bones, but should server as a helpful example for implementing the solution to your current problem.

laravel 5.1 Request::ajax return false

Hello i use same script for Laravel 4.2 and Laravel 5.1 and problem is for Laravel 4.2 work perfectly, but on Laravel 5.1 i can't understand why it's return bad result
Problem is why I got $request->ajax() false for Laravel 5.1?
routes.php
Route::post('/upload-image', [
'as' => 'upload-image-post',
'uses' => 'PageController#profileImage'
]);
PageController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class PageController extends Controller
{
public function profileImage(Request $request)
{
//here is problem
//result good: (Laravel 4.2 shows true)
//result bad: (Laravel 5.1 shows false)
var_dump($request->ajax());
}
}
upload-image.blade.php (js)
<script>
jQuery(document).ready(function($) {
$('#upload_image').click(function(event) {
$('#image').trigger('click');
});
$('#image').change(function(event) {
/* Act on the event */
$('#imageform').submit();
});
$('#imageform').ajaxForm({
beforeSubmit: function() {
},
success: function(msg) {
},
error: function(request, status, error) {
},
complete: function(xhr) {
if(xhr.status != 401) {
$('#image').val('');
result = xhr.responseText;
result = $.parseJSON(result);
if( !$.isEmptyObject(result.file_base_url) ) {
var img = new Image();
img.onload = function() {
$('#register_profile_photo').attr('src', img.src);
$('#register_profile_photo').attr('alt', result.image_alt);
//spinner.stop();
$('#upload-image-error').text('');
}
img.src = result.file_base_url;
} else {
$('#upload-image-error').text(result.image[0]);
}
}
}
});
});
upload-image.blade.php (html)
<form enctype="multipart/form-data" name='imageform' role="form" id="imageform" method="post" action="{!! route('upload-image-post') !!}">
{!! csrf_field() !!}
<div style="display:none;">
<input type="file" name="image" id="image" placeholder="Please choose your image" >
</div>
</form>
<div class="profile-img">
<img style="float: right" id="register_profile_photo" src="default.png" alt="Default image">
<div style="float: right" class="img-edit">Edit picture</div>
</div>
PS. If you test for laravel 4.2 this code need change from "{!! .. !!}" to "{{ .. }}"
I do not think this problem is caused by Laravel version. Laravel sources show, that ajax() call is propagated to Symfony's request component. And that source changed good 5 years back.
You should trace if X-Requested-With header is sent to your application in both cases. You can also set breakpoint to Symfony\Component\HttpFoundation\Request::isXmlHttpRequest() and see what you have in headers.

Resources