Delete Method in Axios, Laravel and VueJS - laravel

I am trying to send a delete request via axios to laravel as follow:
axios.delete('api/users/' + this.checkedNames)
.then((response) => {
console.log(response)
}, (error) => {
// error callback
})
Now from axios documentation I read that for delete request we should be using a configObject so the above could be rewritten as so:
axios.delete('api/users/', {params: {ids:
this.checkedNames})
.then((response) => {
console.log(response)
}, (error) => {
// error callback
})
I have then Route::resource('users', 'UsersController'); in api.php so the default route for deleting is:
DELETE| api/users/{user}| users.destroy
and the controller's method is:
|App\Http\Controllers\UsersController#destroy
I am able to delete as expected a user when I pass a single id let's say api/users/12, it gets deleted correctly but when I try to pass the array above things get complicated.
if I try as per axios documentation axios.delete('api/users/', {params: {id: this.checkedNames}}) it looks I am sending this http://lorillacrud.dev/api/users?id[]=21&id[]=20 but I get a 405 method not allowed.
if I try axios.delete('api/users/' + this.checkedNames ) I get http://lorillacrud.dev/api/users/20,21 so in my destroy method I could grab the ids and delete, but I am wondering if this is the correct way to do it?
update
I seemed I made it work but I am not understanding so any help still appreciated to make a sense of what I am actually making work!
So, if change to:
axios.delete('api/users/destroy', {params: {'id': this.checkedNames})
and in my destroy method:
if ($request->id) {
foreach ($request->id as $id) {
User::destroy($id);
}
}
User::destroy($id);
}
So...
// not deletes the user
axios.delete('api/users/destroy', {params: {id: id}})
// ok deletes the users when using request->id in a for loop in the destroy laravel method.
axios.delete('api/users/destroy', {params: {ids: this.checkedNames}})
// ok deletes one user
axios.delete('api/users/' + id)
sorry guys but I have a lot of confusion why and what !!!
The route name is user.destroy why does it work when I pass an array and it does not when I pass a single value, why viceversa the route with method delete will not delete when pass an array ???
Any difference between using api/users/destroy vs api/users only?
Thanks for any help on this!

I also experienced the same problem. This works for me:
deletePost: function(id) {
axios.post('/posts/'+id,{_method: 'delete'})
}
Using axios.post() instead of axios.delete, and sending _method "delete"

It is because of the method signatures. The default delete route when using Resource expects a single parameter. So when doing:
axios.delete('api/users', {params: {'id': this.checkedNames})
you are missing a required parameter. The route definition is
Route::delete('api/users/{id}', 'UserController#destroy');
// You are missing `id` here. So it won't work.
Usually, if you are going to stray away from the default behavior, it is recommended to create your own function. So you could leave the default destroy($id) function as is to delete a single entry and write a new function that will delete many. Start by adding a route for it
Route::delete('api/users', 'UserController#deleteMany');
Then define the function to handle it
public function deleteMany(Request $request)
{
try
{
User::whereIn('id', $request->id)->delete(); // $request->id MUST be an array
return response()->json('users deleted');
}
catch (Exception $e) {
return response()->json($e->getMessage(), 500);
}
}
To summarise, your problem came from route definition. Your route from Axios did not match the route definition from Laravel, hence the 405.

I was having issue to send data as model while making delete request. I found a fix as follows:
deleteCall (itemId, jsonModel) {
return api.delete(`/users/${itemId}/accounts/`, {data: jsonModel})
},

Deleting users in array
Other good option, is to convert javascript array to string, and pass it has the required parameter, instead of passing object. Here the example:
In Vue.js 2.5.17+
//Use the javascript method JSON.stringify to convert the array into string:
axios.delete('api/users/' + JSON.stringify(this.checkedNames))
In Laravel 5.3+
//Resource default route (you don't need to create, it already exists)
Route::delete('api/users/{id}', 'UserController#destroy');
//In laravel delete method, convert the parameter to original array format
public function destroy($id)
{
User::destroy(json_decode($id); //converting and deleting users in array 'id'
}
Deleting single user by id
Just pass the id. You don't need to convert it.
In Vue.js 2.5.17+
axios.delete('api/users/' + id)
In Laravel 5.3+
You can name the parameter as you wish: user, id, item ,...
In Laravel 5.6+ < is named as $id //this can be the id or the user object
In Laravel 5.7+ > is named as $user //this can be the id or the user object
public function destroy($id)
{
User::destroy($id);
}

axios.post('/myentity/839', {
_method: 'DELETE'
})
.then( response => {
//handle success
})
.catch( error => {
//handle failure
})
https://www.mikehealy.com.au/deleting-with-axios-and-laravel/

Related

Issue with Integers passing data from Vue to Laravel using FormData

I am successfully updating a database using Vue 2 to a Laravel 8 Controller using Axios. However, I am stuck when attempting to pass an integer to my database.
My database has a column, 'number_of_searches' and it must be an integer.
Laravel Migration looks like this:
$table->integer('number_of_searches')->nullable();
And the model looks something like this:
class Product extends Model
{
protected $fillable = [
'product_title',
'number_of_searches' => 'integer',
];
}
My Vue updateProduct() function used FormData and appends the values coming from the form. It looks like this:
updateProduct(product){
let data = new FormData();
data.append('_method', 'PATCH');
data.append('product_title', product.product_title);
data.append('number_of_searches', product.number_of_searches);
axios.post('/api-route-to-update/product_id/', data)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
My update controller looks like this:
public function update(Request $request, $product_id){
$product = Product::findOrFail($product_id);
$product->update($request->all());
$product->save();
}
I can have as many input fields as I need and it works perfectly as long as they are strings. However, when I use a number input field in my component such as:
<input v-model="product.number_of_searches" type="number" min="1" max="999">
The generated json that will pass from axios into my controller looks like this:
{ "id": 5, "product_title": "The Product Title will work great", "number_of_searches": "222"}
You will notice that 'number_of_searches' is passed as a string, hence my database fails because it is the wrong datatype, it requires an integer. After reading the documentation and other threads, it seems that FormData will always return strings and that I must just deal with this on the server side.
So what I did is, I went into my back-end updateProduct() method and attempted to modify the Request.
First I tried a few methods such as:
//this one
$requestData = $request->all();
$requestData['number_of_searches'] = 123;
//also this one
$request->merge(['number_of_searches' => 123]);
//and this
$data = $request->all();
$data['number_of_searches'] = 123;
After countless hours, I am unable to modify the original request. After doing some research, it seems that requests are protected and cannot be modified, which makes sense. Therefore I attempted to create a new request that clones $request->all(), like this:
$new_request = new Request($request->all());
$new_request->merge(['number_of_searches' => 123]);
But I have failed to force to override 'number_of_searched'
My question is:
Should I stay away from FormData completely in this case? What method do you suggest to pass forms that have integers or floats or other datatypes through axios or fetch? Or what am I doing wrong? I find it hard to believe that FormData would only send strings (making parseInt useless before using axios). I'm sure I am doing something wrong from origin.
On the other hand, maybe I need to completely change my approach in my Controller when receiving the data. I am working on an app with a lot of fields and I love $request->all() because it simplifies what I am trying to do. I wouldn't mind using intval on the server side and that's it, but it seems overly complicated.
On the Vue side, you can use the number modifier on v-model to make sure it's not casting the value to a string:
v-model.number="product.number_of_searches"
On the request side, you can use $request->merge to override the value in a request
$request->merge([
'number_of_searches' => (int) $request->get('number_of_searches');
]);
At the model side in the updating hook within the boot method you can ensure the value is being casted as an int when saving:
static::updating(function ($model) {
$model->number_of_searches = (int) $model->number_of_searches;
});
This should give you the end to end.

vue axios delete request not working in laravel 7

Vue component
methods: {
removeCategory(index) {
if (confirm('Are you sure ?')) {
let id = this.categories[index].id;
console.log("ID="+id);
if (id > 0) {
axios.delete('/api/categories/' + id);
}
this.categories.splice(index, 1);
}
},
Routes Api
Route::delete('/categories/{category}', 'CategoryController#destroy');
Controller
public function destroy(Category $category)
{
$this->authorize('delete', $category);
$category->delete();
return $category;
}
Put request is working fine for inserting and updating data, but DELETE request is not able to delete data from the database.
Thanks
Laravel check CSRF token.
You need to add X-CSRF-TOKEN in the request header
You can read this doc : https://laravel.com/docs/7.x/csrf#csrf-x-csrf-token
If you haven't found the answer yet, quick fix as:
Remove the model binding in your Controller.
Grab specific category with an id.
Authorize and delete it.
(no need to modify the Component and the Route)

Laravel 5.4 controller function not able to use a get request parameter from ionic 3

I am try to pass a from ionic application to a laravel 5.4 application, and this parameter is an array, i have been able to pass the parameter successfully but i am being able to use the parameter to select records from the database.
Here is my ionic 3 provider function:
getMySmartQueues(data){
let params = new HttpParams();
params = params.append("sq_ids", JSON.stringify(data));
return this.http.get(this.url + 'my/smart/queues', {params: params});
}
And here is my laravel controller function:
public function getMySmartQueues(Request $request){
$ids = $request['sq_ids'];
$my_sq = SmartQueue::whereIn('id', $ids)->get();
return $my_sq;
}
And here is how i subcribe to the provider function is my page:
ionViewDidLoad() {
this.storage.get('sq_ids').then(
res => {
console.log(res);
if(res != null){
this.sq_ids= res;
console.log(this.sq_ids);
this.mService.getMySmartQueues(this.sq_ids).subscribe(
data => {
console.log(data);
}
);
}
}
);
}
But i get Server internal error. But if i have to hard code a default value for the controller function, let say like [5,6], it will return the records of this ids, but it can not returns the records of the ids sent from the ionic 3 application, will be glad if any one can help me out.
Also if i change the request to a put request i can get the records of the ids sent from the ionic application. But a get request is what i want.
if you want to use controller function with GET you need allow arguments in the Route to allow your id array.
for an example.
Route::get('your/url/{ids}', 'Controller#function')->name('mane_of_the_route');
and the controller function
public function getMySmartQueues(array $ids){
$my_sq = SmartQueue::whereIn('id', $ids)->get();
return $my_sq;
}
I have figure it out, and this is what i had to do, i think it might help someone one day, i just had to json_decode the request like so:
public function getMySmartQueues(Request $request){
$ids = $request['sq_ids'];
$my_sq = SmartQueue::whereIn('id', json_decode($ids))
->with(
'station.company'
)->get();
return $my_sq;
}

laravel array of strings to route action

A javascript code uses "map" method on array of object to extract just the text value:
var checked_leaves = checked_ids.filter(function(elm) {
if (elm.children.length == 0)
return elm;
}).map(function(elm, index) {
return elm.text.trim();
});
this array of string is sent to a Laravel route using ajax (with Vue http)
this.vm.$http.get(this.el.action + checked_leaves).then((response) => {
console.log(response);
//this.vm.speciesDetails = JSON.parse(response.data);
}, (response) => {
});
Where the this.el.action is api/taxonomytospecies/ and the corresponding Route is:
Route::get('api/taxonomytospecies/{ids}', 'TaxonomyController#getSpeciesFromTaxonomy');
And inside TaxonomyController:
public function getSpeciesFromTaxonomy($ids) {
// Eloquent job to retrieve the data from the DB
}
1) Is there a better way to pass an array of values like the one I get from the javascript code (they are a lot of strings) to a route of a controller?
2) I get an internal 500 error. The error shows that the call is like :
api/taxonomytospecies/name1,name2,name3,name4,name5
But i don't know how to resolve this kind of error
I would suggest you to use post request instead of get as the data is large.
You can send data as an array to the server.
var data = {ids: checked_leaves};
Then send data variable in your post request.
In your controller you can get data as:
public function getSpeciesFromTaxonomy() {
$ids = request()->get('ids') // returns an array.
// Eloquent job to retrieve the data from the DB
}
And your route should be as:
Route::post('api/taxonomytospecies', 'TaxonomyController#getSpeciesFromTaxonomy');
The solution is to set the Route as:
Route::get('api/taxonomytospecies/', 'TaxonomyController#getSpeciesFromTaxonomy');
And the Vue-resource request as:
this.vm.$http.get(this.el.action, {params: { ids: checked_leaves } }).then((response) => {
but i don't understand why.

how to use Route::input in laravel4?

I am trying to use Laravel 4 method called Route:input("users"). But I am getting following error
Call to undefined method Illuminate\Routing\Router::input()
Any idea how Route::input() works. Is there any file I need to change.
Thanks all
Route::filter('userFilter', function () {
if (Route::input('name') == 'John') {
return 'Welcome John.';
}
});
Route::get('user/{name}', array(
'before' => 'userFilter',
function ($name) {
return 'Hello, you are not John.';
}));
It looks as though Route::input was added in Laravel 4.1, make sure this is the version you are working with if you need to use this functionality.
I assume you've read the docs, but since you asked how it works, here's the example:
Accessing A Route Parameter Value
If you need to access a route parameter value outside of a route, you may use the Route::input method:
Route::filter('foo', function()
{
// Do something with Route::input('users');
});

Resources