notifications in Laravel 9 / Ajax - ajax

I have implemented a notification system in my app and it works fine, but when I want to use it in another controller that uses ajax, the notifications are not loaded in the database. Is there any limitation with Ajax to do this kind of notifications?
Suggestions?
index view:
#extends('layouts.app')
#section('content')
<section class="section">
<div class="section-header">
<h3 class="page__heading">Derivar IP</h3>
</div>
<div class="section-body">
<div class="row">
<div class="col-sm-9">
<div class="card">
<div class="card-header">
<h4>Siniestros para derivar</h4>
</div>
<div class="card-body">
<table class="table table-sm m-1 p-1 table-bordered table-hover table-striped tablita" style="width:100%">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Siniestro</th>
<th scope="col">Fecha IP</th>
<th scope="col">Modalidad</th>
<th scope="col">Dirección</th>
<th scope="col">Localidad</th>
<th scope="col">Inspector</th>
<th scope="col">Acciones</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-3" style="position:fixed; bottom:250px; right:0px">
<div class="card">
<div class="card-header">
<span id="addT">Asignar IP</span>
<span id="updateT">Asignar IP</span>
</div>
<div class="card-body">
<div class="col-xs-4 col-sm-4 col-md-4">
<div class="form-group">
<label for="siniestro">Siniestro</label>
<input type="text" name="siniestro" id="siniestro" class="form-control">
</div>
</div>
<div class="col-xs-4 col-sm-4 col-md-4">
<label for="inspector">inspector</label>
<select class="form-select col-xs-12 col-sm-12 col-md-12" aria-label="Default select example" id="inspector"´for="inspector" name="inspector"">
#foreach ($users as $user)
<option value="{{ $user->id }}">{{ $user->name }}</option>
#endforeach
</select>
</div>
<div class="col-xs-4 col-sm-4 col-md-4">
<div class="form-group">
<label for="patente">Patente</label>
<input type="text" name="patente" id="patente" class="form-control">
</div>
</div>
<div class="col-xs-4 col-sm-4 col-md-4">
<div class="form-group">
<label for="fechaip">Fecha IP</label>
<input type="date" name="fechaip" id="fechaip" class="form-control">
</div>
</div>
<input type="hidden" id="id">
<!-- <button type="button" href="#" data-target="#ModalEnviar" class="btn btn-primary m-2" data-toggle="modal">Enviar IP</button> -->
<button type="submit" id="updateButton" class="btn btn-primary btn-sm" onclick="updateData(event)">Update</button>
</div>
</div>
</div>
</div>
</div>
</section>
#endsection
<!-- DataTables JS -->
<script src="{{ asset('assets/js/jquery.min.js') }}"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/jszip-2.5.0/dt-1.11.5/b-2.2.2/b-colvis-2.2.2/b-html5-2.2.2/b-print-2.2.2/r-2.2.9/datatables.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js"></script>
<!-- searchPanes -->
<script src="https://cdn.datatables.net/searchpanes/1.0.1/js/dataTables.searchPanes.min.js"></script>
<!-- select -->
<script src="https://cdn.datatables.net/select/1.3.1/js/dataTables.select.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/js/all.min.js" integrity="sha512-6PM0qYu5KExuNcKt5bURAoT6KCThUmHRewN3zUFNaoI6Di7XJPTMoT6K0nsagZKk2OB4L7E3q1uQKHNHd4stIQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
#section('javas')
<script>
$('.tablita').DataTable({
"processing": "true",
"serverSide": "true",
"ajax": "{{route('datatable.paraderivar')}}",
"select": "true",
"columns":[
{data: 'id'},
{data: 'siniestro'},
{data: 'fechaip'},
{data: 'modalidad'},
{data: 'direccion'},
{data: 'localidad'},
{data: 'inspector'},
]
});
</script>
<script>
$('#addT').hide();
$('#addButton').hide();
$('#updateT').show();
$('#updateButton').show();
$.ajaxSetup({
headers:{
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
})
//---------------------------------------------- Llamar datos de la BD ---------------------------------------------------------------
function allData(){
$.ajax({
type: "GET",
dataType: "json",
url: "/teacher/all",
success: function (response){
var data = ""
$.each(response, function(key, value){
data = data + "<tr>"
data = data + "<td>"+value.id+"</td>"
data = data + "<td>"+value.siniestro+"</td>"
data = data + "<td>"+value.fechaip+"</td>"
data = data + "<td>"+value.modalidad+"</td>"
data = data + "<td>"+value.direccion+"</td>"
data = data + "<td>"+value.localidad+"</td>"
data = data + "<td>"+value.inspector+"</td>"
data = data + "<td>"
data = data + "<button class='btn btn-info btn-sm' onclick='editData("+value.id+")'>Asignar</button>"
data = data + "</td>"
data = data + "</tr>"
})
$('tbody').html(data);
}
})
}
// --------------------------------------------- fin de llamar datos de la DB ----------------------------------------------------------
allData();
// --------------------------------------------- Limpiar los campos despues del submit -------------------------------------------------
function clearData(){
$('#siniestro').val('');
$('#fechaip').val('');
$('#inspector').val('');
$('#nameError').text('');
$('#titleError').text('');
$('#instituteError').text('');
}
// --------------------------------------------- fin de limpiar los campos despues del submit -------------------------------------------------
// --------------------------------------------- Agregar registros a la table de BD -------------------------------------------------
function addData(){
var siniestro = $('#siniestro').val();
var fechaip = $('#fechaip').val();
var inspector = $('#inspector').val();
var fechaip = $('#fechaip').val();
var patente = $('#patente').val();
$.ajax({
type: "POST",
dataType: "Json",
data: {siniestro:siniestro, fechaip:fechaip, inspector:inspector, patente:patente},
url:"/teacher/store/",
success: function(data){
allData();
clearData();
console.log('datos agregados con éxito');
},
error: function(error){
$('#nameError').text(error.responseJSON.errors.name);
$('#titleError').text(error.responseJSON.errors.title);
$('#instituteError').text(error.responseJSON.errors.institute);
}
})
}
// --------------------------------------------- fin de agregar registros a la table de BD -------------------------------------------------
// --------------------------------------------- Editar registros a la table de BD ---------------------------------------------------------
function editData(id){
$.ajax({
type:"get",
dataType:"json",
url:"/teacher/edit/"+id,
success: function(data){
$('#addT').hide();
$('#addButton').hide();
$('#updateT').show();
$('#updateButton').show();
$('#id').val(data.id);
$('#siniestro').val(data.siniestro);
$('#fechaip').val(data.fechaip);
$('#inspector').val(data.inspector);
$('#patente').val(data.patente);
console.log(data);
}
})
}
// --------------------------------------------- Fin de editar registros a la table de BD -------------------------------------------------
// --------------------------------------------- Update de registros a la table de BD -----------------------------------------------------
function updateData(event){
event.preventDefault();
var id = $('#id').val();
var siniestro = $('#siniestro').val();
var fechaip = $('#fechaip').val();
var inspector = $('#inspector').val();
var patente = $('#patente').val();
$.ajaxSetup({
headers:{
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
})
$.ajax({
type: "PUT",
dataType: "json",
data: {inspector:inspector, siniestro:siniestro, fechaip:fechaip, patente:patente},
url: "/teacher/update/"+id,
success: function(response){
allData();
clearData();
console.log('Siniestro asignado con éxito');
}
})
}
</script>
#endsection
Controller:
<?php
namespace App\Http\Controllers;
use App\Models\Teacher;
use App\Models\Siniestro;
use App\Models\User;
//Notificaciones
use App\Notifications\DataEstadoNotificacion;
use App\Events\DataEstadoEvent;
use Illuminate\Support\Facades\Notification;
use Illuminate\Http\Request;
class TeacherController extends Controller
{
public function allUser(){
$data = User::orderBy('fechaip','DESC')->get();
dd($data);
return response()->json($data);
}
//-----------storeData------------
public function storeData(Request $request){
$request->validate([
]);
$data = Siniestro::insert($request->all()
);
return response()->json($data);
}
// public function editData($id){
// $data = Siniestro::findOrFail($id);
// return response()->json($data);
// }
public function updateData(Request $request, $id)
{
$data = Siniestro::findOrFail($id)->update($request->all();
// event(new DataEstadoEvent($data));
);
return response()->json($data);
auth()->user()->notify(new DataEstadoNotification($data));
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
}
}
Notification:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use App\Models\Siniestro;
use Carbon\Carbon;
class DataEstadoNotificacion extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(Data $data)
{
$this->data = $data;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
'siniestro' => $this->data->siniestro,
'patente' => $this->data->patente,
'fechaip' => $this->data->fechaip,
'tiempo' => Carbon::now()->diffForHumans(),
];
}
}
EventServiceProvider
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Events\SiniestroEstadoEvent;
use App\Listeners\SiniestroEstadoListener;
use App\Events\DataEstadoEvent;
use App\Listeners\DataEstadoListener;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
SiniestroEstadoEvent::class => [
SiniestroEstadoListener::class,
],
DataEstadoEvent::class => [
DataEstadoListener::class,
],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
//
}
/**
* Determine if events and listeners should be automatically discovered.
*
* #return bool
*/
public function shouldDiscoverEvents()
{
return false;
}
}
Listener:
<?php
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Notification;
use App\Models\User;
use App\Notifications\DataEstadoNotificacion;
class DataEstadoListener
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param object $event
* #return void
*/
public function handle($event)
{
$users = User::find($event->data->inspector);
Notification::send($users, new DataEstadoNotificacion($event->data));
}
}
Event:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class DataEstadoEvent
{
public $data;
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

Related

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');
});
//...

Export .xslx data using Laravel Excel with parameter

I want to export data from the database to .xlsx using Laravel-Excel.
I want to pass three parameters to query the data and download into excel file.
I already search and read a few examples but still failed to make the excel file to download.
This is my blade file.
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-3"></div>
<div class="col-md-6">
<div class="card">
<div class="card-header">Download Report</div>
<div class="card-body">
<div class="col-md-12" style="margin-bottom:15px">
<select class="form-control" name="plant" id="plant">
<option selected value="All">Please Select Plant</option>
#foreach($plants as $plant)
<option value="{{ $plant->id }}">{{ $plant->name }}</option>
#endforeach
</select>
</div>
<div class="col-md-12" style="">
<div class="input-group input-daterange" align="center">
<input type="text" name="from_date" id="from_date" readonly class="form-control" value="<?php echo date("Y-m-d");?>" />
<div class="input-group-addon" >To</div>
<input type="text" name="to_date" id="to_date" readonly class="form-control" value="<?php echo date("Y-m-d");?>"/>
</div>
</div>
<br>
<div class="col-md-12" align="center">
<button type="button" name="search" id="search" class="btn btn-info btn-block">Download</button>
</div>
</div>
</div>
</div>
<div class="col-md-3"></div>
</div>
</div>
<script type="text/javascript">
$(function() {
var date = new Date();
$('.input-daterange').datepicker({
todayBtn: 'linked',
format: 'yyyy-mm-dd',
autoclose: true
});
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('#search').click(function(e){
e.preventDefault();
var from_date = $('#from_date').val();
var to_date = $('#to_date').val();
var plant = $('#plant').val();
if(plant != 'All')
{
$.ajax({
url:"{{ route('export') }}",
data:{from_date:from_date, to_date:to_date, plant:plant},
dataType:"json",
})
}
else
{
alert('Please Select Plant');
}
});
});
</script>
#endsection
This is my function at the controller
public function export(Request $request)
{
return (new DetailReportDownload($request->plant,$request->from_date,$request->to_date))->download('Report Details.xlsx');
}
and This is my Export file
class DetailReportDownload implements FromQuery, WithHeadings
{
use Exportable;
protected $plant,$from,$to;
public function __construct(String $from,String $to,String $plant)
{
$this->plant = $plant;
$this->from = $from;
$this->to = $to;
}
public function headings(): array
{
return [
'plandate',
'workcentre',
'partno',
'prodduration',
'totaldowntime',
'planout',
'cumout',
];
}
public function query()
{
return DB::table('plannings')
->select(DB::raw('plandate, workcentre, partno, prodduration, coalesce(sum(downduration),0) as totaldowntime, planout, cumout'))
->join('prodstatuses', 'plannings.id', '=', 'prodstatuses.id')
->leftJoin('downtimes', 'plannings.id', '=', 'downtimes.plan_id')
->whereBetween('plandate', array($this->from, $this->to))
->where('plant_id',$this->plant)
->where('status','Finished')
->groupBy('plannings.id')
->orderBy('plannings.id');
}
}
I wanted to download excel file from parameter given in blade file.
Thanks in advance for any help
create a provider to add below code & register to app.php file
Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array $style) {
$sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});
And create class to download data using parameters,
<?php
namespace App\Modules\User\Http\Exports;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromView;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
/**
* Class ExportUsers
* #package App\Exports
*/
class ExportUsers implements FromView, ShouldAutoSize, WithEvents
{
protected $plannings;
/**
* ExportUsers constructor.
* #param Collection $plannings
*/
public function __construct(Collection $plannings) {
$this->plannings = $plannings;
}
/**
* #return View
*/
public function view() : View {
return view('plannings_list', [
'plannings' => $this->plannings,
]);
}
/**
* #return array
*/
public function registerEvents() : array {
return [
AfterSheet::class => function (AfterSheet $event) {
$this->createStyle($event, 'A1:N1', 9);
$event->sheet->styleCells(
'A1:N1',
[
'font' => [
'bold' => true,
]
]
);
},
];
}
/**
* #param $event
* #param $cell
* #param $size
* #throws \PhpOffice\PhpSpreadsheet\Exception
*/
private function createStyle($event, $cell, $size) {
/** #var AfterSheet $event */
$event->sheet->getDelegate()->getStyle($cell)->getFont()->setSize($size);
}
}
add this code to controller
private function downloadCsv($exportCsvList) {
return Excel::download(new ExportUsers($exportCsvList),
'students.xlsx');
}

trying to integrate ajax autocomplete in my create record in laravel

I found a ajax auto complete and I wan't it to integrate to my form but I can't make it work. Please advise thank you!
[controller]
<?php
namespace App\Http\Controllers;
use App\Purchasetransactions;
use App\AjaxAutocompleteController;
use App\Products;
use App\Categories;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
class PurchasetransactionsController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$purchasetransactions = Purchasetransactions::all();
return view('orders.index', compact('purchasetransactions'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('orders.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$purchasetransactions = Purchasetransactions::create($request->only('products_code','name'));
return redirect(route('orders.index'));
}
/** Auto Complete */
public function productSearch(Request $request){
$query = $request->get('term','');
$products=\DB::table('products');
if($request->type=='product_code'){
$products->where('product_code','LIKE','%'.$query.'%');
}
if($request->type=='product_name'){
$products->where('name','LIKE','%'.$query.'%');
}
$products=$products->get();
$data=array();
foreach ($products as $product) {
$data[]=array('product_code'=>$product->product_code,'name'=>$product->name);
}
if(count($data))
return $data;
else
return ['product_code'=>'','name'=>''];
}
}
[create.blade]
<div class="container">
{!! Form::open(array('route'=>'orders.store')) !!}
<table class="table table-bordered">
<tr>
<th><input class='check_all' type='checkbox' onclick="select_all()"/></th>
<th>S. No</th>
<th>Product Code</th>
<th>product name</th>
</tr>
<tr>
<td><input type='checkbox' class='chkbox'/></td>
<td><span id='sn'>1.</span></td>
<td><input class="form-control autocomplete_txt" type='text' data-type="product_code" id='product_code_1' name='product_code[]'/></td>
<td><input class="form-control autocomplete_txt" type='text' data-type="product_name" id='product_name_1' name='product_name[]'/> </td>
</tr>
</table>
<button type="button" class='btn btn-danger delete'>- Delete</button>
<button type="button" class='btn btn-success addbtn'>+ Add More</button>
{!! Form::close() !!}
</div>
<script type="text/javascript">
$(".delete").on('click', function() {
$('.chkbox:checkbox:checked').parents("tr").remove();
$('.check_all').prop("checked", false);
updateSerialNo();
});
var i=$('table tr').length;
$(".addbtn").on('click',function(){
count=$('table tr').length;
var data="<tr><td><input type='checkbox' class='chkbox'/></td>";
data+="<td><span id='sn"+i+"'>"+count+".</span></td>";
data+="<td><input class='form-control autocomplete_txt' type='text' data-type='product_code' id='product_code_"+i+"' name='product_code[]'/></td>";
data+="<td><input class='form-control autocomplete_txt' type='text' data-type='product_name' id='product_name_"+i+"' name='product_name[]'/></td></tr>";
$('table').append(data);
i++;
});
function select_all() {
$('input[class=chkbox]:checkbox').each(function(){
if($('input[class=check_all]:checkbox:checked').length == 0){
$(this).prop("checked", false);
} else {
$(this).prop("checked", true);
}
});
}
function updateSerialNo(){
obj=$('table tr').find('span');
$.each( obj, function( key, value ) {
id=value.id;
$('#'+id).html(key+1);
});
}
//autocomplete script
$(document).on('focus','.autocomplete_txt',function(){
type = $(this).data('type');
if(type =='product_code' )autoType='product_code';
if(type =='product_name' )autoType='name';
$(this).autocomplete({
minLength: 0,
source: function( request, response ) {
$.ajax({
url: "{{ route('productsearch') }}",
dataType: "json",
data: {
term : request.term,
type : type,
},
success: function(data) {
var array = $.map(data, function (item) {
return {
label: item[autoType],
value: item[autoType],
data : item
}
});
response(array)
}
});
},
select: function( event, ui ) {
var data = ui.item.data;
id_arr = $(this).attr('id');
id = id_arr.split("_");
elementId = id[id.length-1];
$('#product_code_'+elementId).val(data.product_code);
$('#product_name_'+elementId).val(data.name);
}
});
});
</script>
[route]
Route::get('/orders/create','PurchasetransactionsController#create')->name('orders.create');
Route::get('productsearch', ['as'=>'productsearch','uses'=>'PurchasetransactionsController#productsearch']);
I've added multiple autocomplete searches to input fields in laravel, and i've always had to look it back up each time i've implemented it. This is working for me. Here is the input which i'm searching for matching abbreviations in my search
<div class="input-group">
#if(isset($_GET['variable_name']))
<input value="{{$_GET['variable_name']}}" type="search" name="variable_name" class="form-control" id="variable_name" autocomplete="off">
#else
<input type="search" name="variable_name" class="form-control" id="variable_name" placeholder="Search" autocomplete="off">
#endif
</div>
Script to control ajax return:
$(document).ready(function($) {
// Set the Options for "Bloodhound" suggestion engine
var engine = new Bloodhound({
remote: {
url: '/find?variable_name=%QUERY%',
wildcard: '%QUERY%'
},
datumTokenizer: Bloodhound.tokenizers.whitespace('variable_name'),
queryTokenizer: Bloodhound.tokenizers.whitespace
});
$('#variable_name').typeahead({
hint: true,
highlight: true,
minLength: 1
}, {
name: 'abbreviations',
source: engine,
display: function(data) {
console.log(data);
return data.abbreviation //Input value to be set when you select a suggestion.
},
templates: {
empty: [
'<div class="list-group search-results-dropdown"><div class="list-group-item">Nothing found.</div></div>'
],
header: [
'<div class="list-group search-results-dropdown">'
],
suggestion: function(data) {
return '<div style="font-weight:normal; margin-top:-10px ! important;" class="list-group-item">' + data.abbreviation + ' ' + data.table + '</div></div>'
}
}
});
});
Controller function
public function find(Request $request) {
$result=Abbreviation::where('abbreviation', 'LIKE', "%{$request->input('variable_name')}%")
->orWhere('name', 'LIKE', "%{$request->input('variable_name')}%")->get();
return response()->json($result);
}
My Route:
Route::get('/find', 'PagesController#find')->name('typeahead.search');
libraries:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Also need the bloodhound.js and tyepahead.jquery

Ajax retrieves html instead of json

I'm having a problem with an ajax method, it retrieves an html file instead of json and I have no clue why it is happening because it works perfectly in my home route, but when I try to implement it in my create route, the ajax method doesn't work right
route file
Route::get('home', 'HomeController#index');
Route::get('suggestions',[
'as' => 'suggestions_path',
'uses' => 'SuggestionController#index'
]);
Route::get('suggestions/create',[
'as' => 'suggestions_path',
'uses' => 'SuggestionController#create'
]);
Route::get('ajax_scrap_app',[
'as' => 'ajax_scrap_app_path',
'uses' => 'AjaxController#getAppOpenGraph'
]);
HomeController
<?php namespace App\Http\Controllers;
use App\Level;
class HomeController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard to the user.
*
* #return Response
*/
public function index()
{
$levels = Level::all();
//dd($levels);
return view('home')->with('levels',$levels);
}
}
SuggestionController
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\SuggestionRequest;
use App\Level;
use App\Scrap;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Suggestion;
class SuggestionController extends Controller {
public function __construct()
{
$this->middleware('auth');
}
/**
* Despliega todas las sugerencias hechas por el usuario
*
* #return Response
*/
public function index()
{
$suggestions = Auth::user()->suggestions()->latest()->get();
return view('suggestions.all')->with('suggestions',$suggestions);
}
/**
* Despliega la forma para crear una sugerencia
*
* #return Response
*/
public function create()
{
$levels = Level::all();
return view('suggestions.create')->with('levels',$levels);
}
/**
* Guarda la nueva sugerencia
* #param SuggestionRequest $request
* #return Response
*/
public function store(SuggestionRequest $request)
{
$suggestion = new Suggestion($request->all());
Auth::user()->suggestions()->save($suggestion);
return redirect('suggestions');
}
/**
* Despliega una sugerencia específica, basados en el id
*
* #param int $id
* #return Response
*/
public function show($id)
{
$openGraph = new Scrap();
$suggestion = Suggestion::find($id);
return view('suggestions.show')->with(['suggestion' => $suggestion, 'openGraph' => $openGraph]);
}
/**
* Despliega la forma para editar una sugerencia específica, basados en el id
*
* #param int $id
* #return Response
*/
public function edit($id)
{
$suggestion = Suggestion::find($id);
return view('suggestions.edit')->with('suggestion',$suggestion);
}
/**
* Actualiza la sugerencia
*
* #param int $id
* #param SuggestionRequest $request
* #return Response
*/
public function update($id, SuggestionRequest $request)
{
$suggestion = Suggestion::find($id);
$suggestion->update($request->all());
return redirect('suggestions');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
//
}
}
here is my ajax method so far
$('#app_url').on('focusout',function(e){
var appURL = e.target.value;
console.log("appURL: "+appURL);
/* AJAX */
$.get('ajax_scrap_app?app_url='+appURL, function (data) {
console.log(data);
console.log("THIS IS THE TITLE: "+data[0].title);
console.log("THIS IS THE DESCRIPTION: "+data[0].description);
console.log("THIS IS THE IMAGE: "+data[0].image);
$('#app_title').val(data[0].title);
$('#app_description').val(data[0].description);
$('#app_image').val(data[0].image);
});
});
this is AjaxController
public function getAppOpenGraph(){
$scrap = new Scrap();
$url = Input::get('app_url');
$scrap::setUrl($url);
$title = $scrap::getOpenGraphTitle();
$description = $scrap::getOpenGraphDescription();
$image = $scrap::getOpenGraphImg();
$openGraph = [['title'=>$title,'description'=>$description,'image'=>$image]];
return Response::json($openGraph);
}
OUTPUT from home page (http://localhost/exaproject/public/home)
appURL: https://itunes.apple.com/us/app/crossy-road-endless-arcade/id924373886?mt=8&v0=WWW-NAUS-ITSTOP100-FREEAPPS&l=en&ign-mpt=uo%3D4
[Object]
THIS IS THE TITLE: Crossy Road - Endless Arcade Hopper
THIS IS THE DESCRIPTION: Get Crossy Road - Endless Arcade Hopper on the App Store. See screenshots and ratings, and read customer reviews.
THIS IS THE IMAGE: http://a3.mzstatic.com/us/r30/Purple7/v4/20/7a/c2/207ac26e-66f1-1ee0-1f70-c4733a9015a1/icon320x320.png
OUTPUT form create page (http://localhost/exaproject/public/suggestions/create)
appURL: https://itunes.apple.com/us/app/crossy-road-endless-
arcade/id924373886?mt=8&v0=WWW-NAUS-ITSTOP100-FREEAPPS&l=en&ign-mpt=uo%3D4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Apprendiendo</title>
<link href="http://localhost/exaproject/public/css/app.css" rel="stylesheet">
<!-- Latest compiled and minified CSS -->
<!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">-->
<!-- Fonts -->
<link href='//fonts.googleapis.com/css?family=Roboto:400,300' rel='stylesheet' type='text/css'>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Apprendiendo</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>Home</li>
<li class="dropdown">
Sugerencias <span class="caret"></span>
<ul class="dropdown-menu" role="menu">
<li>Crear Sugerencia</li>
<li>Búscar Sugerencias</li>
<li>Mis Sugerencias</li>
</ul>
</li>
<li>Mi Plan</li>
<li>Mi perfil</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
Angel Salazar <span class="caret"></span>
<ul class="dropdown-menu" role="menu">
<li>Logout</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
</div>
<!-- Scripts -->
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script src="http://localhost/exaproject/public/js/app.js"></script>
</body>
</html>
THIS IS THE TITLE: undefined
THIS IS THE DESCRIPTION: undefined
THIS IS THE IMAGE: undefined
I would appreciate some help !!!
Views by default return a string content like you did:
public function create()
{
$levels = Level::all();
// here you are calling an hmlt/text output
return view('suggestions.create')->with('levels',$levels);
}
That is the main reason why you are receiving html response. There are two options:
Return the rendered view inside of json:
public function create()
{
$levels = Level::all();
// here you are calling an hmlt/text output
$output = view('suggestions.create')->with('levels',$levels)->render();
return response()->json(['html' => $output]);
}
By this way, you can read the response in ajax callable as json like data.html
Avoid returning views. If you want json plain data, then works for that:
public function create()
{
// Do some logic here
// Return json data
return response()->json(['foo' => 'bar']);
}
Finally, looks like you are working with RESTful controllers, that is ok, but resources controllers do not were made to return html data.
I made it work, I don't know exactly why, but those are the changes I made
Route.php
Route::get('suggestions/create/ajax_scrap_app',[
'as' => 'ajax_scrap_app_path',
'uses' => 'AjaxController#getAppOpenGraph'
]);
Ajax method
$('#app_url').on('focusout',function(e){
var appURL = e.target.value;
console.log("appURL: "+appURL);
/* AJAX */
$.get('create/ajax_scrap_app?app_url='+appURL, function (data) {
console.log(data);
console.log("THIS IS THE TITLE: "+data[0].title);
console.log("THIS IS THE DESCRIPTION: "+data[0].description);
console.log("THIS IS THE IMAGE: "+data[0].image);
$('#app_title').val(data[0].title);
$('#app_description').val(data[0].description);
$('#app_image').val(data[0].image);
},'json');
});

Resources