Sorting and Filtering ajax data using Laravel and VueJs - laravel

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.

Related

How to pass a vue data value or id from a href link to load new component to show this value or id?

I have one vue componet i wanna click to a href link bellow code to load another vue componet to pass id or any value of this form.
<template>
<div class="container">
<table class="table table-hover">
<tbody>
<tr>
<th>No</th>
<th>another vue component</th>
</tr>
<tr>
<td>1 </td>
<td>
<a href="'/NewVueComponent.vue/ + this.form.id'" > show </a>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data (){
return {
form: new Form({
id: '',
})
}
}
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
In your view component, have a method that will push router to another view. The id can be passed as an arg via params.
<script>
export default: {
data() {
return {
id: "someId"
}
},
methods: {
goTo() {
this.$router.push({name: OtherComponent, params: {
id: this.id
}})
}
}
}
</script>
and on your route declaration, make sure props is set to true
{
path: "/path-to-component",
component: OtherComponent,
name: "OtherComponent",
props: true,
}
and of course on the OtherComponent you will have to define id as a prop.
You can read more about it here https://router.vuejs.org/guide/essentials/passing-props.html

Data are not loaded in Edit Form in Vue app

I'm experimenting with Vue.js and Axios with Laravel. I'm using this tutorial where a simple Posts app is build: https://pusher.com/tutorials/laravel-vue-axios. I'm trying to extend this with an Update function. When I'm clicking on the edit button near a Post, the right Id is fetched. But in my Edit form the data of the post aren't loading. What could be the issue?
This is my code in EditPost.vue:
<template>
<form action="" #submit="editPost(post)">
<h4 class="text-center font-weight-bold">Post edit form</h4>
<div class="form-group">
<input type="text" placeholder="title" class="form-control"> {{ post.title }}
</div>
<div class="form-group">
<textarea placeholder="content" class="form-control" v-model="post.content">
</textarea>
</div>
<div class="form-group">
<button :disabled="!isValid" class="btn btn-block btn-primary" #click.prevent="updatePost(post)">Update
</button>
</div>
</form>
</template>
<script>
import {mapGetters, mapActions} from 'vuex'
export default {
name: "EditPost",
data() {
return {
post:{}
}
},
created () {
this.fetchData();
},
mounted() {
this.$store.dispatch('fetchPost')
},
methods: {
...mapActions('post', [
'fetchPost',
'updatePost'
]),
updatePost(post) {
this.$store.dispatch('updatePost', post)
},
fetchData: function () {
var _this = this;
// ajax call - then
_this.$store.commit('setData', {
name: 'post',
data: res.data.post
});
}
},
computed: mapGetters([
'posts'
])
}
</script>
This is the code in recources/js/store/actions.js:
fetchPost({commit}, post) {
axios.get(`/api/posts/${post.id}`)
.then(res => {
commit('FETCH_POST', res.data)
}).catch(err => {
console.log(err)
})
},
UPDATE: I've put in extra code.
file Posts.vue:
<template>
<div>
<h4 class="text-center font-weight-bold">Posts</h4>
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Content</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="post in posts">
<td>{{post.title}}</td>
<td>{{post.content}}</td>
<td>
<button class="btn btn-info" #click="editPost(post)"><i style="color:white" class="fa fa-edit"></i></button>
<button class="btn btn-danger" #click="deletePost(post)"><i style="color:white" class="fa fa-trash"></i></button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
name: "Posts",
mounted() {
this.$store.dispatch('fetchPosts')
},
methods: {
editPost(post) {
this.$store.dispatch('fetchPost',post)
},
deletePost(post) {
this.$store.dispatch('deletePost',post)
}
},
computed: {
...mapGetters([
'posts'
])
}
}
</script>
file recources/js/store/getters.js:
let getters = {
posts: state => {
return state.posts
}
}
export default getters
file recources/js/store/state.js:
let state = {
posts: []
}
export default state
file recources/js/store/mutations.js:
let mutations = {
CREATE_POST(state, post) {
state.posts.unshift(post)
},
FETCH_POSTS(state, posts) {
return state.posts = posts
},
UPDATE_POST(state, post) {
let index = state.posts.findIndex(item => item.id === post.id)
},
DELETE_POST(state, post) {
let index = state.posts.findIndex(item => item.id === post.id)
state.posts.splice(index, 1)
}
}
export default mutations
You are using post.content, which is coming from your data prop post. I don't see you adding content to post anywhere in your code.
I'm assuming your getter posts is getting the post data from the store.
So maybe you just need to use that instead?
v-model="posts.content">
Without seeing more of your code I cannot tell you exactly what to do. But your main problem is after you update the store value you need to get that value somehow.

How to Fetch data using Vue Js laravel

How do I fetch data using vue js and laravel . I have created vue component and controller.
Here is my database table structure
<script>
export default {
data(){
return {
kudos : []
}
},
created(){
axios.get('./api/kudos')
.then(response => this.kudos = response.data);
}
}
</script>
What I need to do is fetch the database data to blade file using vuejs .
Could someone guide me step by step?
Controller
Vue Component
Blade File
I think you're looking for something like this?
Controller:
public function searchDatabase( Request $request )
{
$foo = DB::table('bar')
->where([
["description", 'LIKE', "%{$request->input('query')}%"]
])
->limit(5)
->get();
return response()->json($foo);
}
YourComponent.vue
<template>
<div id="wrapper">
<div class="input-group">
<input type="text" placeholder="Search database.." v-model="query" v-on:keyup="autoComplete" class="form-control">
</div>
<div class="panel-footer" v-if="results.length">
<table class="table table-sm">
<tr v-bind:key="result" v-for="result in results">
<td> {{ result.description }} </td>
</tr>
</table>
</div>
</div>
</template>
<script>
export default{
data(){
return {
query: '',
url: '/search/blade/route',
results: []
}
},
methods: {
autoComplete(){
this.results = [];
if(this.query.length > 2){
axios.get('/api/kudos', {params: {query: this.query}}).then(response => {
this.results = response.data;
});
}
}
}
}
</script>
search.blade.php
<your-component></your-component>
Add the name of your data in your response
<script>
export default {
data(){
return {
kudos : []
}
},
created(){
axios.get('./api/kudos')
.then(response => this.kudos = response.data.NameOfYourData);
}
}
</script>

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.

Vue not rendering my data

I have a component that I get data on create with ajax and I show this in a Template. Basically I have this:
my Vue code:
Vue.component('feedback-table', {
template: '#grid-template',
data: function () {
return {
chancesOfApproval:[],
}
},
created:function(){
$.getJSON('/getFeedbackQuestionsAndChances',function(data){
this.chancesOfApproval = data.chancesOfApproval;
}.bind(this));
},
});
new Vue({
el: '#feedback-wrapper',
});
And here is my template:
<template id="grid-template">
<table class="table table-bordered table-responsive table-striped">
<tr v-for="entry in chancesOfApproval">
<td>#{{ entry.position }}</td>
</tr>
</table>
</template>
<div id="feedback-wrapper">
<feedback-table></feedback-table>
</div>
The data is being getted from the jquery because if I do console.log(this.chanceOfApproval) for example, it appears fine in the console. And I do not get any error in my console, so I have no idea why it does not work.
It behaves as expected here, where I've switched out the getJSON for a setTimeout doing the same assignment.
Vue.component('feedback-table', {
template: '#grid-template',
data: function() {
return {
chancesOfApproval: [],
}
},
created: function() {
/*
$.getJSON('/getFeedbackQuestionsAndChances', function(data) {
this.chancesOfApproval = data.chancesOfApproval;
}.bind(this));
*/
setTimeout(() => {
this.chancesOfApproval = [{
position: 1
}, {
position: 2
}];
}, 500);
},
});
new Vue({
el: '#feedback-wrapper',
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<template id="grid-template">
<table class="table table-bordered table-responsive table-striped">
<tr v-for="entry in chancesOfApproval">
<td>#{{ entry.position }}</td>
</tr>
</table>
</template>
<div id="feedback-wrapper">
<feedback-table></feedback-table>
</div>
You are using function.bind(this) to bring this from outer scope to the function scope, in your $http success handler.
Have you checked if it is not creating any issues? I am not aware of how bind is implemented. Maybe it is not allowing Vue to trigger its Reactivity System.
If you see values in console as a plain JSON object, then it is probably wrong. Vue.js modifies object params to getters / setters / observers so that it can bind to the DOM.
Alternatively, why dont you try the arrow function or using a self variable, just to see if it solves the issue?
Arrow function (ES6 and above):
created:function(){
$.getJSON('/getFeedbackQuestionsAndChances',data => {
this.chancesOfApproval = data.chancesOfApproval;
});
}
Or use a local variable:
created:function(){
var self = this; // self points to this of Vue component
$.getJSON('/getFeedbackQuestionsAndChances',function(data){
self.chancesOfApproval = data.chancesOfApproval;
});
}
Another note: instead of setTimeout(), you also have the option of Vue.nextTick() as follows:
Vue.nextTick(function () {
// DOM updated
})
or in your case:
this.$nextTick(function () {
// DOM updated
})

Resources