Laravel ReactJS Post Method Not Allowed - laravel

I know there are lots of solution for this kind of problem that I'm having. But I think I have almost tried most of them and none works.
My experience with PHP Laravel is quite good but not with front-end libraries or framework such as VueJS or ReactJS. I am planning to expand my knowledge with front-end part with ReactJS.
I have created a sample project that is food ordering system. These are the tables:-
User migration table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
Food migration table
public function up()
{
Schema::create('foods', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('description')->default('');
$table->boolean('in_stock')->default(1);
$table->timestamps();
});
}
Food_user migration table
public function up()
{
Schema::create('food_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('quantity');
$table->boolean('is_served')->default(0);
$table->timestamps();
});
}
My routes and related controller:-
web.php
<?php
Route::get('/', function () {
return view('welcome');
});
Route::resource('food', 'FoodController');
Route::get('/allfood', 'FoodController#index');
Route::post('/addfood', 'FoodController#create');
// Route::group(['middleware' => 'cors'], function($router){
// Route::post('/addfood', 'FoodController#create');
// });
FoodController
<?php
namespace App\Http\Controllers;
use App\Food;
use Illuminate\Http\Request;
class FoodController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return response()->json(Food::all());
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
$newfood = Food::create([
'name' => request('foodname'),
'description' => request('fooddesc'),
'in_stock' => 1,
]);
return response()->json(Food::all());
}
}
I can display the seeded data well with axios
Main.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Food from './Food';
export default class Main extends Component {
constructor() {
super();
this.state = {
foods: [],
currentPage: 1,
}
}
componentDidMount() {
axios({
method: 'get',
url: 'http://localhost:8000/allfood'
})
.then(response => {
this.setState({ foods: response.data });
});
}
renderFoods() {
return this.state.foods.map(foods => {
return (
<div className="col-md-8 col-md-offset-2" key={foods.id}>
<div className="panel panel-default">
<div className="panel-heading">{ foods.name }</div>
<div className="panel-body">
{ foods.description }
</div>
</div>
</div>
);
})
}
changePage(pagenum) {
this.setState({currentPage:pagenum});
}
render() {
switch(this.state.currentPage) {
case 1:
return (
<div className="container-fluid" style={{marginTop: 50 + 'px'}}>
<div className="top-right links">
<a href="#" onClick={() =>this.changePage(2)}>Add Food</a>
<a href="#" onClick={() =>this.changePage(1)}>Order Food</a>
</div>
<div className="row text-center">
<h2>List of Menu</h2>
</div>
<div className="row">
{ this.renderFoods() }
</div>
</div>
);
break;
case 2:
return (
<div>
<div className="container-fluid" style={{marginTop: 50 + 'px'}}>
<div className="top-right links">
<a href="#" onClick={() =>this.changePage(2)}>Add Food</a>
<a href="#" onClick={() =>this.changePage(1)}>Order Food</a>
</div>
</div>
<Food/>
</div>
);
break; }
}
}
if (document.getElementById('main')) {
ReactDOM.render(<Main />, document.getElementById('main'));
}
But to add a new record (new food). Here I am stuck.
Food.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
export default class Food extends Component {
constructor() {
super();
this.state = {
newFood: {
name: '',
description: '',
instock: 0
},
foods: []
}
}
submitMenu () {
var foody = this.state.newFood;
console.log(foody);
var testpost = axios({
method: 'post',
url: 'http://localhost:8000/addfood',
data: {
name: foody.name,
description: foody.description,
in_stock: foody.instock
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
console.log(testpost);
}
handleInput(key, e) {
var state = Object.assign({}, this.state.newFood);
state[key] = e.target.value;
this.setState({newFood: state });
}
render() {
return (
<div className="container-fluid" style={{marginTop: 50 + 'px'}}>
<div className="row text-center">
<h2>Add Menu</h2>
</div>
<div className="row">
<div className="col-md-8 col-md-offset-2">
<div className="panel panel-default">
<div className="panel-body">
<form onSubmit={this.submitMenu.bind(this)} method="POST">
<div className="form-group">
<label>Food Name</label>
<input type="text" className="form-control" placeholder="Food Name" name="foodname" onChange={(e)=>this.handleInput('name',e)}/>
</div>
<div className="form-group">
<label>Food Description</label>
<textarea className="form-control" name="fooddesc" onChange={(e)=>this.handleInput('description',e)}></textarea>
</div>
<div className="checkbox">
<label>
<input type="checkbox" name="instock" value="1"/> In Stock?
</label>
</div>
<button type="submit" className="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
When I type new information in the form and submit. Laravel throws error:-
Symfony \ Component \ HttpKernel \ Exception \
MethodNotAllowedHttpException
No message
And when I check the browser's console log, here what I see:-
> Object { name: "Deep Fried Chicken", description: "Dipped with chill sauce", instock: 0 }
> Promise { <state>: "pending" }
So what is the problem here? I have tried:-
Install and configure Laravel Cors to bypass CSRF.
Create a specific Laravel Cors middleware group.
Change method from POST to GET.
Remove (comment) \App\Http\Middleware\VerifyCsrfToken::class from
kernel.php.
Try hardcoding data at axios.
I suspect my usage of axios post method is not right. Still, I just follow the documentation.
This is my first experience on full javascript front-end development. And my knowledge of javascript is very very little. I hope my question here is proper and fully explained.....

ur code is right, u just need to inform ur create method that has Request as param to get all data sent from ur axios code.
ur create would be like this and u need to return http success status code to ur client side code (201) :
for more information about http code read this article : link
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create(Request $request)
{
$newfood = Food::create([
'name' => $request->get('foodname'),
'description' => $request->get('fooddesc'),
'in_stock' => 1,
]);
//return response()->json(Food::all()); /* u don't need to return data here */
return response()->json([],201);
}

Related

How to change the role in migration table either admin or user based on the selection in laravel-8?

I developed one users table without role column , now i want to add role column in my migration table which contains either admin or user , if the registered person selects user radio btn in frontend UI page the role should be updated as user or if the person selects admin the role should be changed as admin in my migration table [in postman also how to pass role based on role the value should change in my database table] please help me to fix this issue
UsersMigration table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('fullName');
$table->string('email')->unique();
$table->string('mobile')->unique();
$table->string('email_verified_at')->nullable();
$table->string('password');
$table->enum('role', ['user', 'admin'])->default('user'); //here
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
UserRegisterController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class UserController extends Controller
{
// AWS_USE_PATH_STYLE_ENDPOINT=false
public function __construct() {
$this->middleware('auth:api', ['except' => ['login', 'register']]);
}
public function register(Request $request)
{
$this->validate($request, [
'fullName'=>'required|string|between:3,15',
'email'=>'required|email|unique:users',
'password'=>'required|regex:/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!#$%^&*-]).{6,}$/',
'mobile'=>'required|digits:10'
]);
$user = new User([
'fullName'=> $request->input('fullName'),
'email'=> $request->input('email'),
'password'=> bcrypt($request->input('password')),
'mobile'=>$request->input('mobile')
]);
$user->save();
return response()->json(['message'=>'Successfully Created user'],201);
}
}
i am pasting my frontend UI page also which should be written in vue.js
Register.vue
<template>
<div class="main">
<div v-if="flag==true" class="container">
<img id="side-img" src="../assets/sideImg.png" alt="notFound" />
<p id="side-content">Online Book Shopping</p>
<div class="box">
<div class="headings">
<h5 class="signin" v-on:click="flip();" id="login" :class="{ active: isLogin }" #click="isLogin = true">Login</h5>
<h5 class="signup" id="signup" :class="{ active: !isLogin }" #click="isLogin = false">signup</h5>
</div>
<form ref="myForm" #submit.prevent="handlesubmit">
<div class="fullname">
<p>FullName</p>
<input type="name" id="name-input" class="namebox" required v-model="fullName" autocomplete="off" pattern="[A-Za-z]{3,12}">
</div>
<div class="username">
<p>EmailID</p>
<input type="email" id="Email-input" class="emailbox" autocomplete="off" required v-model="email" pattern="^[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}$">
</div>
<div class="password-section">
<p>Password</p>
<input :type="password_type" class="password" :class="{'password-visible': isPasswordVisible }" id="passField" v-model="password" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$!%*?&])[A-Za-z\d#$!%*?&]{6,}$" required>
<i class="bi bi-eye-slash" id="togglePassword" #click="togglePassword();"></i>
</div>
<div class="mobile">
<p>MobileNumber</p>
<input type="tel" class="telephone" autocomplete="off" v-model="mobile" id="tel" pattern="^\d{10}$" required>
</div>
<div class="role-btns">
<input type="radio" id="user" name="user" vlaue="user" >
<label for="user" class="radio-label">User</label>
<input type="radio" id="admin" name="user" value="admin">
<label for="admin">Admin</label>
</div>
<button class="btn-section" id="btn" type="submit">Signup</button>
</form>
</div>
</div>
<Login v-if="flag==false" />
</div>
</template>
<script>
import service from '../service/User'
export default {
name: 'Register',
components: {
Login: () => import('./Login.vue')
},
data() {
return {
fullName: '',
email: '',
password: '',
mobile: '',
password_type: "password",
isLogin: false,
isPasswordVisible: false,
flag: true,
title: 'Online Book Shopping'
}
},
methods: {
flip() {
this.flag = !this.flag;
},
togglePassword() {
this.password_type = this.password_type === 'password' ? 'text' : 'password'
this.isPasswordVisible = !this.isPasswordVisible
},
handlesubmit() {
let userData = {
fullName: this.fullName,
email: this.email,
password: this.password,
mobile: this.mobile
}
service.userRegister(userData).then(response => {
if (response.status == 201) {
alert("user registered successfully");
this.$refs.myForm.reset();
this.$router.push('/login');
}
return response;
}).catch(error => {
alert("invalid credentials");
return error;
})
}
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/Register.scss";
</style>
Change radio name
<div class="role-btns">
<input type="radio" id="user" name="role" vlaue="user" >
<label for="user" class="radio-label">User</label>
<input type="radio" id="admin" name="role" value="admin">
<label for="admin">Admin</label>
</div>
and in controller
$this->validate($request, [
'fullName'=>'required|string|between:3,15',
'email'=>'required|email|unique:users',
'password'=>'required|regex:/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!#$%^&*-]).{6,}$/',
'mobile'=>'required|digits:10',
'role'=>'required|in:user,admin'
]);
$user = new User([
'fullName'=> $request->input('fullName'),
'email'=> $request->input('email'),
'password'=> bcrypt($request->input('password')),
'mobile'=>$request->input('mobile') ,
'role'=>$request->role ,
]);
$user->save();

Yajra DataTables service implementation upgrade from Laravel 5 to Laravel 6

We have been using Yajra DataTables with Laravel 5 for a few years and have built up a library of over 50 of them, basically for the index page of a BREAD UI. It's finally time to upgrade, and We're using the service implementation, which looks like this.
The current code is working against
"yajra/laravel-datatables-oracle": "^6.0",
Here is the Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\DataTables\WidgetDataTable;
use App\Models\Widget;
use Illuminate\Support\Facades\Auth;
use App\Models\Widgetaccount;
use App\Events\Widgetcrud;
use App\DataTables\WidgetHistoryDataTable;
use Illuminate\Support\Facades\DB;
class WidgetController extends Controller
{
/**
* Create a new controller instance
*
* #return void
*/
public function __construct()
{
$this->middleware('permission:widget_view', ['only' => ['index', 'history']]);
$this->middleware('permission:widget_create', ['only' => ['create','store']]);
$this->middleware('permission:widget_edit', ['only' => ['edit','update']]);
$this->middleware('permission:widget_delete', ['only' => ['destroy']]);
}
/**
* Display a listing of the resource.
*
* #param object $dataTable
* #return \Illuminate\Http\Response
*/
public function index(WidgetDataTable $dataTable)
{
return $dataTable->render('widget.index', [
'title' => 'Manage Widgets',
]);
}
// other methods here
}
Here is the DataTables class:
<?php
namespace App\DataTables;
use Illuminate\Support\Facades\DB;
use Yajra\DataTables\Services\DataTable;
use Illuminate\Support\Facades\Auth;
class widgetDataTable extends DataTable
{
/**
* Display ajax rwidgetonse.
*
* #return \Illuminate\Http\JsonResponse
*/
public function ajax()
{
return $this->datatables
->queryBuilder($this->query())
->editColumn(
'edit accounts',
function ($widget) {
return '<a href="' . route('widgetaccounts.index', 'widgetid=' . $widget->id)
. '" class="btn btn-xs btn-primary"><i class="glyphicon glyphicon-edit"></i> </a>';
}
)
->editColumn(
'documentation',
function ($widget) {
if ($widget->documentation != null) {
return '<a href="javascript:void(0)" data-value="' . $widget->documentation .
'" class="btn btn-xs btn-primary opendocument">View</a>';
} else {
return '';
}
}
)
->addColumn(
'action',
function ($widget) {
return '<a href="' . route('widgets.edit', $widget->id) .
'" class="btn btn-xs btn-primary" dusk="widget-edit-button-'.$widget->id .'"><i class="glyphicon glyphicon-edit"></i> Edit</a>
<a href="javascript:void(0)" data-remote="' . route('widgets.destroy', $widget->id) .
'" class="btn btn-xs btn-danger btn-delete" dusk="widget-delete-button-'.$widget->id .'"><i class="glyphicon glyphicon-trash"></i>Delete</a>';
}
)
->make(true);
}
/**
* Get the query object to be processed by dataTables.
*
* #return \Illuminate\Database\Eloquent\Builder|
*/
public function query()
{
$widget_id = null;
if ($this->request()->has("widgetid")) {
$widget_id = $this->request()->get("widgetid");
}
$query = DB::connection('dashboard')
->table('widgets')
->join('users', 'users.id', '=', 'widgets.user_id')
->whereNull('widgets.deleted_at')
->when($widget_id,
function ($queryvar, $widget_id) {
return $queryvar->where('widgets.id', $widget_id);
})
->select(
'widgets.id',
'widgets.name',
'widgets.active',
'users.name as username',
'widgets.documentation',
'widgets.created_at',
'widgets.updated_at',
'widgets.deleted_at'
);
return $this->applyScopes($query);
}
/**
* Optional method if you want to use html builder.
*
* #return \Yajra\Datatables\Html\Builder
*/
public function html()
{
if (Auth::user()->can('distribution_manage_widget_lists_edit')) {
return $this->builder()
->columns($this->getColumns())
->ajax('')
->addAction(['width' => '80px'])
->parameters([
'dom' => 'lBfrtip',
'buttons' => ['csv', 'excel'],
'pageLength' => 50
]);
}else{
return $this->builder()
->columns($this->getColumns())
->ajax('')
->parameters([
'dom' => 'lBfrtip',
'buttons' => ['csv', 'excel'],
'pageLength' => 50
]);
}
}
/**
* Get columns.
*
* #return array
*/
protected function getColumns()
{
return [
'id',
'name',
'active',
'documentation' => ['searchable' => false, 'orderable' => false],
'edit accounts' => ['searchable' => false, 'orderable' => false],
'last edited by' => ['name' => 'users.name', 'data' => 'username'],
'created_at',
'updated_at',
];
}
/**
* Get filename for export.
*
* #return string
*/
protected function filename()
{
return 'widgetdatatables_'.time();
}
}
Here is the view:
#extends('layouts.main')
#section('content')
#include('partials.panel-open', [ 'title' => "Manage widgets" ])
<form action="{{route('widgetsearch')}}" method="POST">
{{ csrf_field() }}
<div class="search_button_group">
<div class="row">
<div class="col-sm-4 col-sm-offset-2">
<label>Search for widget-related Settings: </label>
</div>
<div class="col-sm-6">
<div class="input-group">
<input type="text" class="form-control" placeholder="" name="search" aria-describedby="basic-addon1" required="required">
<button class="input-group-addon btn btn-primary" id="basic-addon1" type="submit">Go</button>
</div>
</div>
</div>
</div>
</form>
<div class="row form-group">
<div class="col-sm-6">
#permission(('widget_create'))
Add New widget
#endpermission
</div>
<div class="col-sm-6">
<div class="text-right">
widget History
</div>
</div>
</div>
{!! $dataTable->table(['class' => 'table table-bordered','id' =>'widget-table']) !!}
#permission(('widget_create'))
Add New widget
#endpermission
#include('partials.panel-close')
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Documentation</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
#endsection
#push('scripts')
<script src="/vendor/datatables/buttons.server-side.js"></script>
{!! $dataTable->scripts() !!}
<script type="text/javascript">
$('#widget-table').on('click', '.btn-delete[data-remote]', function (e) {
e.preventDefault();
if (confirm("Are you sure you want to delete"))
{
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
var url = $(this).data('remote');
$.ajax({
url: url,
type: 'DELETE',
dataType: 'json',
data: {method: '_DELETE', submit: true}
})
.always(function (data) {
var count = data.count;
if (count == 0) {
$('#widget-table').DataTable().draw(false);
} else {
alert("widget can't be deleted as there are associated widget Account/s (#" + count + ") under the same. Kindly remove the widget Account/s first.");
}
});
}
});
$(document).on("click",".opendocument",function(){
$(".modal-body").html($(this).data('value'));
$('#myModal').modal('show');
});
</script>
#endpush
Now I've updated composer and am trying to use:
"yajra/laravel-datatables-oracle": "^9.0",
"yajra/laravel-datatables-buttons": "^4.0",
And when I view the widget index, I get the ajax error dialog
DataTables warning: table id=widget-table -
Ajax error. For more information about this error,
please see http://datatables.net/tn/7
When I look in the Laravel.log:
[2020-07-24 10:30:55] local.ERROR: Call to a member function queryBuilder() on null
{"userId":19,"exception":"[object]
(Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Call to a member function queryBuilder() on null at /Projects/my-app/app/DataTables/WidgetDataTable.php:20)
[stacktrace]
#0 [internal function]: App\\DataTables\\WidgetDataTable->ajax()
So, it seems that on this line:
return $this->datatables
->queryBuilder(...
the datatables property is not set. So, I am stuck as to how to proceed, and have broken my entire application. Looking for advice on what to try or a guide on how to upgrade the Yajra service implementation without having to modify hundreds of files.
It's been a while, but as I myself was stuck at this point in the process of upgrading, I thought I would share the solution as the documentation lacks a bit of detail.
I only got to understand what to change after finding and comparing this example sheet in the documentation:
https://yajrabox.com/docs/laravel-datatables/master/quick-starter
Further changes are then introduced in yajra's upgrade guide:
https://yajrabox.com/docs/laravel-datatables/8.0/upgrade
Changes to the DataTables class:
1.
/**
* Display ajax rwidgetonse.
*
* #return \Illuminate\Http\JsonResponse
*/
public function ajax()
{
return $this->datatables
->queryBuilder($this->query())
becomes:
use Yajra\DataTables\DataTables;
public function dataTable(DataTables $dataTables, $query) {
return $dataTables->eloquent($query)
If you're ajax / datatables function contains the ->editColumn() api, remove the ->render(); at the end. Otherwise html will be parsed as string.
3.
private function getColumns()
{
...
}
becomes protected:
protected function getColumns()
{
...
}
Return Object of the html function is now CamelCased too:
* #return \Yajra\Datatables\Html\Builder
to
* #return \Yajra\DataTables\Html\Builder
the getColumns() function now returns Columns as Array of Columns:
return [
[
'name' => 'users.firstname',
'data' => 'firstname',
'title' => 'Vorname',
],
];
becomes:
return [
Column::computed('firstname')
->name('users.firstname')
->title('Vorname'),
];
For which you need to import:
use Yajra\DataTables\Html\Column;
Even though that's the new way, your way of returning columns should still work as well.
Actually that's all
Many things are possible with sublime's find and replace so it shouldn't be that costly.
I hope that helps someone else who is struggling with the update.
Cheers
Dominik

laravel event generate an error in real chat app

I am working on a demo for instant chat and I was able to display the number of logged in users and show their names in the "Online Users" list, but the problem is that I created a laravel event to show messages in real time, and here I get the following error message in my console: Error: Syntax error, unrecognized expression: #user=1 .
demo app details :
laravel : 5.8.*
php : ^7.1.3
redis & laravel echo & laravel echo serveur
view :
<div class="container">
<div class="row">
<div class="col-md-4">
<h2>Online Users</h2>
<hr>
<h5 id="no-online-users">No Online Users</h5>
<ul class="liste-group" id="online-users">
</ul>
</div>
</div>
<div class="row">
<div class="col-md-9 d-flex flex-column" style="height: 80vh">
<div class="h-100 bg-white mb-4 p-5" id="chat" style="overflow-y: scroll;">
#foreach($messages as $message)
#if(\Auth::user()->id == $message->user_id)
<div class="mt-4 w-50 text-white p-3 rounded float-right bg-primary">
#else
<div class="mt-4 w-50 text-black p-3 rounded float-left bg-warning">
#endif
<p>{{ $message->body }}</p>
</div>
<div class="clearfix"></div>
#endforeach
</div>
<form action="" class="d-flex">
<input type="text" id="chat-text" name="" data-url="{{ route('messages.store') }}" style="margin-right: 10px" class="col-md-9 d-flex flex-column">
<button class="btn btn-primary col-md-3">Send</button>
</form>
</div>
</div>
</div>
MessageController :
namespace App\Http\Controllers;
use App\Message;
use Illuminate\Http\Request;
class MessageController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
//index
public function index()
{
$messages = Message::all();
return view('messages.index',compact('messages'));
}
// store
public function store(Request $request)
{
//$message = auth()->user()->messages()->create($request->all());
//return $request->body;
$message = new Message();
$message->user_id = \Auth::user()->id;
$message->body = $request->body;
$message->save();
broadcast(new MessageDelivered($message))->toOthers();
}
}
the event MessageDelivered:
namespace App\Events;
use App\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MessageDelivered implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('chat-group');
}
}
app.js
require('./bootstrap');
import Echo from "laravel-echo"
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
// online users :
let onlineUsersLength = 0;
window.Echo.join('online')
.here((users) => {
onlineUsersLength = users.length;
console.log(onlineUsersLength);
let userId = $('meta[name=user-id]').attr('content');
//console.log(userId);
users.forEach(function(user){
if (user.id == userId) { return; }
$('#no-online-users').css('display','none');
$('#online-users').append('<li id="user='+user.id+'" class="liste-group-item">'+user.name+'</li>');
})
//console.log(users);
})
.joining((user) => {
$('#no-online-users').css('display','none');
$('#online-users').append('<li id="user='+user.id+'" class="liste-group-item">'+user.name+'</li>');
})
.leaving((user) => {
$('#user='+user.id).css('display','none');
$('#no-online-users').css('display','yes');
});
// submit chat text :
$('#chat-text').keypress(function(e){
//console.log(e.which);
if(e.which == 13){
e.preventDefault();
let body = $(this).val();
let url = $(this).data('url');
let data = {
'_token': $('meta[name=csrf-token]').attr('content'),
body
}
//console.log(body);
$.ajax({
url: url,
method: 'post',
data: data,
});
}
});
window.Echo.channel('chat-group')
.listen('MessageDelivered', (e) => {
console.log('message');
});
problem :
in first user console (user id 1 in database)
in second user console (user id 2 in database)
When I refresh the page for a specific user, the error appears for the second user
I guess you have a typo here $('#user='+user.id).css('display','none')
^^^
and here $('#online-users').append('li id="user='+user.id+'" class="liste-group-item">'+user.name+'</li>'); ^^^
You may fix it
//...
users.forEach(function(user){
if (user.id == userId) { return; }
$('#no-online-users').css('display','none');
$('#online-users').append('<li id="user-'+user.id+'" class="liste-group-item">'+user.name+'</li>');
})
//...
.joining((user) => {
$('#no-online-users').css('display','none');
$('#online-users').append('<li id="user='+user.id+'" class="liste-group-item">'+user.name+'</li>');
})
.leaving((user) => {
$('#user-'+user.id).css('display','none');
$('#no-online-users').css('display','yes');
});
//...

How to get Laravel api resource based data in Vue

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;
})

Laravel Echo isn't listening to the Broadcast event

I am trying to broadcast the event when a user creates a post to all his friends. Laravel Echo isn't listening to the events. I can see the logs on the Pusher site. So the event is being sent to the pusher.
Here's my timeline code:
<template>
<div>
<div class="row">
<status-box :authUser="authUser"></status-box>
</div>
<div class="row">
<div class="col-lg-8">
<div v-if="statuses.length">
<status v-for="status in statuses" :status="status"></status>
</div>
<div v-else>
<p>No posts to show yet.</p>
</div>
</div>
</div>
</div>
<script>
import EventHub from './../eventhub.js';
export default {
data() {
return {
statuses: [],
authUser: null,
};
},
methods: {
pushNewStatus(status) {
status.parent_id = null;
this.statuses.unshift(status);
// Broadcasting the event to so that user's friends can see the post in realtime
Echo.private('status.' + status.id)
.listen('StatusWasPosted', (e) => {
this.pushNewStatus(e.status);
});
}
},
mounted() {
EventHub.$on('status-posted', this.pushNewStatus)
axios.get('/chatty/getStatuses/')
.then(({data}) => {
this.statuses = data.statuses;
this.authUser = data.user_name;
})
.catch(error => console.log(error));
}
}
Here's the channel authorization logic:
Broadcast::channel('status.{statusId}', function ($user, $statusId) {
$status = Status::find($statusId);
$status_owner = User::find($status->user_id);
return $user->isFriendsWith($status_owner);
});
Here's the channel name in the StatusWasPosted event class
public function broadcastOn() {
return new PrivateChannel('status.' . $this->status->id);
}
I am emitting status-posted in the status compoenet when a new status is created.
Where am I going wrong??

Resources