How to get Laravel api resource based data in Vue - laravel

I'm trying to show user projects list where user_id column is match with auth()->user()->id.
the problem i have is how to define what function of my resourced route to use.
Code
Controller
class ProjectController extends Controller
{
public function index()
{
$projects = Project::orderby('id', 'desc')->latest()->take(10)->get();
return response()->json($projects);
}
public function userprojects()
{
$projects = Project::orderby('id', 'desc')->where('user_id', '=', Auth::user()->id)->get();
return $projects;
}
}
Api route
Route::resource('projects', 'Api\ProjectController', ['except' => ['create', 'edit', 'destroy']]);
Vue component
<template>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Your Published Projects <span class="badge badge-info">{{projects.length}}</span></div>
<div class="card-body">
<ul>
<li v-for="project in projects" :key="project.id">
{{project.title}} - {{project.user_id}}
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
projects: []
}
},
created(){
this.fetchProjects();
},
methods:{
fetchProjects(){
var self = this;
axios.get('api/projects')
.then(function (resp) {
self.projects = resp.data;
})
.catch(function (resp) {
console.log(resp);
alert("Could not load projects");
});
},
},
}
</script>
Question
How do I tell my component to not load index function but to load
data from userprojects function?

So you could add a new route
Route::get('projects-user', 'Api\ProjectController#userprojects')->name('userprojects');
In js.
axios.get(Router('userprojects').url()).then(response => {
this.userprojects= response.data;
});
Also you could do just this in the controller
class ProjectController extends Controller
{
public function index()
{
if(Auth::check()){
$projects = Project::orderby('id', 'desc')->where('user_id', '=', Auth::user()->id)->get();
}else{
$projects = Project::orderby('id', 'desc')->latest()->take(10)->get();
}
return response()->json($projects);
}
}

You can create a new route before the resource route and use it:
Route::get('projects/me', 'Api\ProjectController#userprojects', ['except' => ['create', 'edit', 'destroy']]);
Route::resource('projects', 'Api\ProjectController', ['except' => ['create', 'edit', 'destroy']]);
then on your component:
axios.get('api/projects/me')
.then(function (resp) {
self.projects = resp.data;
})

Related

Sending messages to a specific user with Laravel-Websockets (One to One chat)

I have a websocket group chat in my app which broadcasts user's message to all the other users. I want to make a one on one chat also which will broadcast messages to two sides only. How can I tell the websocket to broadcast the message to a specific user?
My Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Message;
use App\Events\MessageSent;
use Auth;
class ChatsController extends Controller
{
public function index()
{
if (Auth::check() === false) {
return view('login');
}
else
{
return view('chats');
}
}
public function fetchMessages()
{
return Message::with('user')->get();
}
public function sendMessage(Request $request)
{
$message = auth()->user()->messages()->create([
'message' => $request->message
]);
broadcast(new MessageSent($message->load('user')))->toOthers();
return ['status' => 'success'];
}
}
My Vue file:
<template>
<div class="row">
<div class="col-8">
<div class="card card-default">
<div class="card-header">Messages</div>
<div class="card-body p-0">
<ul class="list-unstyled" style="height:300px; overflow-y:scroll" v-chat-scroll>
<li class="p-2" v-for="(message, index) in messages" :key="index" >
<div style="background: #009afb; padding: 8px; color: white; border-radius: 15px;">
<img v-if="message.user.image == 'img'" src="https://www.stickpng.com/assets/images/585e4bf3cb11b227491c339a.png" style="width: 35px; height: 35px;">
<img v-else v-bind:src="'../images/' + message.user.image"
style="width: 35px; height: 35px;border-radius: 50%;">
<strong>{{ message.user.name }} {{ message.user.surname }} :</strong>
{{ message.message }}
<p style="color:lightgray;">
{{ message.created_at }}
</p>
</div>
</li>
</ul>
</div>
<input
#keydown="sendTypingEvent"
#keyup.enter="sendMessage"
v-model="newMessage"
type="text"
name="message"
placeholder="Enter your message..."
class="form-control">
</div>
<span class="text-muted" v-if="activeUser" >{{ activeUser.name }} is typing...</span>
</div>
<div class="col-4">
<div class="card card-default">
<div class="card-header">Active Users</div>
<div class="card-body">
<ul>
<li class="py-2" v-for="(user, index) in users" :key="index">
{{ user.name }}
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props:['user'],
data() {
return {
messages: [],
newMessage: '',
users:[],
activeUser: false,
typingTimer: false,
}
},
created() {
this.fetchMessages();
Echo.join('chat')
.here(user => {
this.users = user;
})
.joining(user => {
this.users.push(user);
})
.leaving(user => {
this.users = this.users.filter(u => u.id != user.id);
})
.listen('MessageSent',(event) => {
this.messages.push(event.message);
})
.listenForWhisper('typing', user => {
this.activeUser = user;
if(this.typingTimer) {
clearTimeout(this.typingTimer);
}
this.typingTimer = setTimeout(() => {
this.activeUser = false;
}, 3000);
})
},
methods: {
fetchMessages() {
axios.get('messages').then(response => {
this.messages = response.data;
})
},
sendMessage() {
this.messages.push({
user: this.user,
message: this.newMessage
});
axios.post('messages', {message: this.newMessage});
this.newMessage = '';
},
sendTypingEvent() {
Echo.join('chat')
.whisper('typing', this.user);
}
}
}
</script>
My table has fields of id,user_id and message.
Hello I have the same problem and fixed it like this
But Notice that I have the extra logic for it
1- in channels.php
Broadcast::channel('chat.{ticketId}', function ($user, $ticketId) {
$ticket = \App\Models\Ticket::find($ticketId);
return $user->id == $ticket->asked_user_id || $user->id == $ticket->responded_user_id;
});
2- I just allow users to chat with each other that one of them is asked the support ticket or the admin that responded the user
and in my event I have this code
class MessageSentEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $ticket;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(TicketMEssage $message, Ticket $ticket)
{
$this->message = $message;
$this->ticket = $ticket;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('chat.' . $this->ticket->id);
}
public function toBroadcast()
{
return new MessageSentEvent($this->message);
}
}
3- I get message and the ticket like this
$ticket = Ticket::find($id);
$messages = $ticket->messages;
$messages->load('user');
return response()->json([
'messages' => $messages,
'ticket' => $ticket,
'user' => auth()->user()
]);
4- and I store and broadcast Message like below
$ticket = Ticket::find($request->ticket_id);
$message = $ticket->messages()->create([
'message' => $request->message,
'for' => auth()->id() == $ticket->asked_user_id ? TicketMessage::FOR_USER['asked'] : TicketMessage::FOR_USER['responded'],
'user_id' => auth()->id(),
]);
$message->load('user');
broadcast(new MessageSentEvent($message, $ticket));
return ['status' => 'success', 'message' => $message];
5- and the important part in js file (React Or Vue Or ...)
window.Echo.join(`chat.${props.ticketId}`)
.listen('MessageSentEvent', (message) => {
setMessages((prevState) => [...prevState, message.message]);
});
I listen just to channel that is with the ticket id that I get from props(you should pass it in any way)
and the key parts are 1 and 4 and 5
Hope This Help You :)))

how to insert data to database with vue and laravel

i trying to create a crud system using vue js and laravel.
i already create api route and more...
but when i click submit i got message 405 (Method Not Allowed)
here my AddArtist.vue file
<form #submit.prevent="add">
<input type="text" class="form-control" v-model="artist.name" placeholder="Artist Name">
<button class="btn btn-success" type="submit">Save</button>
</form>
<script>
export default {
data: function () {
return {
errors: [],
image: '',
artist: {
name: '',
}
}
},
methods: {
add() {
axios.post('/api/artist/store-artist', this.$data.artist)
.then((response) => {
alert('Success add Artist')
console.log(response)
})
},
},
mounted() {
console.log('Add Artist Mounted.')
}
}
</script>
and my api.php route
Route::group(['middleware' => 'cors'], function(){
Route::post('addartist/store-artist', 'ArtistController#store');
});
and here my controller ArtistController.php
public function store(Request $request)
{
$input = $request->all();
dd($input);
}
and the last is my model Artist.php
class Artist extends Model
{
protected $table = 'artist';
protected $fillable = ['artist_name', 'date_birth', 'cover', 'gender'];
}
that is typo error:
change addartist/store-artist to artist/store-artist in route
Your api is :
Route::group(['middleware' => 'cors'], function(){
Route::post('addartist/store-artist', 'ArtistController#store');
});
and you are doing :
axios.post('/api/artist/store-artist', this.$data.artist)
.then((response) => {
alert('Success add Artist')
console.log(response)
})

Difficult to get associate table's record in Vuejs from Laravel collection

I'm using Vuejs and Laravel building a live feed app, but i found that it is difficult to get associate data from collection in Vuejs, is there anyway to get those data easily?
Here is my attempt:
<div class="sl-item" v-for="post, index in posts">
<a href="javascript:void(0)">
<div class="sl-content">
{{post}}
<br>
------------------------
<br>
{{getUser(post.user_id)}}
</div>
</a>
</div>
Here is my methods that i intend to retrieve user record:
methods: {
getUser (id)
{
return axios.get("/user/getUser/" + id)
.then(response => {
console.log(response.data);
return response.data;
});
}
},
But this is what i got:
I can log what i get in console, but i can't display or access the thing i return from my method.
Is there any other easier way to achieve this?
You fetching all the data from collection. that's why you also getting unwanted data in your object
in your current situation (without changing in your controller script) you can access those data as like:
public function index(Request $request)
{
if ($request->ajax()) {
return Post::with(['user' => function($query){
$query->select(['id', 'name'])
}])
->select(['id', 'title', 'description'])
->get;
}
}
if you do this in your controller, then in your vue file,
data:function(){
return{
posts: [],
};
},
methods: {
getPosts ()
{
return axios.get("/posts")
.then(response => {
this.posts = response.data;
});
}
},
and in component:
<div class="sl-item" v-for="post, index in posts">
<a href="javascript:void(0)">
<div class="sl-content">
{{post.title}}
<br>
------------------------
<br>
{{ post.user.name }}
</div>
</a>
</div>

Multiselect with Vue and Laravel

I need to implement a multiselect in the view in which I am working, the idea is to have several options selected in the same select. I have tried some components that I found on the web but without good results.
The route and the driver method in Laravel work well.
I have to feed the Multiselect from a method that brings the data
If you can give me a hand it would be great, I leave the code
<template>
<div>
<div class="col-sm-12">
<select class="form-control form-control-line">
<option v-for="coin in coins" :key="coin.id" value="coin.id">
{{ coin.name }}
</option>
</select>
</div>
</template>
<script>
export default {
data () {
coins: [],
},
created() {
this.getCoins();
},
methods: {
getCoins(){
let urlCoin = '/dashboard/coins';
axios.get(urlCoin)
.then((response) => {
this.coins = response.data;
})
.catch((err) => {
})
}
}
My Method in the CoinController
class CoinController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function coinList() {
$coins = Coin::orderBy('rank', 'asc')
->select('id', 'name', 'rank')
->get();
return response()->json($coins);
}
}
the idea is to do this
Multiselect
I used Laravel 5.6 and Vuejs
You can't use basic select tag to show multiple selected value that you get from server.. because it only support to select one option.. if you want to select multiple like your pict, you have to add more library like vue multiselect
<multiselect v-model="value",
:options="coins",
:multiple="true",
:close-on-select="false",
:clear-on-select="false",
:hide-selected="true",
:preserve-search="true",
placeholder="Pick some"
label="name",
track-by="name",
:preselect-first="true" >
<template slot="tag" slot-scope="props">
<span class="custom__tag">
<span>{{ props.option.language }}</span>
<span class="custom__remove"
#click="props.remove(props.option)">
x
</span>
</span>
</template>
</multiselect>
<script>
export default {
data () {
value: [],
coins: [],
},
created() {
this.getCoins();
},
methods: {
getCoins(){
let urlCoin = '/dashboard/coins';
axios.get(urlCoin)
.then((response) => {
this.coins = response.data;
})
.catch((err) => {
})
}
}

Datatable service Yajra show blank

i want to add button in Yajra, so i read http://dt54.yajrabox.com/buttons/eloquent.
Im following the step. But still show blank.
nb. if im not using datatable service running well.
Datatables class
namespace App\DataTables;
use App\employee;
use Yajra\Datatables\Services\DataTable;
class EmployeeDataTable extends DataTable
{
public function ajax()
{
return $this->datatables
->eloquent($this->query())
->make(true);
}
public function query()
{
$query = employee::select();
return $this->applyScopes($query);
}
public function html()
{
return $this->builder()
->columns($this->getColumns())
->ajax('{{ url("Employee/index3") }}')
->parameters([
'dom' => 'Bfrtip',
'buttons' => ['export', 'print', 'reset', 'reload'],
]);
}
protected function filename()
{
return 'employeedatatables_' . time();
}
in Controller
use Yajra\Datatables\Facades\Datatables;
use App\DataTables\EmployeeDataTable;
public function index3(EmployeeDataTable $dataTable)
{
return $dataTable->render('employee.users');
}
in View
#extends('layouts.app')
#section('content')
<div class="col-md-8 col-md-offset-2">
<h3>test</h3>
{!! $dataTable->table() !!}
</div>
{!! $dataTable->scripts() !!}
#endsection
If i used firebug, i've got error 304 not modified.
Can you tell me what my mistake,pls ?
Solved.. maybe can help somebody..
this is Column search,and add action using Datatabale service
in Datatables class
public function ajax()
{
return $this->datatables
->eloquent($this->query())
->addColumn('action', function ($query) {
return '<i class="glyphicon glyphicon-edit"></i> Edit
<i class="glyphicon glyphicon-minus-sign"></i> Del';
})
->make(true);
}
public function query()
{
$query = employee::select('ID','cNip','vName','vBankbranch');
return $this->applyScopes($query);
}
public function html()
{
return $this->builder()
->columns($this->getColumns())
->addAction(['width' => '10%'])
->ajax('')
->parameters([
'dom' => 'Bfrtip',
'buttons' => ['export', 'print', 'reset', 'reload'],
'initComplete' => "function () {
this.api().columns().every(function () {
var column = this;
var input = document.createElement(\"input\");
$(input).appendTo($(column.footer()).empty())
.on('change', function () {
column.search($(this).val(), false, false, true).draw();
});
});
}",
]);
}
in View
#extends('layouts.app')
#section('content')
<div class="col-md-8 col-md-offset-2">
<h3>test</h3>
{!! $dataTable->table([], true) !!}
</div>
#endsection
#section('scripts')
{!! $dataTable->scripts() !!}
#endsection

Resources