Laravel $.post for download File? - laravel

I have view.blade.php like this
....
<meta name="_token" content="{!! csrf_token() !!}" />
....
<script>
jQuery(document).ready(function ($) {
$.ajaxSetup({
headers: {'X-CSRF-Token': $('meta[name="_token"]').attr('content')}
});
$.post('/download_file', {file_name: "abc"}, function (data) {
console.log(data);
});
});
</script>
In routes.php I already set route
Route::post('/download_file' , 'DownloadController#load_file');
In DownloadController.php I write code for create and download file like this
<?php
namespace App\Http\Controllers;
use Response;
use File;
use Illuminate\Http\Request;
class DownloadController extends Controller {
public function load_file(Request $request){
if($request->file_name === "abc"){
File::put("files/abc.txt", "This is content in txt file");
$file_abc = public_path() . "/files/abc.txt";
return Response::download($file_abc);
}
}
}
File abc.txt is create on server but browser doesn't download it after $.post call. In console.log(data) I see content of file. Thank for any help.

Laravel provides a response type download out of the box. Official documents states :
The download method may be used to generate a response that forces the user's browser to download the file at the given path. The download method accepts a file name as the second argument to the method, which will determine the file name that is seen by the user downloading the file. Finally, you may pass an array of HTTP headers as the third argument to the method:
return response()->download($pathToFile);
//OR
return response()->download($pathToFile, $name, $headers);
so your load_file function should response the file to download like this, no need to add jquery for this.

Related

laravel passing a variable to js file from a controller

I have a js file located in assets folder (not View). can i pass a varible from a controller?
In view file:
The Js is called like this
<canvas id="chart1" class="chart-canvas"></canvas>
</div>
It is not possible (in my point of view) to put a variable to external JS file. You can use data-... attributes and get values from html elements.
For example you can pass your PHP variable as a json encoded string variable in your controller.
$data['chart_info'] = json_encode($chart_info);
return view('your_view', $data);
Then put it in data-info like this.
<canvas id="chart1" class="chart-canvas" data-info="{{ $chart_info }}"></canvas>
And finally in JS, you can get the variable and decode (parse) it as following.
let canvas = document.getElementById('chart1');
let info = JSON.parse(canvas.dataset.id);
console.log(info);
You can put that part of the Javascript in the view and send the variable to the same view. For example, add a section in view:
#section('footer')
<script type="text/javascript">
</script>
#endsection
Do not forget that you should add #yield('footer') to the end of your layout view.
I don't like to mix javascript and PHP/Blade, it might be hard to read the code in the future... You could use a different approach, loading the chart with a async ajax request.
You will have to create a end-point that returns the data you need for your chart:
Your router:
Route::get('/chart/get-data', [ ControllerName::class, 'getChartData' ]);
Your controller method:
public function getChartData() {
$chartData = [];
// Your logic goes here
return $chardData;
}
In your javascript (using jquery) file there will be something like that:
function loadChartData() {
$.ajax({
'url': '/chart/get-data',
'method': 'GET'
})
.done((data) => {
// Load your chart here!!!
})
.fail(() => {
console.log("Could not load chart data");
});
}
Hope I helped ;)

Cannot return a laravel download via ajax call

I want the user to download a file and it doesn't really need to be via ajax, but it was the easiest way I found, but it's not working.
Here is my method from the Controller that I'm calling:
public function download(Request $request)
{
$dir = $request->get("directory");
return response()->download($dir);
}
Here is my ajax function:
function download(diretorio) {
$.ajax({
url: "/panel/download",
data: {_token: jQuery(".token").val(), diretorio: diretorio},
success: function(e) {
}
}).done(function(e) {
});
}
This function is being called inside this append:
$('#uploads tbody').append("<tr><td>" + fileName + "</td> <td><a class='btn btn-success' href='' onclick=\"download('" + item + "')\">Download</button></td></tr>");
});
Here is my route, which is inside a group called panel:
Route::get('/download/', ['as' => 'files.download', 'uses' => 'Panel\ClientController#download']);
My first question is: Is it possible to make this call from ajax to a download response from laravel?
Second question: I cannot figure out how to replace the ajax call for a route to a laravel controller, is it possible?
Thank you!
Yes it is possible. This is just with Laravel only though. Try this example:
HTML: (just call your GET route here)
download file(s)
Download Function
public function download()
{
// $pathToFile : set to what you need
return Response::download($pathToFile);
}
due to the fact that the directory path parameter has slashes, I think the route is expecting other parameters. So I decided not to pass the entire directory path, but only an ID and the name of the file. So my route became like this: Route::get('/download/{id}/{fileName}', ['as' => 'files.download', 'uses' => 'Painel\ClienteController#fazerDownload']);
And it worked. Thank you for the answers and efforts!

Minimum Working Example for ajax POST in Laravel 5.3

Can someone please explain the ajax post method in Laravel 5.3 with a full-working minimum example?
I know there are some resources in the web, but I miss a concise, straight-forward minimum example.
I presume you have a basic understanding of the model-controler-view paradigm, a basic understanding of Laravel and a basic understanding of JavaScript and JQuery (which I will use for reasons of simplicity).
We will create an edit field and a button which posts to the server. (This works for all versions from Laravel 5.0 to 5.6)
1. The Routes
At first you need to add routes to your routes/web.php. Create one route for the view, just as you know from ordinary views:
Route::get('ajax', function(){ return view('ajax'); });
The second route you need to create is the route that handles the ajax post request. Take notice that it is using the post method:
Route::post('/postajax','AjaxController#post');
2. The Controller Function
In the (second) route you created just now, the Controller function post in the AjaxController is called. So create the Controller
php artisan make:controller AjaxController
and in the app/Http/Controllers/AjaxController.php add the function post containing the following lines:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AjaxController extends Controller {
public function post(Request $request){
$response = array(
'status' => 'success',
'msg' => $request->message,
);
return response()->json($response);
}
}
The function is ready to receive data via a Http request and returns a json-formatted response (which consists of the status 'success' and the message the function got from the request).
3. The View
In the first step we defined the route pointing to the view ajax, so now create the view ajax.blade.php.
<!DOCTYPE html>
<html>
<head>
<!-- load jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<!-- provide the csrf token -->
<meta name="csrf-token" content="{{ csrf_token() }}" />
<script>
$(document).ready(function(){
var CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content');
$(".postbutton").click(function(){
$.ajax({
/* the route pointing to the post function */
url: '/postajax',
type: 'POST',
/* send the csrf-token and the input to the controller */
data: {_token: CSRF_TOKEN, message:$(".getinfo").val()},
dataType: 'JSON',
/* remind that 'data' is the response of the AjaxController */
success: function (data) {
$(".writeinfo").append(data.msg);
}
});
});
});
</script>
</head>
<body>
<input class="getinfo"></input>
<button class="postbutton">Post via ajax!</button>
<div class="writeinfo"></div>
</body>
</html>
If you wonder what's the matter with this csrf-token, read https://laravel.com/docs/5.3/csrf

Laravel: workaround the CSRF token via Ajax issue :

Scenario:
I want via ajax send chosen words to a Controller, but I am getting all the time "Internal server error" After a full Sunday of struggling and swearing I think I know why this is happening and how it could be solved. I dont have that problem if I send the word via a ordinary Form and Submit button. The issue is the mis-marriage between Ajax and the CSRF token mismatch.
So here is the Ajax snippet>
<script>
$(document).ready(function(){
$('.choose-language').on('click', function(e){
e.preventDefault();
var selectedlanguage = $(this).data('value');
alert(selectedlanguage); // it gets the value alright on clicking the paragraph
$.ajax({ // so I want to send it to the controller
type:"POST", // via post
url: 'language', // correct?
data:{'locale': selectedlanguage},
}); // HERE FINISHES THE $.POST STUFF
}); //HERE FINISHES THE CLICK FUNCTION
}); // HERE FINISHES THE DOCUMENT AND READY STUFF
</script>
Here is the HTML
<div class="choose-language">
<p class="choose-language" id="english" data-value="en" >English</p>
<p class="choose-language" id="spanish" data-value="es" >Spanish</p>
</div>
Here is the Routes:
Route::get('/', function () {
return view('welcome');
});
Route::post('language', array(
'as' =>'language',
'uses' => 'LanguageController#changelanguage'
));
And the Controller
class LanguageController extends Controller
{
public function changelanguage()
{
Session::set('locale', \Input::get('locale'));
return \Redirect::back();
}
}
So, if I go to Middleware, I can see there is a File called VerifyCSRFToken.php and inside that file there is this:
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
// code here
];
}
So, I am sure that should fix it, but I wrote 'language' where the // code here is and did not make any difference. There must be other bugs..
Thanks a lot.
UPDATE:
I have found a typo (apologies I had written redirecto instead of redirect) and I m not getting errors anymore.
Add the CSRF token to your HTML head:
<meta name="csrf-token" content="<?= csrf_token() ?>">
Add this to your JS file:
$.ajaxSetup({
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
}
});
The CSRF should now pass the middleware
There was one annoying thing in this HMTL code: as you see the class "choose-language" was repeated also in the div, which caused the click to be repeated twice, and the second time without actually sending a value. So I have left it there for you to see, but you do need to remove it. Once you remove it from the div, the code works correctly. So this responds and solves the issue of Ajax and Laravel CSRF. I have tested the output of the controller and it gets the word sent. Before Laravel 5.0 you had to go through a lot of hacking in the code and fix the bugs and add also conditionals in the filter to let decide when CSRF was or not coming from an Ajax, besides having to add code in every header of every page where you had Ajax sending something etc.
Now, in Laravel 5.0 you just do as I wrote in the code and you are done.

How do I add ajax URL on a laravel js file?

I am building a store locator for a website that I am building in Laravel. Since the blade file calls the js file tht is on the assests folder. It doesn't recognize the URL like this
$.ajax({
url: '{{ URL::action('getLocation') }}',
// ...
});
This is how I have my route.php
Route::post('/getLocation', array('as'=>'getLocation','uses'=>'FrontController#getLocation'));
So it doesn't find the file. How can I call this function in the ajax URL?
Here is a demonstration of how i would achieve this
I might be late here. This is just a sample code to help understand people
who visit this question. Hope this helps anyone who visits here.
in my routes.php i define a named route
Route::post('getLocation',array(
'as'=>'getLocation','uses'=>'FrontController#getLocation')
);
added name route as data-url in my somehtmlform.blade.php file
{!! Form::open() !!}
{!! Form::text('input-name',null,array('class'=>'form-control search-input','data-url'=> URL::route("getLocation") ))
{!! Form::close() !!}
my search.js file catches the data-url and use it as post url
$('.search-input').each(function(){
$(this).on('change',function (e) {
search(this)
});
});
function search(self) {
var query = $(self).val();
$.ajax({
url: $(self).attr('data-url'),
type: 'post',
data: {'q':query, '_token': $('input[name=_token]').val()},
success: function(data){
console.log(data);
},
error: function(data){
// Not found
}
});
}
You can use this package, it gives almost all laravel helper functions which can be used in js files too.
You may try this:
// Add this in your filtes.php file (feel free to store where you like)
View::composer('layouts.master', function($view) {
$ajaxUrl = json_encode(array('url' => URL::action('getLocation')));
$view->with('ajax', $ajaxUrl);
});
Add this in you master.blade.php file's (master layout) <head></head> section (place it before your js file):
<script>var ajax = {{ $ajax or 'undefined' }}</script>
Now you can use this as:
// ajax.url
console.log(ajax.url);
Read here, similar thing.
It looks like you're using the wrong method for generating the URL.
Try switching from URL::action() to URL::route().
URL::action() is used to generate a URL to a given controller action, but then you need to write it like this:
URL::action('FrontController#getLocation')
URL::route() generates a url to a route which is named in the route definition, using "as" => "routeName". In your case:
URL::route('getLocation')
Hope this helps!
If you call your ajax function from a .js file,
try to change the blade part '{{ URL::action('getLocation') }}' to '/getLocation'
or pass a full url like: 'http://domain.com/getLocation' and it should work.
in js file, you can't not use the Url::action for route
just do
url:"/getLocation"

Resources