Delete multiple rows using Laravel and Vue Js - laravel

Am having a problem deleting multiple rows in Laravel and Vue Js. I am able to get the values of id as an array. When I click on delete button I get a status 200 but no record is deleted from the database. Here is my code:
In my table
<tr v-for="user in users.data" :key="user.id">
<td>{{user.id}}</td>
<td>{{user.userName}}</td>
<td><input type="checkbox" :value="user.id" v-model="checkedNames"></td>
<button class="btn btn-warning" #click=" deleteAllUser()">Delete
Selected</button>
</td>
</tr>
Vue Js
<script>
export default {
data(){
return{
checkedNames:[],
Function
deleteAllUser(){
this.form.post('api/deletehotspotusers/',{id:this.checkedNames}).then(()=>{
self.loadHotspotUsers();
}).catch(()=> {
Swal.fire("Failed!", "There was something wrong.", "warning");
});
}
}
In my controller
public function deleteAll(Request $request){
if($request->id){
foreach($request->id as $id){
HotspotUsers::destroy($id);
}
}
My route
Route::post('/deletehotspotusers', 'HotspotUsersController#deleteAll');

To delete a model record you need to call the delete method. You can try the below in the controller method
//import use statement at the top of the class
//use Illuminate\Support\Arr;
public function deleteAll(Request $request){
if($request->id){
HotspotUsers::whereIn('id', Arr::wrap($request->id))->delete();
}
}
In Vue, input type checkbox, v-model uses checked property and change event, so v-model will record either true or false based on the checked state. In order to populate the id with user.id, you need to make use of change event
<tr v-for="user in users.data" :key="user.id">
<td>{{user.id}}</td>
<td>{{user.userName}}</td>
<td>
<input type="checkbox" :value="user.id" #change="onChecked(user.id)">
</td>
<td>
<button class="btn btn-warning" #click=" deleteAllUser()">
Delete Selected
</button>
</td>
</tr>
And in the script section in methods
onChecked(id){
if(!this.names.includes(id)){
this.names.push(id)
} else {
this.names.splice(this.names.indexOf(id),1)
}
}

I am not into vue.js.
If your front-end works good, then here is the laravel code.
Make sure that $request->id is receiving the value you expected.
You can use like
Model::destroy([array of primary keys])
If your Model's primary key is id, then you can specify array of ids like [1,2,3,4].
But before make sure the input values by using logger($request->id).
Thank you

Related

View and Controller for a Downloadpage

I need to create a downloadpage. Ich have a model Product and a model File. The create/store and the edit/update is already working. With a submit button I'm saving fields like produktname, description, etc. into products-table. Fields like filename, filePath and product_id saving into files-table. Files also uploaded to Storage. Model Product has a hasMany-relation to File and the model File has a BelongsTo-relation to Product. In the File model "product_id" is related to the Product model.
So far so good. What's also working is: Index view of FileController. I can see all uploaded files and can also download them. Through the product_id I can access the actual product show method. That's how it should be. It's possible here in the index.blade.php:
#foreach ($files as $file)
<tr>
<th>{‌{ $file->filename }}</th>
<td>download</td>
<td>{‌{ $file->product_id }}</td>
<td>{‌{ $file->id }}</td>
</tr>
#endforeach
In the show.blade.php I can see already all data from the products table. I have two buttons for downloading changelog (just a link) and working and for downloading the stored file (which is in the files table. I can't get it working for the download stored file. dd($files); is NULL. Here's the ProductController show part. I applied use App\File; on top of the controller, because I want to give the ability to access the File model.
public function show(Product $product)
{
return view('products.show', compact('product','file'));
}
In show.blade.php I get an error: compact(): Undefined variable: file
<div>
<button id="changelog" name="changelog" class="btn btn-lg btn-primary btn-block" type="submit" onclick="window.open('{‌{ $product->changelog }}')">Download Changelog</button>
<button id="filename" name="filename" class="btn btn-lg btn-success btn-block" type="submit" onclick="window.open('{‌{ $file->filename }}')">Download Installer</button>
</div>
How can I access an element of the other model or the other table? How can I expand {‌{ $file->filename }} or probably {‌{ $product->$file->filename }} to get the file to download?
I'm trying since days and can't find the solution.
Thx, for responding. I still have problems doing Eloquent and Query building, but the use of dd od var_dump helps alot and showed me that I have valuable data. The problem was to define the query.
Here's the working stuff:
Product model:
public function file()
{
return $this->hasMany('App\File', 'product_id');
}
File model:
public function product()
{
return $this->hasOne('App\Product', 'id');
}
Product controller:
public function show(Product $product)
{
$files = Product::with('file')->find($product->id)->file;
return view('products.show', compact('product', 'files'));
}
show view:
#foreach ($files as $file)
<button id="filepath" name="filepath" class="btn btn-lg btn-success btn-block" type="submit" onclick="window.open('{{ $file->filepath }}')">Download File: {{ $file->filename }}</button>
#endforeach

How to check for authorization of two users in Laravel blade #can tag

I have 6 types of users in my application. For one view, I want to check if any one of the given two types of users are logged in. If they are, then show this item.
This is working
#can('admin-controller')
<div class="custom-submit-button-group">
View All Messages
</div>
#endcan
But, I want this to work. I want to show the div to these two user types.
#can('admin-controller' || 'general-controller')
<div class="custom-submit-button-group">
View All Messages
</div>
#endcan
But none of them can see this item.
I can use Auth::check() but I only wanted to use #can
Try #canany.
<table>
<tr>
<th>...</th>
#canany(['edit_post', 'delete_post'])
<th>Actions</th>
#endcanany
</tr>
<tr>
<td>...</td>
#canany(['edit_post', 'delete_post'])
<td>
#can('edit_post')
<button>Edit</button>
#endcan
#can('delete_post')
<button>Delete</button>
#endcan
</td>
#endcanany
</tr>
</table>
You can use Gate Facade like this:
#if(Gate::check('update-post') || Gate::check('update-post2'))
#endif
And you can define your permissions in App\Providers\AuthServiceProvider liek this:
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
OR
#if($user->can('perm1') || $user->can('perm2'))
// do something
#endif

Why vue js triggers all methods when there is a change in data?

I have a input field in the form to get the customer name and binding the value to model "customer_name".
<input placeholder="Customer name" required="required" name="customer_name" type="text" id="customer_name" class="form-control" v-model="customer_name">
If user submits the form, I am making a ajax get request to get the matching customer names and storing the results in the variable "customers" and rending the results in table view.
<tr v-for="customer in customers">
<td >
#{{ customer.firstname + " " +customer.lastname}}
</td>
<td >
#{{ formatBday(customer.birthday)}}
</td>
</tr>
And this is formatBday() implementation,
methods: {
formatBday : function (bday) {
console.log("function called");
return moment(bday).format("DD.MM.YYYY");
}
}
So after every ajax call, it will show the results in table view. After showing the results, now i am trying to change the value in customer name text box, and i have observed, for every character i type in the customer name textbox, formatBday() function is being executed.
There is no binding between customername textbox and formatBday() function. But after the search, whenever i type/change customer name formatBday() is being triggered.
Does anyone know how to stop this unwanted function triggering?

VueJs and Laravel - multiple select fields

Using Laravel 5.4 and Vuejs 2.1
In code I have a select field with two input fields (quantity and stock) in tr (Table Row). Table Row with the fields can be dynamically added as much as user is needed, this is the code:
<tbody id="loads-content">
<tr v-for="(item, index) in items">
<td>
<select v-model="item.load_id" name="load_id[]" class="loads" v-on:change="getLoadStock()">
<option v-for="load in loads" :value="load.id" :id="load.id">{{load.name}}</option>
</select>
</td>
<td><input type="text" v-model="item.quantity" name="quantity[]" class="input is-hovered qty"></td>
<td><input type="text" v-model="item.stock" class="input is-hovered stock" disabled readonly="true"></td>
<td>
<button type="button" class="button is-danger remove" #click="items.splice(index, 1)"><i class="fa fa-minus-square-o" aria-hidden="true"></i></button>
</td>
</tr>
<a #click="addLine" class="button is-success"><i class="fa fa-plus-square-o" aria-hidden="true"></i></a>
</tbody>
When you choose some value from select field I need to populate the STOCK input field with stock data from the database. For that I used an API call. I made something like this:
methods: {
addLine() {
this.items.push({
load_id: '',
quantity: '',
stock: ''
})
},
getLoadStock(){
var loadsContent = $('#loads-content');
var tr = loadsContent.parent().parent();
var id = tr.find('.loads').val();
axios.get('/api/load/' + id)
.then(function(response) {
tr.find('.stock').val(response.data.stock);
})
.catch(function(error) {
console.log(error)
});
},
This code is not working as expected.
The goal is to fetch actual stock for current choosen load, to see how much quantity can you enter in the input field for quantity.
I am open for any suggestions, if anyone has a better approach and solution please help.
Thanks in advance! :)
You are mixing two different and incompatible ways of building a web app: Vue.js and jQuery.
When using Vue, you should not be manipulating the DOM directly. You should instead be binding the DOM elements to Vue model attributes. Then, if you need a DOM element to reflect a change, you change the model – not the DOM.
So for instance, you would want something like this (note adding index as an argument to getLoadStock):
<select v-model="item.load_id" name="load_id[]" class="loads" v-on:change="getLoadStock(index)">
<option v-for="load in loads" :value="load.id" :id="load.id">{{load.name}}</option>
</select>
and
getLoadStock(index){
axios.get('/api/load/' + this.items[index].load_id)
.then(function(response) {
this.items[index].stock = response.data.stock;
})
.catch(function(error) {
console.log(error)
});
},

Angular 2 doesn't update my view after I add or edit item

I've finally made my app in angular 2. Everything is solved, except one thing. When I add item into my table or edited it, I can't see the change until I refresh page or click for example next page button (I have implemented pagination). I included:
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
in this order. My method for adding item is very simple:
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();}
Whhen I add item, and put breakpoint on get method, It is called correctly and I get right information from my DB, but I don't know why view isn't refreshed then. Do you have any idea why is it happened? Thanks for suggestions!
EDIT: department is just department: Department, where Department is interface with properties (departmentNo, departmentName, departmentLocation). The view for adding item looks like:
<form [ngFormModel]="myForm"
(ngSubmit)="addDepartment(newItem); showAddView=false" [hidden]="!showAddView" align="center">
<div>
<label for="editAbrv">Department name:</label><br>
<input type="text" [(ngModel)]="newItem.departmentName" [ngFormControl]="myForm.controls['departmentName']" >
<div *ngIf="myForm.controls['departmentName'].hasError('required')" class="ui error message"><b style="color:red;">Name is required</b></div>
</div>
<br/>
<div>
<label for="editAbrv">Department Location:</label><br>
<input type="text" [(ngModel)]="newItem.departmentLocation" [ngFormControl]="myForm.controls['departmentLocation']" >
<div *ngIf="myForm.controls['departmentLocation'].hasError('required')" class="ui error message"><b style="color:red;">Location is required</b></div>
</div>
<br/>
<div>
<button type="submit" [disabled]="!myForm.valid" class="ui button">Add item</button>
<button><a href="javascript:void(0);" (click)="showHide($event)" >
Cancel
</a></button>
</div>
</form>
and my department table is:
<table align="center">
<thead>
<tr>
<td>#</td>
<td><strong>Department</strong></td>
<td><strong>Department Location</strong></td>
<td><strong>Edit</strong></td>
<td><strong>Delete</strong></td>
</tr>
</thead>
<tbody>
<tr *ngFor="#department of departments | searchString:filter.value ; #i = index">
<td>{{i + 1}}.</td>
<td> {{department.departmentName}}</td>
<td>{{department.departmentLocation}}</td>
<td>
<button class="btnEdit" (click)="showEdit(department)">Edit</button>
</td>
<td>
<button class="btnDelete" (click)="deleteDepartment(department)" >Delete</button>
</td>
</tr>
</tbody>
</table>
With this code, you don't wait for the response of the addDepartment request and execute the getAll request directly.
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
}
You should move the call to getAll within the callback registered in subscribe. At this moment, the addDepartment is actually done and you can reload the list...
The code could be refactored like this (it's a guess since I haven't the content of addDepartment and getAll methods):
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(addedDepartment => {
this.department = this.getAll();
});
}
This issue occurs because of the way you're using departmant and how change detection works. When you use *ngFor="#department of departments", angular change detection looks for a object reference on departments array. When you update/change one of the items in this array object reference to the array itself doesn't change, so angular doesn't run change detection.
You have few options:
1) change reference of the array by replacing it with new array with updated values
2) tell angular explicitly to run change detection (which I think is easier in your case):
constructor(private _cdRef: ChangeDetectorRef) {...}
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
this._cdRef.markForCheck();
}

Resources