Calling a PHP method inside a controller with Ajax (Laravel) - php

I have a Controller in my Laravel project called Clientecontroller, it works perfectly. Inside it, I have a method called listar() who brings me client's information.
public function listar(Cliente $cliente) {
$clientes = DB::table('clientes')
->where('documento_id', 1)
->first();
return $clientes;
}
Sure it has some troubles but my main question is, how I call this listar() function from a view with Angular or Ajax or whatever could work.
I am working in a selling system and I have to bring the client information before selecting anything else. I want to write the ID number from the clients in my view and bring the client information from my controller without reloading. But I am still stuck in the processing reaching the listar() function.
Thank you very much.

in your routes.php file add
Route::post('/cliente', 'Clientecontroller#listar');
And now use your ajax call in order to send data to /cliente the data will be sent through to your listar method in the ClienteController.
$.ajax({
type: "POST",
url: '/cliente',
data: { id: 7 }
}).done(function( msg ) {
alert( msg );
});
This question was answered, for more details head over here

1. The classical HTML approach
Let's say you have a button on your page :
<button id="call-listar">Call !</button>
You could send an HTTP Request to your Laravel application like that :
document.querySelector('#call-listar').addEventListener('click', (e) => {
// Use the fetch() API to send an HTTP Request :
fetch('/the-url-of-listar-controller')
.then(response => response.json())
.then(json => {
// Do what you want to do with the JSON
});
});
📖 You can find a very usefull documentation about the fetch() API here : https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
2. Inside an Angular Component
This is an other story here, let's say you have this button in your HTML Template :
<button (click)="callListar()">Call !</button>
Inside your TypeScript, you could use HttpClientModule to send an HTTP Request to your Laravel App :
class MyComponent {
constructor(private http: HttpClient){}
callListar() {
this.http.get('/url-of-listar-controller')
.subscribe(response => {
// Do what you want with the response
});
}
}
WARNING : HttpClientModule needed !
You must import the HttpClientModule inside your AppModule or any other module of your Angular App where you want to use this component :
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [...],
imports: [HttpClientModule]
})

Related

Post form data to php script using axios

I'm trying to send the form data to a php script using axios.
Is the syntax of axios correct?
How can I view the data sent via the post method?
I just started programming in vuetify and php, so I need a little help
methods: {
formSubmit(e) {
e.preventDefault();
let currentObj = this;
this.axios.post('http://localhost/index.php/',{
name : this.name, user : this.username
})
.then(function (response) {
currentObj.output = response.data;
})
.catch(function (error) {
currentObj.output = error;
});
},
}
in the php file there's :
<?php
require_once 'limonade.php';
$data = $_POST;
dispatch('/api/', 'test1');
function test1()
{
return 'Hello';
}
run();
Your php only acts when it's a GET Call, limonade's dispatch() is for GET only.
In your php you are creating a GET endpoint on the /api/ url that will execute the test1 function. Meaning when you call /api via get, you will get Hello as answer.
if you want that to be POST (without touching your javascript) the php should be something like:
# '/' because you are calling to http://localhost/index.php/ it could be '/whatever' if you call http://localhost/whatever (assuming you have configured everythign as limonade recomends)
function test2()
dispatch_post('/', 'test2');
{
return 'Hello via post';
}

How to pass Laravel data into Vue root instance with Laravel Mix Setup

So I am using Laravel 5.5. I have a data coming from my Controller and I want to pass it to my root vue instance not the component.
So for example I have the Dashboard Controller which has a data of "users"
class DashboardController extends Controller {
public function index(){
$user = User::find(1);
return view('index', compact('user'));
}
}
I am using Larave mix on my project setup. So my main js file is the app.js. That "$user" data I need to pass on the root Vue instance. Which is located in app.js
const app = new Vue({
el: '#dashboard',
data: {
// I want all the data from my controller in here.
},
});
If you don't want to use an API call to get data (using axios or else), you could simply try this :
JavaScript::put(['user' => $user ]);
This will, by default, bind your JavaScript variables to a "footer" view. You should load your app.js after this footer view (or modify param bind_js_vars_to_this_view).
In app.js :
data: {
user: user
}
Read more : https://github.com/laracasts/PHP-Vars-To-Js-Transformer
I would make a request to fetch the user's data as has been suggested.
Alternatively, you can add a prop to the dashboard component in index.blade.php and set the user like <dashboard :user="{{ $user }}"></dashboard>. You'll probably want to json_encode or ->toArray() the $user variable.
Then within the dashboard component you can set data values based on the prop.
props: ['user'],
data () {
return {
user: this.user
}
}
I just solved this by placing a reference on the window Object in the <head> of my layout file, and then picking that reference up with a mixin that can be injected into any component.
TLDR SOLUTION
.env
GEODATA_URL="https://geo.some-domain.com"
config/geodata.php
<?php
return [
'url' => env('GEODATA_URL')
];
resources/views/layouts/root.blade.php
<head>
<script>
window.geodataUrl = "{{ config('geodata.url') }}";
</script>
</head>
resources/js/components/mixins/geodataUrl.js
const geodataUrl = {
data() {
return {
geodataUrl: window.geodataUrl,
};
},
};
export default geodataUrl;
usage
<template>
<div>
<a :href="geodataUrl">YOLO</a>
</div>
</template>
<script>
import geodataUrl from '../mixins/geodataUrl';
export default {
name: 'v-foo',
mixins: [geodataUrl],
data() {
return {};
},
computed: {},
methods: {},
};
</script>
END TLDR SOLUTION
If you want, you can use a global mixin instead by adding this to your app.js entrypoint:
Vue.mixin({
data() {
return {
geodataUrl: window.geodataUrl,
};
},
});
I would not recommend using this pattern, however, for any sensitive data because it is sitting on the window Object.
I like this solution because it doesn't use any extra libraries, and the chain of code is very clear. It passes the grep test, in that you can search your code for "window.geodataUrl" and see everything you need to understand how and why the code is working.
That consideration is important if the code may live for a long time and another developer may come across it.
However, JavaScript::put([]) is in my opinion, a decent utility that can be worth having, but in the past I have disliked how it can be extremely difficult to debug if a problem happens, because you cannot see where in the codebase the data comes from.
Imagine you have some Vue code that is consuming window.chartData that came from JavaScript::put([ 'chartData' => $user->chartStuff ]). Depending on the number of references to chartData in your code base, it could take you a very long time to discover which PHP file was responsible for making window.chartData work, especially if you didn't write that code and the next person has no idea JavaScript::put() is being used.
In that case, I recommend putting a comment in the code like:
/* data comes from poop.php via JavaScript::put */
Then the person can search the code for "JavaScript::put" and quickly find it. Keep in mind "the person" could be yourself in 6 months after you forget the implementation details.
It is always a good idea to use Vue component prop declarations like this:
props: {
chartData: {
type: Array,
required: true,
},
},
My point is, if you use JavaScript::put(), then Vue cannot detect as easily if the component fails to receive the data. Vue must assume the data is there on the window Object at the moment in time it refers to it. Your best bet may be to instead create a GET endpoint and make a fetch call in your created/mounted lifecycle method.
I think it is important to have an explicit contract between Laravel and Vue when it comes to getting/setting data.
In the interest of helping you as much as possible by giving you options, here is an example of making a fetch call using ES6 syntax sugar:
routes/web.php
Route::get('/charts/{user}/coolchart', 'UserController#getChart')->name('user.chart');
app/Http/Controllers/UserController.php
public function getChart(Request $request, User $user)
{
// do stuff
$data = $user->chart;
return response()->json([
'chartData' => $data,
]);
}
Anywhere in Vue, especially a created lifecycle method:
created() {
this.handleGetChart();
},
methods: {
async handleGetChart() {
try {
this.state = LOADING;
const { data } = await axios.get(`/charts/${this.user.id}/coolchart`);
if (typeof data !== 'object') {
throw new Error(`Unexpected server response. Expected object, got: ${data}`);
}
this.chartData = data.chartData;
this.state = DATA_LOADED;
} catch (err) {
this.state = DATA_FAILED;
throw new Error(`Problem getting chart data: ${err}`);
}
},
},
That example assumes your Vue component is a Mealy finite state machine, whereby the component can only be in one state at any given time, but it can freely switch between states.
I'd recommend using such states as computed props:
computed: {
isLoading() { return (this.state === LOADING); },
isDataLoaded() { return (this.state === DATA_LOADED); },
isDataFailed() { return (this.state === DATA_FAILED); },
},
With markup such as:
<div v-show="isLoading">Loading...</div>
<v-baller-chart v-if="isDataLoaded" :data="chartData"></v-baller-chart>
<button v-show="isDataFailed" type="button" #click="handleGetChart">TRY AGAIN</button>

How to send a request from angular front end to laravel API?

I'm building a RESTful API with Laravel 5.2 and I have an AngularJS 1.5 front end. I am successfully writing services to get information but I am having troubble putting or posting anything to the database when I pass it to the API. I've tried doing some searching and but I just don't understand how to actually save data I would send the API. Here is my attempt so far:
-Service from the Factory-
addReceipt: function(request) {
return $http.post(api_url + "/rewards/receipts/add", request).then(function(results) {
console.log(results);
return results.data;
});
}
-From the Controller
$scope.submitReceipt = function() {
rewardsFactory.addReceipt($scope.model).then(function() {
console.log($scope.model);
toaster.pop({ type: 'success', title: 'Claim Submitted!', body: "Thanks! We'll take a look at your claim shortly.", showCloseButton: true });
});
};
-From Laravel API routes
Route::post('rewards/receipts/add', 'Rewards\RewardsController#addReceipt');
-From Laravel Controller
public function addReceipt(Request $request)
{
//Add the Receipt
DB::table('receipts')->insert(
['transaction_id' => $request->input('transactionID'),
'client_id' => $request->input('client_id'),
'location_id' => $request->input('location_id') ]
);
}
My Current Cors setup seems to be working out well enough for at least some traffic so I don't think that is the problem but I'm just still not sure what I'm doing wrong.
Note that $http does not send form encoded data by default, it sends application/json in request body.
I don't do any work with laravel but if you check $_POST you will see it is empty so $request->input is probably empty also.
In php you can access the response body using :
json_decode(file_get_contents('php://input')[,true/*optional to convert to array*/])
I believe that json_decode($request->getContent()) will do the same in laravel
The alternative is to use the following $http set up taken from the docs to send form encoded data
.controller(function($http, $httpParamSerializerJQLike) {
//...
$http({
url: myUrl,
method: 'POST',
data: $httpParamSerializerJQLike(myData),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
});
You can also set $http.defaults in a run block so all post or put are sent as x-www-form-urlencoded and not have to add the config to each use

Contao 2.11 call to module via ajax

I have question about call to my module action via ajax.
I'd like call to class in my module via ajax. But best solution for me is call to clean class. Not extends Module.
I don't know hot can I make url without add article to database and add module to him.
I use JQuery instead mooTools but js framework is not important. Most important is call to php class by ajax.
I have ajax module. But if I call to ajax.php required is module id from tl_module table. I don't want use this table. (Ajax will be very often calling, I prefer to don't load all contao mechanism. It should be very fast).
Thanks in advance for answers.
I found the answer for Contao >3.x in a GitHub issuse(german)
At first do in your Front-end Template:
<script type="text/javascript">
var data = {};
data["REQUEST_TOKEN"] = "<?php echo REQUEST_TOKEN ?>";
$(document).ready(function(){
$("#trigger").click(function(event){
$.post(
'<?php echo \Contao\Environment::get('requestUri')?>',
data,
function(responseText) {
alert(responseText);
}
).fail(function( jqXhr, textStatus, errorThrown ){ console.log( errorThrown )});
event.preventDefault();
});
});</script>
Important is the
- data["REQUEST_TOKEN"] -> if you do not add it, the POST-request will not reach your module:
public function generate()
{
if ($_SERVER['REQUEST_METHOD']=="POST" && \Environment::get('isAjaxRequest')) {
$this->myGenerateAjax();
exit;
}
return parent::generate();
}
//do in frontend
protected function compile()
{
...
}
public function myGenerateAjax()
{
// Ajax Requests verarbeiten
if(\Environment::get('isAjaxRequest')) {
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(array(1, 2, 3));
exit;
}
}
If you want to do the ajax via GET you do not need the reqest token but the jquery funktion $get();
I would suggest you to use Simple_Ajax extension.
In this case you dont need to use Database and you can do pretty much anything you can do normally with Jquery ajax calls.
It works with Contao 2.11 and you can call your php class with it.
I find it much easier to use than ajax.php .
You can get it from : https://contao.org/de/extension-list/view/simple_ajax.de.html
Copy SimpleAjax.php to Contao's root folder.
Go to [CONTAO ROOT FOLDER]/system/modules and create a php file like following :
class AjaxRequestClass extends System
{
public function AjaxRequestMethod()
{
if ($this->Input->post('type') == 'ajaxsimple' )
{
// DO YOUR STUFF HERE
exit; // YOU SHOULD exit; OTHERWISE YOU GET ERRORS
}
}
}
Create a folder called config with a php file like following ( You can hook you class to TL_HOOKS with class name - class method, simple_ajax will execute you method whenever a ajax call is made ):
$GLOBALS['TL_HOOKS']['simpleAjax'][] = array('AjaxRequestClass','AjaxRequestMethod'); // Klassenname - Methodenname
Now you can easily make ajax calls with simply posting data to SimpleAjax.php:
$.ajax({
type: "POST",
url: "SimpleAjax.php",
data: { type: "ajaxsimple" },
success: function(result)
{
//DO YOUR STUFF HERE
}

Return a view via ajax in laravel

I want to display a view to the user whenever user clicks on a button using ajax.
This is my code.
// BASE = localhost/project/public/
$('#button').click(function() {
$.ajax({
url: BASE + "user/settings",
type: 'GET'
})
.done(function( data ) {
console.log( data );
});
});
And my routes.php
Route::get('user/settings', 'UserController#getSettings');
And UserController.php
public function getSettings(){
return View::make('user.settings');
}
But output is this error:
{"error":{"type":"ErrorException","message":"Undefined offset: 0","file":"H:\\dev \\xampp\\htdocs\\lchat\\vendor\\laravel\\framework\\src\\Illuminate\\Support \\Collection.php","line":470}}
EDIT: error was in view. I fixed it.
Problem2: The page which is loading via ajax, itself contains another ajax post request. but it's not sending data via ajax anymore. refreshes the page to send data.
The jquery code:
$('#settings :submit').click(function(e){
e.preventDefault();
$.post(BASE + 'settings/save', {
'userName' : $('#userName').val()
}, function(data) {
return 'OK';
});
});
Problem solved: I used .on to bind event:
$(document).on('click', '#settings :submit', function(e){ ... } );
It's working...
Thank everyone.
Well, for starters, you have an error in your view. The error you're getting is in reference to an array you're trying to access that doesn't actually have the key you're trying to use ($arr[0]).
Once you fix the errors with the view itself, it should work fine. The JavaScript will get the data as HTML, and you can just insert it into wherever you want it to show up.
Use string method before view file
return (String) view('Company.allUserAjax');

Categories